> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kaleidoswap.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a submarine swap

> On-chain → Lightning. You send the invoice to pay and your refund public key; the maker returns the lockup address, the expected amount, the swap tree, and its timeout. **Verify the lockup against your own key before funding it.** The response carries `swapAuth`, issued once: store it with the swap.



## OpenAPI

````yaml /openapi.json post /v2/swap/submarine
openapi: 3.1.0
info:
  title: KaleidoSwap Maker API
  version: v2
  description: >-
    Public HTTP API of the KaleidoSwap maker. Wire-compatible with the Boltz
    `/v2` protocol for submarine, reverse, and chain swaps, with KaleidoSwap
    additions (RGB, atomic swaps, pay-through, LSPS1, swap credentials).
    Integrate through the Swap SDK where possible: it verifies every swap the
    maker proposes.
  contact:
    name: KaleidoSwap
    url: https://kaleidoswap.com
servers:
  - url: https://maker.signet.kaleidoswap.com
    description: Signet (Mutinynet)
security: []
tags:
  - name: Service
    description: Maker identity, version, and capabilities.
  - name: Pairs and quotes
    description: Routes the maker trades, their limits and fees, and quotes.
  - name: Submarine swaps
    description: On-chain → Lightning. You lock on chain; the maker pays your invoice.
  - name: Reverse swaps
    description: >-
      Lightning → on-chain. You pay a hold invoice; the maker locks on chain;
      you claim.
  - name: Chain swaps
    description: On-chain → on-chain. Both sides lock; you claim the maker's lockup.
  - name: Swap status
    description: Swap status over HTTP and WebSocket.
  - name: Recovery
    description: Restore swaps from an xpub and recover swap credentials.
  - name: Atomic RGB swaps
    description: BTC ↔ RGB asset swaps in a single transaction.
  - name: Pay-through
    description: Lightning payment → on-chain payout to any address.
  - name: Lightning channels (LSPS1)
    description: Buy inbound Lightning channels (LSPS1).
  - name: Chain data
    description: The maker's view of chain tips and fees.
