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.Pay
The maker must have pay-through enabled. The client needs no WebAssembly initialization:TypeScript
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
createagain 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.
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.
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.