0Bit Documentation

Configure return URLs and outcome pages

Build success, failure, cancelled, expired, and processing pages for hosted 0Gate flows without trusting browser-only state.

Return URLs and outcome pages are the bridge between the hosted 0Gate experience and your product. They should make users feel oriented, but they should read final state from your backend.

Do not trust URL state

A user can visit, refresh, replay, or share a return URL. Use it as a routing signal only. The page should fetch your own attempt status, which is backed by signed webhooks and reconciliation.

Outcome flow

URL design

URLUse
/checkout/{attemptId}/returnUser arrived from a successful or processing hosted path.
/checkout/{attemptId}/cancelUser left or cancelled the hosted path.
/checkout/{attemptId}/statusReusable status page for email, support, and refreshes.

Keep the attempt id opaque. Do not place secret keys, browser session secrets, raw provider values, or terminal truth in query parameters.

Status endpoint

export async function getCheckoutStatus(attemptId: string, accountId: string) {
  const attempt = await checkoutAttempts.getForAccount(attemptId, accountId);

  if (!attempt) return { view: 'not_found' };
  if (attempt.status === 'fulfilled') return { view: 'success' };
  if (attempt.status === 'failed') return { view: 'failed', canRetry: true };
  if (attempt.status === 'expired') return { view: 'expired', canRetry: true };
  if (attempt.status === 'cancelled') return { view: 'cancelled', canRetry: true };

  return { view: 'processing', nextPollMs: 3000 };
}

Page states

Backend statePage viewCustomer copy
processingProcessing“We are confirming your checkout. You can leave this page and return later.”
fulfilledSuccess“Your checkout is complete.”
failedFailed“This checkout could not be completed. You can try again or contact support.”
expiredExpired“This session expired. Start again to get a fresh checkout.”
cancelledCancelled“This checkout was cancelled. You can start a new attempt.”

Client page pattern

export function CheckoutOutcome({ attemptId }: { attemptId: string }) {
  const status = useCheckoutStatus(attemptId);

  if (status.view === 'processing') return <ProcessingReceipt nextPollMs={status.nextPollMs} />;
  if (status.view === 'success') return <SuccessReceipt />;
  if (status.view === 'failed') return <FailureReceipt canRetry={status.canRetry} />;
  if (status.view === 'expired') return <ExpiredReceipt />;
  if (status.view === 'cancelled') return <CancelledReceipt />;

  return <SupportFallback attemptId={attemptId} />;
}

Outcome page guardrails

DoAvoid
Show your attempt id, normalized state, created time, and next action.Showing raw webhook payloads, signatures, or browser session secrets.
Poll your own status endpoint while processing.Polling client-side callbacks or trusting URL query values.
Offer a fresh retry for failed/expired/cancelled attempts.Reusing expired or cancelled browser session values.
Provide support links with a safe reference id.Exposing provider, treasury, compliance-rule, or risk-threshold details.

On this page