paths:
  /v2/swap/submarine:
    post:
      tags:
        - Submarine swaps
      summary: Create a submarine swap
      description: >-
        On-chain → Lightning. You send the invoice to pay and your refund public
        key; the maker returns the lockup address, the expected amount, the swap
        tree, and its timeout. **Verify the lockup against your own key before
        funding it.** The response carries `swapAuth`, issued once: store it
        with the swap.
      operationId: create_submarine_swap
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSubmarineRequest'
        required: true
      responses:
        '201':
          description: Swap created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmarineCreateResponse'
        '400':
          description: Malformed input or webhook URL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: An active swap already exists for this preimageHash.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: >-
            Quoting/inventory/derivation failure, an invoice the maker cannot
            pay under its payout CLTV cap (`invoice_cltv_too_large`), or an
            invoice of this maker that cannot be paid in-process
            (`internal_hop_unsupported`, `internal_hop_refused`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: >-
            Over the caller-rate or rolling notional budget; carries
            Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: signing key, node, or quoting engine unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - {}
        - PartnerAuth: []
        - OrgKey: []
components:
  schemas:
    CreateSubmarineRequest:
      type: object
      description: >-
        Body of `POST /v2/swap/submarine` — Boltz-shaped, camelCase. Accepts
        both the maker's native shape (`pairId` + `preimageHash` +

        `fromAmount`) and the **stock Boltz SDK** shape (`from` + `to` +
        `invoice`,

        with the hash and on-chain amount derived server-side).
      required:
        - refundPublicKey
      properties:
        beneficiary:
          type:
            - string
            - 'null'
          description: >-
            A `kaleidoswap:` beneficiary handoff carrying the invoice to pay, in

            place of `invoice`. This is how a payer funds a swap that pays
            **someone else**: the

            recipient's wallet emits one string and the payer's passes it

            through, rather than the payer knowing to pull an invoice out of it.
            The maker checks the request's network and expiry, and the swap is

            atomic exactly as it always was — the lockup commits to the

            recipient's payment hash, so the maker can only claim it by paying

            them.
        from:
          type:
            - string
            - 'null'
          description: >-
            Boltz: on-chain currency symbol (e.g. `"BTC"`). Combined with `to`
            into

            a `pairId` when `pairId` is absent.
        fromAmount:
          type:
            - integer
            - 'null'
          format: int64
          description: >-
            Amount, in the from-asset's smallest unit, the taker will lock

            on-chain. Optional for a BTC↔BTC submarine: derived from the invoice

            amount + the pair's fees (Boltz `expectedAmount`). For a Liquid

            submarine (L-BTC or L-USDT) the invoice is authoritative and this
            legacy

            field is accepted only when it equals the canonical inverse quote.
          minimum: 0
        invoice:
          type:
            - string
            - 'null'
          description: |-
            The BOLT11 invoice the taker wants paid over Lightning — the
            maker pays it once the taker's lockup/VHTLC confirms, then claims
            the lockup with the preimage the payment reveals. Its payment hash
            must equal `preimage_hash`. Boltz-shaped submarine: the user
            supplies the invoice to be settled.
        invoiceAmount:
          type:
            - integer
            - 'null'
          format: int64
          description: |-
            With `offer`: the Lightning amount, in sats, to request from a
            variable-amount offer. Optional for a fixed-amount offer, and must
            equal its amount when given. Rejected without `offer`.
          minimum: 0
        offer:
          type:
            - string
            - 'null'
          description: >-
            **BOLT12 alternative to `invoice`**: an `lno1…` offer the taker
            wants

            paid. The maker fetches an invoice from it at create time (without

            paying), binds the swap to that invoice's payment hash — returned as

            `preimageHash` — and releases the payment once the lockup confirms.
            Mutually exclusive with `invoice` and with an explicit
            `preimageHash`.
        pairHash:
          type:
            - string
            - 'null'
          description: >-
            Optional `pairHash` rate-lock: the hash the taker quoted against.
            When present it's verified against the pair's current rate card and
            a

            mismatch is rejected with `400 pair_hash_mismatch`.
        pairId:
          type:
            - string
            - 'null'
          description: >-
            Trading-pair key, e.g. `"BTC/BTC"`. Optional when `from`+`to` are
            given.
        preimageHash:
          type:
            - string
            - 'null'
          description: >-
            The taker's BOLT11 payment hash — `SHA256(preimage)`, 32 bytes hex.
            Optional: derived from `invoice` when absent (Boltz behaviour).
        refundPublicKey:
          type: string
          description: The taker's 33-byte compressed refund public key, hex.
        to:
          type:
            - string
            - 'null'
          description: 'Boltz: Lightning currency symbol (e.g. `"BTC"`).'
        webhook:
          oneOf:
            - $ref: '#/components/schemas/WebhookConfig'
              description: >-
                Optional HTTPS callback for status changes (Boltz `webhook`
                shape). Persisted on the swap row; the dispatcher reads it on
                each

                `SwapUpdate`.
            - type: 'null'
    SubmarineCreateResponse:
      type: object
      required:
        - id
        - swapAuth
        - claimPublicKey
        - address
        - swapTree
        - timeoutBlockHeight
        - expectedAmount
        - acceptZeroConf
        - bip21
      properties:
        acceptZeroConf:
          type: boolean
          description: >-
            Whether the maker accepts a 0-conf deposit. Always `false` — the
            swap

            engine has no zero-conf path. Present because stock Boltz

            clients require it (non-Option in their `CreateSubmarineResponse`).
        address:
          type: string
          description: P2TR lockup address (or `ark1…` VHTLC / `el1…` Liquid HTLC).
        assetId:
          type:
            - string
            - 'null'
          description: Swap asset for Liquid routes (L-USDT); omitted on BTC/Arkade routes.
        bip21:
          type: string
          description: >-
            BIP-21 funding URI for the taker's wallet
            (`bitcoin:<addr>?amount=<btc>`). Empty for Arkade/Liquid lockups,
            which are not `bitcoin:` URIs.
        claimPublicKey:
          type: string
          description: 33-byte compressed maker pubkey (hex) used in the MuSig2 aggregate.
        expectedAmount:
          type: integer
          format: int64
          description: Amount the taker must lock on-chain (Boltz `expectedAmount`).
          minimum: 0
        feeAssetId:
          type:
            - string
            - 'null'
          description: Elements fee/policy asset for Liquid routes (L-BTC).
        id:
          type: string
          description: Swap id (26-character string).
        internalHop:
          oneOf:
            - $ref: '#/components/schemas/InternalHopRef'
              description: >-
                **Only when `invoice` is a hold invoice of this maker**: the
                swap that

                minted it, which this one pays in-process instead of over
                Lightning. One hash binds both: the claim of that swap's lockup
                reveals the

                preimage that lets the maker claim this deposit. Only an Arkade

                deposit paying a reverse to an RGB lockup is admitted.
            - type: 'null'
        invoiceAmount:
          type:
            - integer
            - 'null'
          format: int64
          description: >-
            **BOLT12 (`offer`) creates only**: the Lightning amount, in sats,
            the

            fetched invoice is for and the maker will pay.
          minimum: 0
        preimageHash:
          type:
            - string
            - 'null'
          description: >-
            **BOLT12 (`offer`) creates only**: the payment hash of the invoice
            the

            maker fetched from the offer — the hash the lockup commits to, which

            the taker could not know in advance. 32 bytes hex.
        referralId:
          type:
            - string
            - 'null'
          description: |-
            Boltz compatibility field. The maker currently has no referral
            attribution and returns JSON `null`.
        rgb:
          oneOf:
            - $ref: '#/components/schemas/RgbLock'
              description: >-
                **RGB routes only** (`from` on `rgb_l1`): how to lock the RGB
                asset in

                the swap tree's P2TR `address`. `expectedAmount` is then the
                asset

                amount in the contract's units, not sats.
            - type: 'null'
        swapAuth:
          type: string
          description: >-
            Per-swap taker credential, 32 bytes hex. Issued **once**, here.
            Present it as `X-Swap-Auth` on `POST /v2/swap/{id}/rate-decision`;

            without it the maker can't tell the taker from anyone else who

            happens to know the swap id.
        swapTree:
          $ref: '#/components/schemas/SwapTree'
        timeoutBlockHeight:
          type: integer
          format: int32
          description: |-
            Refund-leaf timelock (block height for BTC/Liquid; unix-ts for
            Arkade — see the persisted form for which).
          minimum: 0
    ErrorResponse:
      type: object
      description: Boltz-shaped error envelope.
      required:
        - error
      properties:
        details:
          type:
            - string
            - 'null'
          description: Optional human-readable detail. Present on 4xx; absent on 5xx.
        error:
          type: string
          description: Stable machine-readable error code, e.g. `pair_hash_mismatch`.
    WebhookConfig:
      type: object
      description: |-
        Opt-in HTTPS callbacks for a swap's status changes. ```json
        "webhook": {
          "url": "https://merchant.example/callback",
          "hashSwapId": true,
          "status": ["transaction.confirmed", "invoice.paid"]
        }
        ```
      required:
        - url
      properties:
        hashSwapId:
          type: boolean
          description: >-
            When `true`, the swap id in the callback payload is
            `SHA256(swap_id)`

            — for merchants that don't want correlatable ids on the wire.
        status:
          type:
            - array
            - 'null'
          items:
            type: string
          description: |-
            `None` (the
            field absent) means *every* transition is delivered.
        url:
          type: string
          description: Callback URL.
    InternalHopRef:
      type: object
      description: The swap a submarine pays in-process.
      required:
        - payeeId
      properties:
        payeeId:
          type: string
          description: Id of the paid swap.
    RgbLock:
      type: object
      description: >-
        The RGB lock of a swap whose deposit (submarine) or payout (reverse) is

        an RGB asset in the swap tree's P2TR output. **Submarine:** the taker's
        rgb-lib `send` pays a witness recipient:

        `recipientId` (the HTLC script) with `WitnessData { amount_sat: htlcSat,

        blinding }`, assigning `amount` of `assetId`, and posts the consignment
        to

        `transportEndpoints`. The maker pays the invoice once the lock has

        `minConfirmations` and it holds exactly `amount` on the HTLC output;
        after

        `timeoutBlockHeight` the taker can reclaim through the refund leaf, with
        a

        colored spend (an uncolored one burns the asset). **Reverse:** once the
        hold invoice is paid (held) the maker's rgb-lib send

        pays `htlcSat` to `scriptPubkey` assigning `amount` of `assetId`, and

        posts the consignment to `transportEndpoints` under `recipientId`; the

        lock txid is then on `GET /v2/swap/reverse/{id}/transaction`. The taker

        accepts it with `blinding`, waits for `minConfirmations`, and claims

        through the claim leaf with a colored spend of the HTLC alone (output 0
        an

        OP_RETURN commitment): `htlcSat` pays the claim at `claimFeeRate` and

        leaves a 546-sat colored output, so the taker needs no BTC of their own.
        The claim reveals the preimage, which settles the hold. An uncolored

        spend burns the asset. After `timeoutBlockHeight` the maker refunds.
      required:
        - assetId
        - amount
        - recipientId
        - blinding
        - htlcSat
        - scriptPubkey
        - transportEndpoints
        - minConfirmations
      properties:
        amount:
          type: integer
          format: int64
          description: >-
            Asset amount in the contract's smallest unit; equals
            `expectedAmount`

            (submarine) or `onchainAmount` (reverse).
          minimum: 0
        assetId:
          type: string
          description: RGB contract id (`rgb:…`).
        blinding:
          type: string
          description: |-
            Decimal blinding chosen by the maker. A string preserves all 63 bits
            in JavaScript clients, whose JSON numbers lose precision above 2^53.
        claimFeeRate:
          type:
            - integer
            - 'null'
          format: int64
          description: '**Reverse only**: fee rate, sat/vB, `htlcSat` funds the claim at.'
          minimum: 0
        cooperativeRefund:
          type:
            - string
            - 'null'
        htlcSat:
          type: integer
          format: int64
          description: |-
            Sats of the HTLC output: at least this (submarine); 546 plus the
            claim fee at `claimFeeRate` (reverse).
          minimum: 0
        minConfirmations:
          type: integer
          format: int32
          description: |-
            Confirmations the lock needs before the other side acts on it; the
            timeout leaves room for them and for the claim to confirm.
          minimum: 0
        recipientId:
          type: string
          description: |-
            rgb-lib recipient id of the HTLC script: the proxy key of the lock
            consignment.
        scriptPubkey:
          type: string
          description: |-
            The HTLC output script (hex), the same P2TR as `address` /
            `lockupAddress`.
        transportEndpoints:
          type: array
          items:
            type: string
          description: RGB proxy the lock consignment is posted to.
    SwapTree:
      type: object
      description: '`swapTree` returned on every swap creation + status response.'
      required:
        - claimLeaf
        - refundLeaf
      properties:
        claimLeaf:
          $ref: '#/components/schemas/SwapLeaf'
        refundLeaf:
          $ref: '#/components/schemas/SwapLeaf'
    SwapLeaf:
      type: object
      description: |-
        One tapscript leaf — leaf-version byte (`196` / `0xc4` for elements,
        `192` / `0xc0` for Bitcoin) plus the hex script.
      required:
        - version
        - output
      properties:
        output:
          type: string
          description: Hex-encoded leaf script.
        version:
          type: integer
          format: int32
          description: Tapscript leaf-version byte.
          minimum: 0
  securitySchemes:
    PartnerAuth:
      type: http
      scheme: bearer
      bearerFormat: kld_test_… / kld_live_…
      description: >-
        Secret organization API key from the partner panel, for servers. Sent on
        swap creation as `Authorization: Bearer <key>` to attribute the swap to
        your organization. Optional; an invalid key is rejected. Never use it in
        client-side code.
    OrgKey:
      type: apiKey
      in: header
      name: X-Kaleido-Org-Key
      description: >-
        Public organization key (64 hex characters) for client-side attribution.
        A label, not a credential. Sent on swap creation only. Never combine
        with `PartnerAuth`.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.