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

# Pay an Address from Lightning

> Let a payer settle a Lightning invoice while the recipient receives an on-chain payout, using the Swap SDK PayThroughClient with idempotent creation and safe recovery

Your user wants to pay someone's on-chain address but only has Lightning. **Pay-through** turns a Lightning payment into an on-chain payout to any address.

## How it works

The payer pays a hold invoice. The maker broadcasts the payout to the destination address. Then the hold settles. If the maker never pays out, the hold is released.

> [!WARNING]
>
> The payout leg has **no hash lock**: the maker controls it. The payer's Lightning payment stays held until the payout is broadcast, but the payout itself is not enforced on chain. Use the [HTLC swaps](https://docs.kaleidoswap.com/sdk/swap-types.md) where that matters.

## Pay

The maker must have pay-through enabled. The client needs no WebAssembly initialization:

```typescript TypeScript theme={null}
import { PayThroughClient } from "@kaleidorg/swap-sdk/pay-through";

const pay = new PayThroughClient({ makerUrl: "https://maker.signet.kaleidoswap.com/v2" });

if (!(await pay.supportsIdempotency())) {
  throw new Error("This maker does not support safe retries of pay-through creation");
}

const request = { destination: recipientAddress, invoiceAmount: 100_000 };
const idempotencyKey = crypto.randomUUID();
// Persist request, key, and maker URL BEFORE sending.

const order = await pay.create(request, { idempotencyKey });
// Persist order (including swapAuth) privately.
if (order.expiresAt <= Math.floor(Date.now() / 1000)) throw new Error("Invoice expired");

// Show order.invoice, order.payoutAsset, and order.payoutAmount for approval.
// After the payer's wallet pays order.invoice:
const status = await pay.status(order.id);
```

`transaction.mempool` reports the payout broadcast; `invoice.settled` reports that the hold settled.

## What `create` checks

It refuses an order that differs from the request: another destination, another `invoiceAmount`, less than the requested `payoutAmount`, or another asset. It decodes the invoice and refuses one whose amount or payment hash differs from the order. Amounts are safe JavaScript integers; a larger value is rejected, not rounded.

## Idempotent creation and recovery

`create(request, { idempotencyKey })` sends the key as an `Idempotency-Key` header. Use a random UUIDv4 generated with a CSPRNG, persist it before sending, and treat it as a secret: replaying it can recover the order's `swapAuth`.

* Call `supportsIdempotency()` **before the first create**, against the same maker. Older makers can silently ignore the key, so a successful create does not prove support.
* To recover a lost response, call `create` again with the **same** request, key, maker URL, and credentials.
* On `PAY_THROUGH_IDEMPOTENCY_IN_FLIGHT`, retry the identical request and key with bounded backoff (a few attempts over one to two minutes).
* Never change the key while a timeout, `5xx`, or in-flight outcome is unresolved, and never pay a second invoice to recover the first.

Other error codes exported by the subpath: `PAY_THROUGH_IDEMPOTENCY_MISMATCH` (the request differs from the original), `PAY_THROUGH_IDEMPOTENCY_SCOPE_MISMATCH` (different credentials), and `PAY_THROUGH_IDEMPOTENCY_EXPIRED` (the original order expired or is no longer awaiting payment: reconcile it before creating a new one).

Requests time out after `timeoutMs` (30 seconds by default) and accept an optional `signal`. `PayThroughClient` also takes an `orgKey` for [partner attribution](https://docs.kaleidoswap.com/sdk/partner-attribution.md).

## If something goes wrong

* **The invoice expired unpaid:** start a new payment intent with a new request and a new key.
* **The payer paid but no payout appears:** check `pay.status(order.id)`. The hold settles only after the payout is broadcast; until then the payment can still be released.


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