Developer Docs

Hosted Checkout

Redirect customers to BSync hosted checkout pages.

BSync provides a fully hosted checkout page. After creating a Payment Intent, redirect the customer to checkoutUrl — BSync handles provider selection, payment instructions, and status tracking.

OpenAPI: Hosted Checkout paths under /checkout/{token}/docs/api-reference

Checkout URL

When you create a Payment Intent, the response includes:

{
  "checkoutUrl": "https://bsyncapp.com/checkout/token_xyz"
}

Redirect the customer:

res.redirect(payment.checkoutUrl);

The checkout page is hosted by BSync. You do not need to build payment UI, provider selection, or SMS matching logic.

Redirect Flow

sequenceDiagram
    participant Merchant
    participant Customer
    participant BSyncCheckout as BSync_Checkout
    participant BSyncAPI as BSync_API
 
    Merchant->>BSyncAPI: POST /v1/payment-intents
    BSyncAPI-->>Merchant: checkoutUrl
    Merchant->>Customer: Redirect to checkoutUrl
    Customer->>BSyncCheckout: Load checkout page
    BSyncCheckout->>Customer: Select provider + enter phone
    Customer->>BSyncCheckout: Complete payment
    BSyncCheckout->>Merchant: Redirect to successUrl
    BSyncAPI->>Merchant: PAYMENT_PAID webhook

Customer Experience

  1. Customer lands on the hosted checkout page.
  2. Available payment providers are displayed (e.g. Vodafone Cash).
  3. Customer selects a provider.
  4. Customer enters their sender phone number.
  5. Payment instructions are shown (amount, receiver, QR/deep link).
  6. Customer completes payment via their mobile wallet.
  7. BSync matches the SMS transaction automatically.
  8. On success, customer is redirected to successUrl after redirectDelay seconds.

Checkout Endpoints

These endpoints power the hosted page. You typically do not call them directly — they are documented in OpenAPI for reference and custom integrations.

MethodPathDescription
GET/checkout/{token}Load checkout session
GET/checkout/{token}/statusPoll checkout status
GET/checkout/{token}/instructionsPayment instructions
POST/checkout/{token}/providerSelect payment provider
POST/checkout/{token}/senderSubmit sender phone
GET/checkout/{token}/eventsSSE real-time events

No API key required for checkout endpoints — the session token authenticates the request.

Real-Time Events (SSE)

Subscribe to GET /checkout/{token}/events for live payment updates:

event: checkout_connected
data: {"paymentId":"pay_abc123","checkoutStatus":"waiting_payment",...}

event: payment_confirmed
data: {"paymentId":"pay_abc123","checkoutStatus":"paid","paymentStatus":"paid",...}
SSE EventTrigger
checkout_connectedInitial connection
payment_waitingPayment created
payment_detectedSMS matched
payment_confirmedPayment paid (terminal)
payment_review_requiredManual review needed
payment_failedReview rejected (terminal)
payment_expiredSession expired (terminal)
payment_cancelledCancelled (terminal)
heartbeatKeep-alive
server_shutdownServer restart — reconnect after retryAfter seconds

Terminal events: payment_confirmed, payment_expired, payment_cancelled, payment_failed.

SSE is useful for custom checkout pages. For most integrations, webhooks are the recommended approach.

Expiry

Checkout sessions expire at the Payment Intent's expiresAt timestamp (default: 30 minutes). Expired sessions return HTTP 410:

{
  "success": false,
  "error": {
    "code": "CHECKOUT_EXPIRED",
    "type": "conflict_error",
    "message": "Checkout session has expired.",
    "requestId": "req_abc123",
    "details": {}
  }
}

Success

When payment is confirmed:

  1. Checkout page shows success state.
  2. Customer is redirected to successUrl after redirectDelay seconds.
  3. PAYMENT_PAID webhook is delivered to your server.
  4. Payment Intent status becomes paid.

Always verify payment server-side — do not rely on the redirect alone.

Cancellation

Customer can cancel from the checkout page. If cancelUrl is set, they are redirected there. A PAYMENT_CANCELLED webhook is delivered.

You can also cancel server-side via POST /v1/payment-intents/{paymentId}/cancel.

Review Required

Some payments require manual review (e.g. amount mismatch, duplicate detection). When this happens:

  • SSE event: payment_review_required
  • Webhook: PAYMENT_REVIEW_REQUIRED
  • matchStatus becomes review_required
  • verificationStatus becomes manual_review

Your integration should handle this state gracefully — inform the customer that payment is being verified.

Subsequent webhooks: PAYMENT_REVIEW_APPROVED or PAYMENT_REVIEW_REJECTED.

Failure

Payment can fail when manual review is rejected:

  • SSE event: payment_failed (terminal)
  • Payment Intent status becomes failed
  • verificationStatus becomes failed

Production Tips

  • Set both successUrl and cancelUrl for a complete customer experience.
  • Use webhooks as the primary notification mechanism, not SSE or polling.
  • Handle review_required state in your order management system.
  • Never fulfill orders based on the redirect alone — always confirm via webhook + getStatus().

Was this page helpful?

hosted-checkout

Command Palette

Search for a command to run...