> ## 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.

# Receive On-chain from Lightning

> Turn a Lightning payment into on-chain BTC, L-BTC, or L-USDT with a Swap SDK reverse swap, and claim the payout with your own secret

Your user pays over Lightning and wants the funds on chain. This is a **reverse swap**.

## How it works

Your app creates a secret and pays a hold invoice locked to it. The maker then locks the funds on chain to the same secret. Your app claims them, which reveals the secret and lets the maker settle your payment.

Until your app claims, the Lightning payment is held, not settled. If the maker never locks, the payment is released back.

## Setup

The code on this page assumes this setup. It connects to the signet maker and loads your swap mnemonic. See [Installation](https://docs.kaleidoswap.com/sdk/installation.md) and [Keys and recovery](https://docs.kaleidoswap.com/sdk/keys-and-recovery.md) if you have neither yet.

```typescript TypeScript theme={null}
import { init, SwapClient, SwapMasterKey, SwapScript, toJson } from "@kaleidorg/swap-sdk";

await init();

const network = "signet";
const makerUrl = "https://maker.signet.kaleidoswap.com/v2";
const bitcoinEsploraUrl = "https://esplora.signet.kaleidoswap.com";
const liquidEsploraUrl = "https://blockstream.info/liquidtestnet/api";

const client = new SwapClient(makerUrl);
const master = SwapMasterKey.fromSwapMnemonic(process.env.SWAP_MNEMONIC!, network);

// Two things your app provides:
//   nextSwapIndex(): Promise<bigint>  a persisted counter, never reused
//   store                             durable storage for swap records
```

```python Python theme={null}
import asyncio, os
import kaleidorg_swap_sdk as sdk

network = sdk.Network.SIGNET
client = sdk.SwapClient("https://maker.signet.kaleidoswap.com/v2", None)
master = sdk.SwapMasterKey.from_swap_mnemonic(os.environ["SWAP_MNEMONIC"], network)
```

## Receive funds

**1. Create the swap**

```typescript theme={null}
const index = await nextSwapIndex();
const claimKey = master.deriveSwapKey(index);
const preimage = master.derivePreimage(index);

const card = (await client.reversePairs())?.BTC?.["L-BTC"]; // Lightning -> L-BTC
if (!card) throw new Error("Route not offered right now");

const swap = await client.createReverseSwap(network, {
  from: "BTC",
  to: "L-BTC",
  invoiceAmount: 50_000n,
  preimageHash: preimage.sha256,
  claimPublicKey: claimKey.publicKey,
  pairHash: card.hash,
});

await store.put(swap.id, toJson({ index, makerUrl, swap }));
```

The SDK checks that the invoice is locked to your secret and that the lockup is claimable with your key.

**2. Pay the invoice**

Pay `swap.invoice` from any Lightning wallet. Check your payout address first: the claim is the first step that would reject a wrong-network address, and by then the invoice is paid.

**3. Wait for the maker's lockup**

The swap reaches `transaction.mempool`, then `transaction.confirmed`.

**4. Claim**

```typescript theme={null}
const script = SwapScript.fromReverse("liquid", network, swap, claimKey.publicKey);

const claim = await script.constructClaim(preimage.preimage, {
  outputAddress: myLiquidAddress,
  swapId: swap.id,
  keysSecretHex: claimKey.secretKey,
  makerBaseUrl: makerUrl,
  network,
  liquidEsploraUrl,
});
// Save claim.hex() first, then:
await claim.broadcast(network, undefined, liquidEsploraUrl);
```

The swap ends in `invoice.settled`.

> **Python**
>
> ```python theme={null}
> claim_key = master.derive_swap_key(index)
> preimage = master.derive_preimage(index)
> btc = sdk.btc_chain_from_network(network)
> lbtc = sdk.lbtc_chain_from_network(network)
> card = (await client.get_reverse_pairs()).pairs["BTC"]["L-BTC"]
>
> swap = await client.create_reverse_swap(
>     sdk.CreateReverseRequest(
>         invoice_amount=50_000, _from=btc, to=lbtc,
>         preimage_hash=preimage.sha256(), claim_public_key=claim_key.public(),
>         pair_hash=card.hash,
>     )
> )
> script = sdk.SwapScript.from_reverse(chain=lbtc, reverse_response=swap, our_pubkey=claim_key.public())
> ```

## If something goes wrong

* **The maker never locks**, or its lockup fails (`transaction.failed`, `transaction.refunded`): your Lightning payment is released automatically. Nothing to do.
* **Your app was offline:** claim as soon as it comes back. A claim must confirm before the swap's `timeoutBlockHeight`. `claimReverseSwap` checks the remaining margin and your chain evidence before revealing the secret; see [Claims and refunds](https://docs.kaleidoswap.com/sdk/claims-and-refunds.md).
* **The broadcast response was lost:** rebroadcast the saved transaction. Never sign a second claim.

## Receiving other assets

| Asset you receive | What changes |
| - | - |
| BTC | `to: "BTC"`, `SwapScript.fromReverse("bitcoin", ...)`, a Bitcoin Esplora URL |
| L-USDT | `to: "L-USDT"`. The claim uses a caller-funded PSET: your wallet adds L-BTC for the fee (`prepareLiquidClaim`) |
| USDT-RGB | Pin the RGB contract, and your rgb-lib wallet colors the claim. See [Swap BTC and USDT on RGB](https://docs.kaleidoswap.com/sdk/rgb-swaps.md) |


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