Documentation

Settlement

Settlement APIs let you accept payments (eg. USDC, DAI, BUSD, USDT, EURC, and cNGN) programmatically without a hosted checkout page. Deposit sessions assign a unique address per payment with a fixed expected amount, partial-payment tracking, and automatic excess refunds on sweep. Wallet direct and wallet intent flows cover in-app payers. Videpay detects on-chain activity, sweeps deposits, relays intents, and emits webhooks as payments move to settled.

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

When should I use this?

  • You embed payment into your own product UI instead of hosted checkout.
  • You need standalone deposit sessions with unique on-chain addresses.
  • Customers pay from an in-app wallet (direct transaction or signed intent).

Why use Videpay?

  • Same settlement engine and fee model as checkout: consistent payout routing.
  • Deposit sessions enforce a fixed expected amount with partial, full, and overpayment handling built in.
  • Public API keys can create sessions and poll status from frontends safely.
  • Sync, settle, refund, and recovery operations cover the full deposit lifecycle.

Exchange withdrawal with partial then full pay

Your app creates a 25 USDC deposit session. The customer sends 10 USDC first, deposit.updated shows PARTIALLY_FUNDED with remaining 15. An hour later they send 15 more, status becomes FULLY_FUNDED, sweep runs, and payment.settled credits your balance. If they had sent 30 USDC in one go, we'd still settle 25 and the 5 USDC excess would refund to refundAddress automatically.

Before you start

  • Sandbox or live secret API key (public key for create/poll endpoints)
  • Registered merchant wallet on the target chain
  • Webhook endpoint or Realtime connection for deposit and payment events

How settlement works

  1. Quote protocol fee with POST /payments/quote-fee before presenting totals.
  2. Choose a flow: deposit session (address), wallet direct (unsigned tx), or wallet intent (EIP-712 + relay).
  3. Poll GET endpoints or listen to webhooks as status advances.
  4. Terminal success always surfaces as payment.settled with the appropriate flow value.
FieldTypeRequiredDescription
directflowNoPayer sends an on-chain pay() transaction from their wallet. Returns unsigned transaction calldata.
relayed_intentflowNoPayer signs an EIP-712 PaymentIntent; Videpay relays settlement gaslessly after token approval.
relayed_batchflowNoMultiple relayed_intent payments settled in one on-chain batch transaction.
deposit_sweepflowNoFunds received at a deposit address are swept into your merchant balance. Created when a deposit session settles.

Dashboard features

Dashboard maps to these APIs

Open Dashboard → Payments. The Payments tab lists settlement records (GET /payments/settlements) with filters, detail view (GET /payments/settlements/{id}), sync, and refund actions. The Deposits tab lists deposit sessions (GET /payments/deposit-sessions) with balance progress, manual settle, refund, and token recovery. Dashboard browser calls include authorization step-up (PIN/OTP/2FA) in the request body: API key integrations omit it.

  1. Payments tab: filter by status, reference, customer; open detail for tx hash, fees, and refund.
  2. Deposits tab: monitor amounts.received progress; trigger settle or refund from the session drawer.
  3. Create deposit session or prepare direct/intent payment from dashboard modals (same payloads as API).
  4. Activity log mirrors PAYMENT_* and PAYMENT_DEPOSIT_* audit events from API calls.

Quote protocol fee

Preview gross, fee, and net amounts from the on-chain TokenRegistry Payment fee bucket before creating a settlement or showing totals in your UI.

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
assetstringYesAsset symbol to quote (USDC).
amountdecimal stringYesGross payment amount in human units.
POST/payments/quote-fee

Quote protocol fee for a payment amount. Accepts public or secret API keys.

Headers

headers
01x-api-key: pk_AbCdEfGhIj_XyZ1234567890abcdefghij02Content-Type: application/json

Request body

request.json
01{02  "chain": "base",03  "asset": "USDC",04  "amount": "25"05}

Deposit session funding rules

A deposit session is a fixed-amount payment contract, not an open tip jar. When you create a session, `amount` becomes the on-chain `expectedAmount` for that deposit address. Videpay continuously syncs the address balance, advances session status, emits webhooks, and, once fully funded, sweeps the expected portion to your merchant wallet. Surplus and expiry behavior are deterministic; your integration mostly listens and reacts.

Why deposit address ≠ donation address

