Skip to main content

Overview

The ZBD Widget is an embeddable iframe that handles the full cashout flow for your users — identity verification (KYC), bank account linking (Plaid), and ACH payouts. Your backend handles user creation, session minting, and balance funding; the widget handles everything else.

Integration Flow

1. Create User        POST /api/v1/cashout/users              (your server → ZBD API)
2. Fund User          POST /v1/cashout/funding-transfers       (your server → ZBD API)
3. Create Session     POST /api/v1/cashout-widget              (your server → ZBD API)
4. Embed Widget       <iframe src="{widget_url}" />            (your frontend)
5. Listen for Events  window.addEventListener("message", ...)  (your frontend)

Authentication

Widget endpoints use two auth patterns:
ContextAuthHeader
Your server → ZBDPublisher API keyapikey: YOUR_API_KEY
Widget iframe → ZBDSession JWT (automatic)Authorization: Bearer {session_token}
Never expose your publisher API key in the browser. Steps 1–3 must happen on your server.

Embedding the Widget

After creating a session, embed the widget URL as an iframe:
<iframe
  src="https://ramp.zbdpay.com?session_token=eyJhbGci..."
  style="width: 100%; height: 600px; border: none;"
  allow="camera; microphone"
></iframe>

Widget Events

The widget communicates with your page via postMessage. Listen for events on the parent window:
window.addEventListener("message", (event) => {
  const { type, payload } = event.data ?? {};
  if (!type?.startsWith("ZBD_")) return;

  switch (type) {
    case "ZBD_WIDGET_READY":
      console.log("Widget loaded", payload?.user);
      break;
    case "ZBD_CASHOUT_SUCCESS":
      console.log("Cashout submitted", payload);
      // Close the widget iframe, refresh balances
      break;
    case "ZBD_WIDGET_CLOSE":
      // User closed the widget — remove the iframe
      break;
  }
});
EventPayloadDescription
ZBD_WIDGET_READY{ user? }Widget loaded and authenticated
ZBD_WIDGET_CLOSEUser closed the widget
ZBD_CASHOUT_SUCCESS{ cashout_id, amount, currency_code, usd_equivalent }Cashout submitted successfully
ZBD_KYC_COMPLETE{ tier }Identity verification approved
ZBD_METHOD_ADDED{ payout_method_id, type, label }Bank account linked via Plaid
ZBD_AUTH_TOKEN_READY{ auth_token, user? }OTP verified, auth JWT available
ZBD_WIDGET_ERROR{ code, message }An error occurred

Embed Parameters

Pass these as URL query parameters on the widget URL:
ParameterRequiredDescription
session_tokenYesJWT from Create Session
flowNocashout (default), kyc, add-method
themeNozbd-default, zbd-light
embedNotrue for chrome-less mode (no header/footer)
componentNobalance, history, method-picker for standalone components

Webhooks

After a cashout is initiated, ZBD sends lifecycle webhooks to the webhook_url you provided when creating the session. The webhook_url must be HTTPS.

Initiated

Sent immediately after the cashout is submitted and the user’s balance is debited. Includes fee_amount.
{
  "event": "ZBD_WIDGET.V1.CASHOUT.INITIATED",
  "timestamp": "2026-05-28T22:21:03.067Z",
  "data": {
    "payout_id": "f4ba94c1-...",
    "user_account_id": "4ac4fd8a-...",
    "amount": "10.00",
    "currency": "USD",
    "payment_method": "ach",
    "status": "initiated",
    "reference_id": "player-42",
    "fee_amount": "0.50"
  }
}

Completed

Sent when the ACH transfer settles at the bank (typically 1–3 business days).
{
  "event": "ZBD_WIDGET.V1.CASHOUT.COMPLETED",
  "timestamp": "2026-05-30T14:12:00.000Z",
  "data": {
    "payout_id": "f4ba94c1-...",
    "user_account_id": "4ac4fd8a-...",
    "amount": "10.00",
    "currency": "USD",
    "payment_method": "ach",
    "status": "completed",
    "reference_id": "player-42"
  }
}

Failed

Sent when the ACH transfer is rejected by the bank or payment processor. Includes error_reason.
{
  "event": "ZBD_WIDGET.V1.CASHOUT.FAILED",
  "timestamp": "2026-05-30T14:12:00.000Z",
  "data": {
    "payout_id": "f4ba94c1-...",
    "user_account_id": "4ac4fd8a-...",
    "amount": "10.00",
    "currency": "USD",
    "payment_method": "ach",
    "status": "failed",
    "reference_id": "player-42",
    "error_reason": "Insufficient funds at receiving bank"
  }
}

Payload Fields

FieldTypeDescription
payout_idUUIDUnique cashout identifier
user_account_idUUIDZBD user ID
amountstringDecimal in major units (e.g. "9.50" = $9.50)
currencystringAlways USD
payment_methodstringAlways ach
statusstringinitiated, completed, or failed
reference_idstringYour reference_id from Create User (null if not linked)
fee_amountstringFee deducted (only on initiated)
error_reasonstringFailure reason (only on failed)
ACH returns (post-settlement reversals) do not trigger a webhook. They are handled internally by ZBD.