Documentation

Realtime events

Every webhook event Videpay sends to your server is also broadcast over Realtime. Use webhooks for reliable server-side fulfillment; use Realtime when you need instant UI updates, live checkout status, admin dashboards, or ops monitors, without polling. Webhooks are the source of truth. Realtime is the hype notification.

Need machine-readable request/response bodies for your AI or codebase? Download this page as plain Markdown.

When should I use this?

  • Your checkout page needs instant paid/failed feedback (no polling loop).
  • Your internal dashboard should live-update when payments or transfers complete.
  • You want sub-second latency for ops tooling alongside webhooks for durability.

Why use Videpay?

  • Identical event names and payload shapes as webhooks, one handler logic, two transports.
  • Connect from your backend with x-api-key or from a checkout page with a short-lived token.
  • No extra setup beyond what you already use for API authentication.

Checkout page + webhook together

Your hosted checkout connects via Realtime so the customer sees Confirmed! within seconds. Your backend still receives payment.settled via webhook to fulfill the order: if the customer closes the tab before the UI updates, the webhook guarantees you never miss the payment. UI can ghost you. Webhooks cannot.

Before you start

  • API key (backend) or checkout realtime token (public checkout page)
  • socket.io-client in your frontend or backend process

Webhooks vs Realtime: use both

Webhooks are the source of truth for fulfillment: Videpay retries failed deliveries, records attempts, and signs payloads. Realtime is ephemeral and best for UX. Production integrations should always handle webhooks; add Realtime where instant feedback matters. Both together is the move. Realtime alone is a brave choice.

  1. Webhooks → your server → fulfill orders, update ledger, send receipts (required).
  2. Realtime → browser or live dashboard → update UI immediately (optional but recommended for checkout).
  3. Same events: payment.settled, deposit.created, deposit.updated, transfer.updated, checkout.created, subscription.charged, and all others listed on the Webhooks page.
  4. Same envelope: { event, emittedAt, businessId, data }: mirror your webhook parser.

Connect from your backend (API key)

Connect to https://sandbox.api.videpay.io (sandbox) or https://api.videpay.io (live). Pass your secret API key in the x-api-key header, the same key you use for REST. You receive every business event for that API key's business.

  1. Install socket.io-client.
  2. Connect to the API host WebSocket URL with x-api-key in extraHeaders.
  3. Listen for connected, then subscribe to event names matching your webhooks.
  4. Handle error events for auth failures or expired keys.
GET(WebSocket) connect

Socket.IO connection handshake. On success the server emits connected with business and apiKey summary.

Headers

headers
01x-api-key: sk_...

Backend example

Listen for payment.settled and deposit.updated with the same payload structure as your webhook handler.

realtime-server.ts
01import { io } from "socket.io-client";02 03const socket = io("https://sandbox.api.videpay.io", {04  transports: ["websocket"],05  extraHeaders: {06    "x-api-key": process.env.VIDEPAY_SECRET_KEY,07  },08});09 10socket.on("connected", (payload) => {11  console.log("Connected as", payload.authType, payload.business.name);12});13 14// Same event names and payload shapes as webhooks15socket.on("payment.settled", (payload) => {16  // payload: { event, emittedAt, businessId, data }17  fulfillOrder(payload.data.payment.reference);18});19 20socket.on("deposit.updated", (payload) => {21  updateCheckoutProgress(payload.data.deposit);22});23 24socket.on("error", ({ code, message }) => {25  console.error("Realtime error", code, message);26});

Checkout page example

Public checkout pages use a realtime token: never expose your secret API key in the browser.

checkout-realtime.ts
01import { io } from "socket.io-client";02 03// 1. Create deposit session on your checkout page04// 2. Exchange session for a short-lived token05const tokenRes = await fetch(06  `/checkout-links/public/${publicCode}/realtime-token`,07  {08    method: "POST",09    headers: { "Content-Type": "application/json" },10    body: JSON.stringify({ sessionId }),11  },12);13const { token } = await tokenRes.json();14 15// 3. Connect with checkout-public auth16const socket = io("https://sandbox.api.videpay.io", {17  transports: ["websocket"],18  auth: { token },19});20 21socket.on("connected", (payload) => {22  console.log("Checkout realtime ready", payload.checkout);23});24 25socket.on("payment.settled", (payload) => {26  showSuccessUI(payload.data.payment);27});

Connect from a checkout page (public token)

