0Bit Documentation

Build a 0Gate swap flow

Build a hosted 0Gate swap flow without implying a public headless swap API or exposing liquidity internals.

Use 0Gate for public swap journeys when the customer can complete the hosted 0Bit experience. The source repos show swap as a hosted iframe/kit-block flow; partner-level headless swap quote and execute APIs are not the public default.

Keep public swaps inside hosted 0Gate

Public swap flows should stay inside 0Gate unless your account is explicitly approved for another product surface. Use this guide for session locking, browser handoff, signed events, and reconciliation; use the API reference for approved request and response fields.

Flow boundary

BoundaryOwned byWhat it means
Swap intentYour appYou know why the customer wants a swap and what account/action it belongs to.
Hosted swap flow0GateThe iframe handles customer-facing swap UX and any product-approved quote confirmation.
Browser callbackBrowserUX only; show processing or return status.
Backend terminal eventYour backendThe only path that can close your internal swap intent.

Implementation shape

  1. Create a swap intent before opening 0Gate.
  2. Lock the server-created session to swap.
  3. Mount the swap kit block or the hosted widget with a session-bound flow.
  4. Store the 0Gate session id, your swap intent id, and every webhook event id.
  5. Reconcile from trusted server state if the callback fires before webhook delivery.
async function startSwap(input: SwapIntent) {
  const intent = await swapIntents.create({
    accountId: input.accountId,
    fromAsset: input.fromAsset,
    toAsset: input.toAsset,
    amountIntent: input.amountIntent,
    status: 'pending_session',
  });

  const session = await gateSessions.createForAttempt({
    attemptId: intent.id,
    flow: 'swap',
    userReference: intent.id,
    idempotencyKey: `swap:${intent.id}`,
  });

  await swapIntents.attachGateSession(intent.id, session.id);
  return { intentId: intent.id, clientSecret: session.clientSecret };
}

Swap state model

StateWhat changedYour action
pending_sessionIntent exists only in your app.Allow safe retry of session creation.
requires_actionHosted swap session is attached.Open the hosted swap flow.
processingBrowser says the hosted flow completed.Show processing and wait for backend truth.
fulfilledVerified backend state confirms completion.Close the swap intent exactly once.
failedHosted swap cannot complete.Keep the customer-safe failure reason and allow a new attempt.
expiredSession lifetime ended.Create a new intent/session if the customer retries.
cancelledCustomer or backend cancelled.Preserve audit state and do not reuse the session.

Quote expectations

Swap pricing is sensitive because it touches liquidity and execution correctness. Keep this public guide to user-flow behavior; exact quote surfaces, fields, and execution semantics belong in approved API reference pages.

ScenarioShow before checkoutConfirm after checkout
Indicative preview availableEstimated output, fees, and a clear “may change” label.The final trusted state from backend events.
No preview availableAsset pair, entered amount, and hosted-flow handoff.The final trusted state from backend events.
Quote changed or expiredAsk the customer to restart from a fresh hosted flow.Do not reuse stale displayed pricing.

Webhook handling

async function applySwapEvent(event: GateSessionEvent) {
  const intent = await swapIntents.findByGateSession(event.data.id);
  if (!intent) return;

  const firstSeen = await webhookEvents.insertOnce(event.id);
  if (!firstSeen) return;

  if (event.type === 'gate_session.completed') {
    await swapIntents.fulfillOnce(intent.id, { sourceEventId: event.id });
  }

  if (['gate_session.failed', 'gate_session.expired', 'gate_session.cancelled'].includes(event.type)) {
    await swapIntents.closeWithoutFulfillment(intent.id, event.type);
  }
}

Production checklist

  • Keep public swap UX on hosted 0Gate unless a different product entitlement is approved.
  • Keep provider, treasury, and routing internals out of public-facing swap UX.
  • Treat preview pricing as indicative unless the API reference says it is locked.
  • Make browser success a processing state only.
  • Fulfill from signed backend state and dedupe duplicate events.

On this page