Deposit sessions require a fixed expected amount: the customer is paying an invoice, not choosing a number. Donation campaigns accept any amount to a campaign `walletAddress` and aggregate toward an optional `goalUsd`. Deposit sessions also use a separate, higher protocol fee bucket than donations. Different rails for different economics.

  1. PENDING: session is open, `amounts.received` is zero. Customer has not sent funds yet (or sync has not observed them).
  2. PARTIALLY_FUNDED: customer sent less than `amounts.expected`. Videpay emits deposit.updated with `amounts.received`, `amounts.remaining`, and `amounts.progressPercentage`. The session stays open; background sync keeps watching for the rest until `expiresAt` or full funding.
  3. FULLY_FUNDED: `amounts.received` ≥ `amounts.expected`. If the customer overpaid, `amounts.excess` is populated but settlement has not happened yet. Videpay selects the winning route (for multi-chain sessions) and queues an on-chain sweep automatically; you can also nudge with POST `/payments/deposit-sessions/{id}/settle`.
  4. SETTLED: sweep completed. Exactly `expectedAmount` (net of protocol fee) credits your merchant balance via a `deposit_sweep` settlement payment. `payment.settled` is the terminal success event, there is no `deposit.settled` webhook. `session.settlementPaymentId` links the session to the settlement record.
  5. EXPIRED / REFUNDED / CANCELLED: terminal failure or reversal paths. Partially funded sessions that miss the deadline move to EXPIRED; funds can be returned via refund flows documented on the Refunds page.

Partial payments and overpayment

Deposit addresses are designed for real-world payer behavior: wire delays, exchange minimums, and the occasional math typo.

  1. Underpayment (partial): Customer sends 12 USDC on a 25 USDC session. Status becomes `PARTIALLY_FUNDED`. deposit.updated fires with `remaining: "13"` and `progressPercentage: "48.00"`. Do not fulfill yet. Wait for additional transfers or expiry. Poll GET `/payments/deposit-sessions/{id}` or listen on Realtime for the same payload shape.
  2. Exact payment: Customer sends exactly 25 USDC. Status becomes `FULLY_FUNDED`, then sweep runs. You receive payment.settled when the merchant credit is confirmed.
  3. Overpayment: Customer sends 30 USDC on a 25 USDC session. API exposes `amounts.excess: "5"` while status is `FULLY_FUNDED`. On sweep, the contract settles exactly `expectedAmount` to your merchant wallet and automatically refunds the excess to `refundAddress` in the same on-chain transaction. After settlement, `amounts.refunded` reflects the returned surplus. You keep the invoice amount; the customer gets their change back, no manual refund ticket required.
  4. Wrong token: Customer sends the wrong ERC-20. Use POST `.../recover-token` (or `recover-native` for ETH) to move it off the deposit address into Videpay platform custody. A recovery holding is created. Release it via POST `/recovery-holdings/{id}/release` to credit your registered `merchantAddress`. Unsupported sends do not count toward `amounts.received` for the expected asset.
FieldTypeRequiredDescription
amounts.expected / expectedRawdecimal / rawNoFixed invoice total configured at session creation. This is the amount sweep settles toward.
amounts.received / receivedRawdecimal / rawNoUSDC observed at the deposit address so far. Increments as transfers arrive.
amounts.remaining / remainingRawdecimal / rawNoShortfall until fully funded. Zero once received ≥ expected.
amounts.excess / excessRawdecimal / rawNoSurplus above expected before sweep. Refunded to refundAddress during sweep.
amounts.refunded / refundedRawdecimal / rawNoAfter SETTLED or REFUNDED, cumulative amount returned to refundAddress (includes overpayment change).
amounts.progressPercentagestringNoFunding progress toward expected (e.g. "50.00" for half paid). Useful for checkout progress UI.
refundAddressaddressNoRequired for overpayment change and expiry refunds. Set at session creation; baked into the on-chain deposit route.

Deposit sessions

Deposit sessions assign a unique `depositAddress` per payment (or one address per chain when `chain` is omitted). Customers send the expected asset from any wallet or exchange withdrawal. Videpay tracks partial receipts via deposit.updated, auto-sweeps when fully funded, and refunds excess atomically on sweep. Terminal success is always payment.settled with `flow: deposit_sweep`.

Omit chain for all supported networks

If you do not pass `chain` on POST /payments/deposit-sessions, Videpay creates deposit routes on every active merchant chain that supports the asset. The session includes `routes[]` with an address per network. When multiple routes receive funds, the first fully funded route wins; surplus on non-winning routes can be refunded after the winner settles. Pass `chain` only when you want a single-network session.

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoLock the session to one chain. Omit to create deposit routes on every active merchant chain that supports the asset: session.routes[] lists an address per network. An unsupported asset and chain combination returns 400. See Supported chains.
assetstringYesAsset symbol from GET /finance/assets. When chain is omitted, routes are created on every active merchant chain that lists this symbol.
amountdecimal stringYesExpected deposit amount: fixed for the life of the session. Partial and overpayment handling is relative to this total.
refundAddressaddressNoAddress to return overpayment change and expiry refunds. Required for correct excess handling on sweep.
payerAddressaddressNoExpected sender wallet (optional enforcement hint).
customerIduuidNoAttach session to a CRM customer.
expiresAtdatetimeNoISO datetime when the session stops accepting deposits.
expiresInMinutesintegerNoRelative expiry (1–1440 minutes) instead of expiresAt.
reference / title / description / metadatastring / objectNoReconciliation and display fields.
POST/payments/deposit-sessions