For customer-facing pages, never embed your secret API key. Request a short-lived realtime token tied to a deposit session or payment, then connect with auth: { token }.

POST/checkout-links/public/:publicCode/realtime-token

Issue a scoped token for checkout status events only.

Headers

headers
01Content-Type: application/json

Request body

request.json
01{02  "sessionId": "ds_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b"03}

Event payloads

Realtime emits the same JSON your webhook endpoint receives. Example listeners:

POST(WebSocket event: payment.settled)

Identical to webhook body: use the same parsing code.

Request body

request.json
01{02  "event": "payment.settled",03  "emittedAt": "2026-07-07T10:12:00.000Z",04  "businessId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",05  "data": {06    "type": "payment",07    "payment": {08      "id": "pst_4a8f2c1d9e7b6a3f5c2d8e1b0a9f7c6d",09      "title": "Videpay Pro Plan",10      "description": null,11      "reference": "order-1001",12      "referenceHash": "0xabc123...",13      "flow": "deposit",14      "status": "settled",15      "environment": "test",16      "chain": {17        "id": 84532,18        "name": "base-sepolia"19      },20      "merchant": {21        "profileId": "prof_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b",22        "merchantAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",23        "settlementContractAddress": "0xPaymentSettlementAddress",24        "tokenRegistryAddress": "0xTokenRegistryAddress"25      },26      "checkoutLinkId": "cl_7f3a9b2c-4d1e-4a8f-9c0b-1e2d3f4a5b6c",27      "customerAddress": "0xCustomerWallet12345678901234567890123456789012",28      "customer": {29        "id": ":cus_3b7e9f1a-2c4d-5e6f-7a8b-9c0d1e2f3a4b",30        "name": "Jane Doe",31        "email": "buyer@example.com",32        "phoneNumber": null,33        "reference": null34      },35      "asset": {36        "name": "USD Coin",37        "symbol": "USDC",38        "logo": "",39        "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",40        "decimals": 6,41        "isNative": false42      },43      "amounts": {44        "grossRaw": "25000000",45        "gross": "25",46        "feeRaw": "125000",47        "fee": "0.125",48        "netRaw": "24875000",49        "net": "24.875",50        "refundedRaw": "0",51        "refunded": "0"52      },53      "batch": null,54      "intent": null,55      "relay": {56        "queuedAt": null,57        "startedAt": null,58        "attemptCount": 059      },60      "transaction": {61        "hash": "0xabc123def4567890abcdef1234567890abcdef1234567890abcdef1234567890",62        "blockNumber": 12345678,63        "logIndex": 464      },65      "refundTransaction": {66        "hash": null,67        "blockNumber": null,68        "logIndex": null69      },70      "metadata": {},71      "preparedAt": "2026-07-07T10:10:00.000Z",72      "submittedAt": "2026-07-07T10:11:00.000Z",73      "settledAt": "2026-07-07T10:12:00.000Z",74      "refundedAt": null,75      "failedAt": null,76      "lastSyncedAt": "2026-07-07T10:12:00.000Z",77      "failureReason": null,78      "createdAt": "2026-07-07T10:10:00.000Z",79      "updatedAt": "2026-07-07T10:12:00.000Z"80    }81  }82}
POST(WebSocket event: deposit.created)

Fires when a deposit session is created with an address.

Request body

request.json
01{02  "event": "deposit.created",03  "emittedAt": "2026-07-07T10:12:00.000Z",04  "businessId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",05  "data": {06    "type": "deposit",07    "deposit": {08      "id": "ds_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b",09      "title": "Videpay Pro Plan",10      "description": null,11      "reference": "order-1001",12      "status": "AWAITING_PAYMENT",13      "environment": "test",14      "chain": {15        "id": 84532,16        "name": "base-sepolia"17      },18      "asset": {19        "name": "USD Coin",20        "symbol": "USDC",21        "logo": "",22        "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",23        "decimals": 624      },25      "merchantAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",26      "checkoutLinkId": "cl_7f3a9b2c-4d1e-4a8f-9c0b-1e2d3f4a5b6c",27      "refundAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",28      "depositAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",29      "depositFactoryAddress": "0xDepositFactoryAddress",30      "tokenRegistryAddress": "0xTokenRegistryAddress",31      "amounts": {32        "expectedRaw": "25000000",33        "expected": "25",34        "receivedRaw": "0",35        "received": "0",36        "remainingRaw": "25000000",37        "remaining": "25",38        "excessRaw": "0",39        "excess": "0",40        "refundedRaw": "0",41        "refunded": "0",42        "progressPercentage": "0.00"43      },44      "customer": {45        "id": ":cus_3b7e9f1a-2c4d-5e6f-7a8b-9c0d1e2f3a4b",46        "name": "Jane Doe",47        "email": "buyer@example.com",48        "phoneNumber": null,49        "reference": null50      },51      "metadata": {},52      "announceTxHash": null,53      "announcedAt": null,54      "expiresAt": "2026-07-07T11:00:00.000Z",55      "lastBalanceCheckAt": null,56      "lastSyncedAt": null,57      "settledAt": null,58      "refundedAt": null,59      "cancelledAt": null,60      "settlementPaymentId": null,61      "createdAt": "2026-07-07T10:05:00.000Z",62      "updatedAt": "2026-07-07T10:05:00.000Z",63      "routes": []64    }65  }66}
POST(WebSocket event: transfer.updated)

