Status lifecycle
A swap moves through a sequence of statuses from creation to terminal state. Poll GET /v1/swaps/:id until terminal.
Happy path
waiting → confirming → exchanging → sending → finished
All statuses
| Status | Terminal | Meaning | Suggested partner UX |
|---|---|---|---|
waiting | no | Awaiting incoming payment to payinAddress | Show "Send <amountFrom> <from> to <payinAddress>" with a copy button |
confirming | no | Detected on chain — waiting for confirmations | "Detected on chain — waiting for N confirmations" |
exchanging | no | Confirmed; the swap is executing | "Exchanging…" with a spinner |
sending | no | Funds en route to payoutAddress | "Sending to your wallet…" |
finished | yes | Swap complete; user has been credited | Success state with a link to the payout tx (when available) |
failed | yes | Failed — most often the deposit was below minimum | "Swap failed — <message>". Offer support contact |
refunded | yes | Funds returned to refundAddress (or to the original sending address when refundAddress was omitted and the chain supports it) | "Refunded — see <refundHash>" |
overdue | yes | Float-rate window expired before payin landed | "Window closed. Start a new swap." |
expired | yes | Fixed-rate window expired before payin landed | "Window closed. Start a new swap." |
hold | conditional | AML/KYC review — funds held until verified | Direct user to email security@ghostswap.io. Do not promise a resolution time |
When to stop polling
Stop polling when status is in the terminal set:
const TERMINAL = new Set(['finished', 'failed', 'refunded', 'overdue', 'expired']);
if (TERMINAL.has(swap.status)) {
// Update your DB, credit the user, etc.
return;
}hold is a soft-block — keep polling at a slower cadence (every few minutes) since it can resolve to finished or refunded after manual review.
How fresh is the status?
A background worker on our side polls upstream every ~30 seconds for any swap not in a terminal state. So your worst-case lag from "user's deposit was confirmed on chain" → "your dashboard shows confirming" is ~30 seconds + your poll cadence.
For end-to-end "real-time" feel, poll us every 10 seconds while the partner-facing UI is open. We absorb the upstream cost.
Common transitions
waiting→overdue: user never sent the funds within the float window. Status flips after ~36 hours of inactivity. Refund flow doesn't apply (no funds were received).waiting→confirming→failed: the user sent an amount under the pair's minimum. Funds are received but cannot be exchanged. Goes torefundedshortly after — funds return torefundAddressif one was provided, otherwise to the original sending address where the chain supports it (a small number of chains requirerefundAddressfor automatic refund and will queue the refund for support otherwise).confirming→hold: the deposit triggered an AML flag. Funds are held; the user must complete KYC verification — direct them to security@ghostswap.io.hold→finished: KYC cleared, swap completed.hold→refunded: KYC failed or the user requested a refund.
See also
- Errors — what to show when a status transition fails to fetch.
- End-to-end swap guide — full polling reference implementation.