Create a standalone deposit session. Accepts public or secret API keys.

Headers

headers
01x-api-key: pk_AbCdEfGhIj_XyZ1234567890abcdefghij02Content-Type: application/json

Request body

request.json
01{02  "asset": "USDC",03  "chain": "base",04  "amount": "25",05  "reference": "tip-001",06  "refundAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",07  "payerAddress": "0xCustomerWallet12345678901234567890123456789012",08  "customerId": ":cus_3b7e9f1a-2c4d-5e6f-7a8b-9c0d1e2f3a4b",09  "checkoutLinkId": "cl_7f3a9b2c-4d1e-4a8f-9c0b-1e2d3f4a5b6c",10  "title": "Videpay Pro Plan",11  "expiresInMinutes": 60,12  "metadata": {13    "orderId": "ord-1001"14  }15}
GET/payments/deposit-sessions/ds_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b

Retrieve deposit session status, amounts, and settlementPaymentId when swept. Accepts public or secret API keys.

Headers

headers
01x-api-key: pk_AbCdEfGhIj_XyZ1234567890abcdefghij02Content-Type: application/json
GET/payments/deposit-sessions

List deposit sessions. Requires secret API key.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Deposit session operations

Background workers continuously sync active deposit sessions; you rarely need to poll manually. Use sync to force a balance refresh after a slow exchange withdrawal, settle to nudge sweep when a session is already `FULLY_FUNDED`, and recovery endpoints when customers send the wrong asset. Refund and refund-all are documented on the Refunds page.

Deposit webhooks vs payment.settled

While a deposit is in progress, listen for deposit.created (session opened) and deposit.updated (partial receipts, balance syncs, status transitions). These events are not sent for terminal session statuses. When sweep completes, Videpay emits payment.settled with `flow: deposit_sweep`, not `deposit.settled`. Use `session.settlementPaymentId` to correlate the deposit session with its settlement record. For partial payments, deposit.updated is your progress signal; for fulfillment, wait for payment.settled.

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
wrongTokenaddressYesERC-20 contract address of the token mistakenly sent to the deposit address.
POST/payments/deposit-sessions/ds_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b/sync

Queue an on-chain balance sync for the deposit address.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json
POST/payments/deposit-sessions/ds_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b/settle

Queue a sweep after the session is fully funded. Creates a settlement payment with flow deposit_sweep and emits payment.settled when complete.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json
POST/payments/deposit-sessions/ds_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b/recover-token

Queue recovery of a non-USDC ERC-20 token mistakenly sent to the deposit address.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "wrongToken": "0xWrongToken12345678901234567890123456789012"03}
POST/payments/deposit-sessions/ds_8e4f1a2b-3c5d-4e6f-7a8b-9c0d1e2f3a4b/recover-native

Queue recovery of native ETH accidentally sent to the deposit address.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Wallet direct settlement

The payer broadcasts a pay() transaction from their wallet. The API returns calldata for your wallet SDK. No relay queue involved.

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
assetstringYesAsset symbol from GET /finance/assets (see Supported chains). Must be supported on the selected chain.
amountdecimal stringYesPayment amount in human units (e.g. "25" for 25 USDC).
customerAddressaddressYesPayer wallet address.
customerIduuidNoLink payment to an existing CRM customer.
title / description / referencestringNoDisplay and reconciliation fields echoed in webhooks.
metadataobjectNoArbitrary JSON (max 16KB) stored on the payment.
ttlSecondsintegerNoIntent-only: signature validity window (30–86400 seconds).
POST/payments/settlements/direct/prepare

Prepare a wallet-direct settlement. Requires secret API key.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "chain": "base",03  "asset": "USDC",04  "amount": "25",05  "customerAddress": "0xCustomerWallet12345678901234567890123456789012",06  "customerId": ":cus_3b7e9f1a-2c4d-5e6f-7a8b-9c0d1e2f3a4b",07  "reference": "tip-002",08  "title": "In-app tip",09  "metadata": {10    "recipientId": "user_42"11  }12}

Wallet intent settlement