Fires when outbound transfer status changes: also available on merchant Realtime.

Request body

request.json
01{02  "event": "transfer.updated",03  "emittedAt": "2026-07-07T10:12:00.000Z",04  "businessId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",05  "data": {06    "environment": "test",07    "chain": {08      "id": 84532,09      "name": "base-sepolia",10      "displayName": "Base Sepolia",11      "explorerUrl": "https://base-sepolia.blockscout.com",12      "logoPath": "/chains/base.svg",13      "logoUrl": null,14      "nativeAsset": {15        "name": "Ether",16        "symbol": "ETH",17        "logoPath": "/assets/eth.svg",18        "logoUrl": null19      }20    },21    "business": {22      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",23      "name": "Acme Commerce",24      "logo": null25    },26    "merchant": {27      "profileId": "prof_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b",28      "merchantId": "0x0000000000000000000000000000000000000001",29      "merchantAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",30      "ownerAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",31      "settlementMode": "external_wallet",32      "registryStatus": "registered",33      "walletStatus": "ready",34      "registeredAt": "2026-07-01T10:00:00.000Z",35      "lastSyncedAt": "2026-07-07T09:00:00.000Z"36    },37    "transfer": {38      "id": "trf_5c8d2e1f-9a3b-4c7d-8e6f-1a2b3c4d5e6f",39      "reference": "payout-001",40      "referenceHash": "0xdef456...",41      "status": "executed",42      "txHash": "0xdef456abc7890123456789012345678901234567890123456789012345678901",43      "blockNumber": 12345680,44      "logIndex": 2,45      "merchantAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",46      "recipient": {47        "address": "0xRecipientAddress123456789012345678901234567890",48        "recipientId": "rcp_7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d",49        "source": "registry"50      },51      "batch": null,52      "asset": {53        "name": "USD Coin",54        "symbol": "USDC",55        "logo": "",56        "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",57        "decimals": 658      },59      "amount": {60        "raw": "1000000"61      },62      "memo": "Weekly vendor payout",63      "metadata": null,64      "deadline": "2026-07-07T14:05:00.000Z",65      "processingStartedAt": "2026-07-07T14:00:00.000Z",66      "submittedAt": "2026-07-07T14:00:30.000Z",67      "executedAt": "2026-07-07T14:01:00.000Z",68      "failedAt": null,69      "failureReason": null,70      "submissionAttemptCount": 1,71      "createdAt": "2026-07-07T14:00:00.000Z",72      "updatedAt": "2026-07-07T14:01:00.000Z"73    }74  }75}

Webhooks you'll receive

Register a webhook endpoint and verify the X-Protocol-Signature header on every delivery before fulfilling orders or updating your database.

Webhookpayment.settled

Sent when funds are confirmed on-chain and credited to your merchant balance.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: payment.settled04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...
Webhookdeposit.created

Sent when a deposit session is created and a unique payment address is assigned.

Delivery headers

webhook-headers
01Content-Type: application/json02User-Agent: Protocol-Webhooks/1.003X-Protocol-Event: deposit.created04X-Protocol-Delivery: wev_1a2b3c4d-5e6f-7890-abcd-ef123456789005X-Protocol-Business-Id: a1b2c3d4-e5f6-7890-abcd-ef123456789006X-Protocol-Attempt: 107X-Protocol-Signature: sha256=abc123def456...