> ## 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 chain swap

> On-chain → on-chain. Send your preimage hash, a claim public key, a refund public key, and one amount side (`userLockAmount` or `serverLockAmount`). The maker returns `lockupDetails` (where you lock) and `claimDetails` (where it locks for you). **Verify both against your keys before funding.** The response carries `swapAuth`, issued once.



## OpenAPI

````yaml /openapi.json post /v2/swap/chain
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/chain:
    post:
      tags:
        - Chain swaps
      summary: Create a chain swap
      description: >-
        On-chain → on-chain. Send your preimage hash, a claim public key, a
        refund public key, and one amount side (`userLockAmount` or
        `serverLockAmount`). The maker returns `lockupDetails` (where you lock)
        and `claimDetails` (where it locks for you). **Verify both against your
        keys before funding.** The response carries `swapAuth`, issued once.
      operationId: create_chain_swap
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateChainRequest'
        required: true
      responses:
        '201':
          description: Chain swap created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChainCreateResponse'
        '400':
          description: Malformed input or webhook URL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Active swap exists for this preimageHash.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Quote/derivation failure or unsafe timeout ordering.
          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, chain provider, or quoting engine unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - {}
        - PartnerAuth: []
        - OrgKey: []
components:
  schemas:
    CreateChainRequest:
      type: object
      description: >-
        Body of `POST /v2/swap/chain` — Boltz-shaped, camelCase. Atomic routes
        return one HTLC description per side and do not require a

        destination address at creation. The legacy plain-send route remains

        address-driven for backward compatibility.
      required:
        - preimageHash
        - refundPublicKey
      properties:
        claimPublicKey:
          type:
            - string
            - 'null'
          description: >-
            Taker's 33-byte compressed **claim** pubkey for the Liquid side.
            Required for an *atomic* pair (the taker is the claim party on the

            maker's L-USDT HTLC); ignored for the plain-send pair.
        from:
          type:
            - string
            - 'null'
          description: 'Boltz: source on-chain currency symbol (e.g. `"BTC"`).'
        fromAmount:
          type:
            - integer
            - 'null'
          format: int64
          description: Legacy alias for `userLockAmount`.
          minimum: 0
        pairHash:
          type:
            - string
            - 'null'
          description: >-
            Optional `pairHash` rate-lock: the hash the taker quoted against.
            Verified against the pair's current rate card when present;

            a mismatch is rejected with `400 pair_hash_mismatch`.
        pairId:
          type:
            - string
            - 'null'
          description: |-
            Trading-pair key. Must resolve to a Chain pair in the engine —
            Optional when `from`+`to` are given (stock Boltz SDK shape).
        preimageHash:
          type: string
          description: |-
            The taker's BOLT11-style payment hash — `SHA256(preimage)`,
            32 bytes hex. Goes into the BTC lockup's claim leaf; the maker
            reveals the preimage at claim time.
        refundPublicKey:
          type: string
          description: |-
            Taker's 33-byte compressed refund pubkey (BTC side). The maker
            is the claim party on the BTC P2TR — taker refunds via script-
            path if the maker fails to claim.
        serverLockAmount:
          type:
            - integer
            - 'null'
          format: int64
          description: |-
            Desired output-side amount; the maker inverse-quotes the canonical
            input. Exactly one amount side is accepted.
          minimum: 0
        to:
          type:
            - string
            - 'null'
          description: 'Boltz: destination on-chain currency symbol (e.g. `"L-USDT"`).'
        userAddress:
          type:
            - string
            - 'null'
          description: >-
            Legacy plain-send destination. Atomic swaps construct the payout
            from

            `claimDetails` after creation and therefore do not require it.
        userLockAmount:
          type:
            - integer
            - 'null'
          format: int64
          description: |-
            Input-side amount. Exactly one of this and `serverLockAmount` is
            required.
          minimum: 0
        webhook:
          oneOf:
            - $ref: '#/components/schemas/WebhookConfig'
              description: Optional HTTPS callback for status changes.
            - type: 'null'
    ChainCreateResponse:
      type: object
      description: >-
        `POST /v2/swap/chain` response. Atomic Liquid pairs use Boltz's standard

        `lockupDetails` + `claimDetails` shape. The optional flat fields
        preserve

        the existing plain-send and Arkade extension responses.
      required:
        - id
        - swapAuth
      properties:
        address:
          type:
            - string
            - 'null'
        claimDetails:
          oneOf:
            - $ref: '#/components/schemas/ChainSwapDetailsResponse'
            - type: 'null'
        claimPublicKey:
          type:
            - string
            - 'null'
        expectedAmount:
          type:
            - integer
            - 'null'
          format: int64
          minimum: 0
        id:
          type: string
        lockupDetails:
          oneOf:
            - $ref: '#/components/schemas/ChainSwapDetailsResponse'
            - type: 'null'
        payoutAmount:
          type:
            - integer
            - 'null'
          format: int64
          description: L-USDT amount the maker delivers once the BTC deposit confirms.
          minimum: 0
        serverLockup:
          oneOf:
            - $ref: '#/components/schemas/ChainServerLockup'
              description: >-
                Present only for atomic chain pairs — the maker's L-USDT (or
                VHTLC)

                lockup the taker claims revealing the preimage.
            - type: 'null'
        swapAuth:
          type: string
          description: |-
            Per-swap taker credential, 32 bytes hex — see
            `swapAuth`. Chain swaps also need it on
            `POST /v2/swap/chain/{id}/quote`.
        swapTree:
          oneOf:
            - $ref: '#/components/schemas/SwapTree'
            - type: 'null'
        timeoutBlockHeight:
          type:
            - integer
            - 'null'
          format: int32
          minimum: 0
        userAddress:
          type:
            - string
            - 'null'
    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.
    ChainSwapDetailsResponse:
      type: object
      description: One side of the standard atomic Chain create response.
      required:
        - swapTree
        - lockupAddress
        - serverPublicKey
        - timeoutBlockHeight
        - amount
      properties:
        amount:
          type: integer
          format: int64
          minimum: 0
        assetId:
          type:
            - string
            - 'null'
        blindingKey:
          type:
            - string
            - 'null'
          description: >-
            `null` for Liquid; absent for Bitcoin, which has no such field. The
            maker mints its Liquid HTLC lockups **unconfidential** on

            purpose, so no output blinding key exists to return: treat

            `lockupAddress` as explicit — fund it with an unblinded output

            where the taker funds, and build claims against an explicit

            prevout where the taker claims.
        feeAssetId:
          type:
            - string
            - 'null'
        lockupAddress:
          type: string
        serverPublicKey:
          type: string
        swapTree:
          $ref: '#/components/schemas/SwapTree'
        timeoutBlockHeight:
          type: integer
          format: int32
          minimum: 0
    ChainServerLockup:
      type: object
      required:
        - address
        - timeoutBlockHeight
        - refundPublicKey
        - amount
      properties:
        address:
          type: string
        amount:
          type: integer
          format: int64
          minimum: 0
        refundPublicKey:
          type: string
        swapTree:
          oneOf:
            - $ref: '#/components/schemas/SwapTree'
              description: >-
                Present on the Liquid HTLC server lockup; omitted for an Arkade

                VHTLC (which is reparameterised by the taker, not
                script-shaped).
            - type: 'null'
        timeoutBlockHeight:
          type: integer
          format: int32
          minimum: 0
    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.