The payer signs an EIP-712 PaymentIntent and approves USDC. Your backend relays the signature; Videpay submits the on-chain transaction gaslessly.

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
assetstringYesAsset symbol from GET /finance/assets (see Supported chains). Must be supported on the selected chain.
amountdecimal stringYesPayment amount in human units (e.g. "25" for 25 USDC).
customerAddressaddressYesPayer wallet address.
customerIduuidNoLink payment to an existing CRM customer.
title / description / referencestringNoDisplay and reconciliation fields echoed in webhooks.
metadataobjectNoArbitrary JSON (max 16KB) stored on the payment.
ttlSecondsintegerNoIntent-only: signature validity window (30–86400 seconds).
ttlSecondsintegerNoIntent signature validity window (30–86400 seconds). Defaults to 3600.
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
paymentIduuidYesPrepared relayed_intent payment ID.
signaturehex stringYesEIP-712 signature from the payer wallet.
POST/payments/settlements/intents/prepare

Prepare a relayed_intent payment and return typed data for signing.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "chain": "base",03  "asset": "USDC",04  "amount": "25",05  "customerAddress": "0xCustomerWallet12345678901234567890123456789012",06  "customerId": ":cus_3b7e9f1a-2c4d-5e6f-7a8b-9c0d1e2f3a4b",07  "reference": "tip-003",08  "ttlSeconds": 360009}
POST/payments/settlements/intents/relay

Relay a signed payment intent. Queues on-chain submission and emits payment.updated while processing.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "paymentId": "pst_4a8f2c1d9e7b6a3f5c2d8e1b0a9f7c6d",03  "signature": "0x..."04}

Settlement payment details

Poll or list settlement payments across all flows. Use sync when webhooks are delayed or to confirm relay progress.

FieldTypeRequiredDescription
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
customerIduuidNoFilter by linked CRM customer.
checkoutLinkIduuidNoFilter by originating checkout link.
statusstringNoSettlement status filter (pending, queued, submitted, settled, refunded, failed, invalidated).
qstringNoSearch reference, title, or customer wallet address.
offset / limitintegerNoPagination. limit max 100.
businessIduuidNoTarget business. Omit when your API key is scoped to one business.
chainstringNoChain scope for settlement APIs (base, polygon, etc.). Required for wallet direct/intent prepare. Sandbox resolves to testnets automatically.
txHashhex stringNoOptional on-chain transaction hash. Omit to nudge relay/sync workers when txHash is already known.
GET/payments/settlements/pst_4a8f2c1d9e7b6a3f5c2d8e1b0a9f7c6d

Retrieve payment status, amounts, and transaction hash. Accepts public or secret API keys.

Headers

headers
01x-api-key: pk_AbCdEfGhIj_XyZ1234567890abcdefghij02Content-Type: application/json
GET/payments/settlements

List settlement payments with filters. Requires secret API key.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json
POST/payments/settlements/pst_4a8f2c1d9e7b6a3f5c2d8e1b0a9f7c6d/sync

Force sync with on-chain state. Optionally pass txHash when relay metadata is missing.

Headers

headers
01x-api-key: sk_AbCdEfGhIj_XyZ1234567890abcdefghijklmnopqrstuvwxyz01234502Content-Type: application/json

Request body

request.json
01{02  "txHash": "0xabc123..."03}

Webhook events

Settlement integrations typically subscribe to deposit.created, deposit.updated, payment.created, payment.updated, payment.settled, and payment.refunded. Every deposit and payment payload includes a customer field: pass customerId at creation or collect buyer identity at checkout so fulfillment webhooks carry your CRM record. When nothing is linked yet, customer is null (the key is still present).

FieldTypeRequiredDescription
customerobject | nullNoLinked CRM customer when customerId was set at creation or checkout collected buyer identity. Always present on deposit sessions, settlement payments, and subscriptions: null when unlinked. Shape: { id, name, email, phoneNumber, reference }.
iduuidNoVidepay customer record ID.
namestringNoDisplay name.
email / phoneNumberstring | nullNoContact fields when collected.
referencestring | nullNoYour CRM or user ID: unique per business.
deposit.createdeventNoDeposit session created with depositAddress assigned. Customer at data.deposit.customer.
deposit.updatedeventNoBalance or status change while session is non-terminal (partial payment, sync). Customer at data.deposit.customer. Not sent after SETTLED, REFUNDED, or CANCELLED.
payment.createdeventNoSettlement record created for direct or relayed_intent prepare. Customer at data.payment.customer.
payment.updatedeventNoRelay queue progress, submission, or non-terminal status change. Customer at data.payment.customer.
payment.settledeventNoOn-chain settlement confirmed, including deposit_sweep after deposit address sweep. Customer at data.payment.customer.
payment.refundedeventNoSettlement refund completed. Customer at data.payment.customer.

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.

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...
Webhookdeposit.updated

Sent when deposit progress changes (partial payment received, balance sync, etc.). Not sent for terminal statuses.

Delivery headers

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

Sent when a settlement payment record is created (wallet direct/intent flows).

Delivery headers

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