Bank Webhook Events#
Overview#
This document describes all outgoing webhook event payloads sent by the platform for bank account lifecycle, deposits, and withdrawals. Webhooks are HTTP POST requests with a Content-Type: application/json header delivered to your configured endpoint URL.
Payload Conventions#
| Convention | Detail |
|---|
| Format | JSON |
| HTTP Method | POST |
| Content-Type | application/json |
| Null fields | Included as null (not omitted) |
| Timestamps | ISO 8601 — YYYY-MM-DDTHH:mm:ss.fffffffZ (UTC) |
| Amounts | Decimal string in the currency's major unit (e.g., "1500.00") |
| Currency codes | ISO 4217 (fiat) or ticker symbol (digital assets, e.g., USDT) |
| Event ID | Every event carries a globally unique id (evt_ prefix) for idempotency |
| Signature | Each request includes an X-Webhook-Signature header (HMAC-SHA256 of the raw body using your webhook secret) |
Event Categories#
| Category | Events |
|---|
| Bank Account Creation | banks.accountcreation.approved, banks.accountcreation.rejected |
| Deposit | deposit.submitted, deposit.pending, deposit.approved |
| Withdrawal | withdrawal.completed, withdrawal.rejected |
1. Bank Account Creation Events#
Applicable event types: banks.accountcreation.approved · banks.accountcreation.rejectedThese events track the lifecycle of a customer's bank account creation request from submission through final decision.Payload — Approved#
{
"id": "evt_7f3a2c9d81b64f0e9a1d2c3b4e5f6a70",
"type": "banks.accountcreation.approved",
"createdAt": "2026-04-02T10:15:42.1234567Z",
"data": {
"account_id": "acct_9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
"customer_id": "f51b8db9-0bbf-4a91-b5fe-bf9d7b16f070",
"account_type": "Checking",
"account_number": "1234567890",
"routing_number": "021000021",
"iban": null,
"swift_code": "CHASUS33",
"currency": "USD",
"bank_name": "Example Partner Bank",
"bank_country": "US",
"application_status": "banks.accountcreation.approved",
"application_reason": "Approved",
"performed_at": "2026-04-02T10:15:42.1102938Z"
}
}
Payload — Rejected#
{
"id": "evt_1a2b3c4d5e6f70819a2b3c4d5e6f7081",
"type": "banks.accountcreation.rejected",
"createdAt": "2026-04-02T11:02:10.5567821Z",
"data": {
"account_id": null,
"customer_id": "f51b8db9-0bbf-4a91-b5fe-bf9d7b16f070",
"account_type": "Checking",
"account_number": null,
"routing_number": null,
"iban": null,
"swift_code": null,
"currency": "USD",
"bank_name": "Example Partner Bank",
"bank_country": "US",
"application_status": "banks.accountcreation.rejected",
"application_reason": "KYC verification failed — document mismatch",
"performed_at": "2026-04-02T11:02:10.5401237Z"
}
}
Field Reference#
| Field | Type | Description |
|---|
id | string | Globally unique event identifier (evt_ prefix). Use for idempotency |
type | string | Event type. One of banks.accountcreation.approved, banks.accountcreation.rejected |
createdAt | string | ISO 8601 timestamp when the event was created |
account_id | string | null | Unique identifier of the created bank account. null when rejected |
customer_id | string | Unique identifier of the customer who requested the account |
account_type | string | Account type — Checking, Savings, or Virtual |
account_number | string | null | Account number issued by the partner bank. null when rejected |
routing_number | string | null | ABA routing number (US accounts). null when not applicable |
iban | string | null | IBAN (international accounts). null when not applicable |
swift_code | string | null | SWIFT/BIC of the issuing bank |
currency | string | ISO 4217 currency code of the account |
bank_name | string | Name of the partner/issuing bank |
bank_country | string | ISO 3166-1 alpha-2 country code of the bank |
application_status | string | Final status of the account creation request |
application_reason | string | Human-readable reason accompanying the decision |
performed_at | string | ISO 8601 timestamp when the decision was made |
2. Deposit Events#
Applicable event types: deposit.submitted · deposit.pending · deposit.approvedThese events track the lifecycle of an incoming deposit into a customer's bank account, from initial submission through confirmation.Typical lifecycle: deposit.submitted → deposit.pending → deposit.approvedPayload#
{
"id": "evt_cdb5d44b89da4e2e84d0e981b3af5b18",
"type": "deposit.approved",
"createdAt": "2026-04-03T09:41:18.9921456Z",
"data": {
"deposit_id": "dep_41ac2f77-e2ad-4fac-b4c6-0d54a8bc3e2f",
"account_id": "acct_9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
"customer_id": "f51b8db9-0bbf-4a91-b5fe-bf9d7b16f070",
"amount": "500.00",
"currency": "USD",
"fee": "1.50",
"fee_currency": "USD",
"net_amount": "498.50",
"payment_method": "wire_transfer",
"reference_number": "WIRE20260403A1B2",
"sender_name": "Tarun Kumar",
"sender_bank": "HDFC Bank",
"sender_country": "IN",
"status": "approved",
"message": "Deposit credited successfully.",
"transaction_id": "txn_8d7c6b5a-4e3f-2d1c-0b9a-8f7e6d5c4b3a",
"submitted_at": "2026-04-03T08:12:04.2278182Z",
"performed_at": "2026-04-03T09:41:18.9812345Z"
}
}
Field Reference#
| Field | Type | Description |
|---|
id | string | Globally unique event identifier (evt_ prefix). Use for idempotency |
type | string | Event type. One of deposit.submitted, deposit.pending, deposit.approved |
createdAt | string | ISO 8601 timestamp when the event was created |
deposit_id | string | Unique identifier of the deposit |
account_id | string | Bank account receiving the deposit |
customer_id | string | Customer who owns the account |
amount | string | Gross deposit amount in the major currency unit |
currency | string | ISO 4217 currency code (or asset ticker) of the deposit |
fee | string | Platform/processing fee applied |
fee_currency | string | Currency of the fee |
net_amount | string | Amount credited after fees (amount − fee) |
payment_method | string | Method used — wire_transfer, ach, sepa, upi, crypto |
reference_number | string | Bank/network reference for reconciliation |
sender_name | string | Name of the sending party |
sender_bank | string | Name of the sending bank |
sender_country | string | ISO 3166-1 alpha-2 country code of the sender |
status | string | Current status of the deposit (submitted, pending, approved) |
message | string | Human-readable status message |
transaction_id | string | Ledger transaction identifier once posted; null before crediting |
submitted_at | string | ISO 8601 timestamp when the deposit was first submitted |
performed_at | string | ISO 8601 timestamp of the current status change |
3. Withdrawal Events#
Applicable event types: withdrawal.completed · withdrawal.rejectedFired when a customer's withdrawal request reaches a terminal state — either successfully paid out or rejected.Payload — Completed#
{
"id": "evt_3c990d0027974a269d69ecbbc6252934",
"type": "withdrawal.completed",
"createdAt": "2026-04-04T15:22:07.8274318Z",
"data": {
"withdrawal_id": "wdl_d9727b12-9de8-486e-acfc-3bf07c6bc391",
"account_id": "acct_9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
"customer_id": "f51b8db9-0bbf-4a91-b5fe-bf9d7b16f070",
"amount": "250.00",
"currency": "USD",
"fee": "2.00",
"fee_currency": "USD",
"net_amount": "248.00",
"payment_method": "wire_transfer",
"destination_account_number": "9876543210",
"destination_bank": "ICICI Bank",
"destination_country": "IN",
"reference_number": "WDL20260404X9Y8",
"status": "completed",
"message": "Withdrawal processed successfully.",
"transaction_id": "txn_1f2e3d4c-5b6a-7980-1f2e-3d4c5b6a7980",
"requested_at": "2026-04-04T14:05:31.1102938Z",
"performed_at": "2026-04-04T15:22:07.8196246Z"
}
}
Payload — Rejected#
{
"id": "evt_5377f5d53323457688ea939284e13406",
"type": "withdrawal.rejected",
"createdAt": "2026-04-04T16:10:45.2798593Z",
"data": {
"withdrawal_id": "wdl_aa11bb22-cc33-dd44-ee55-ff6677889900",
"account_id": "acct_9b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
"customer_id": "f51b8db9-0bbf-4a91-b5fe-bf9d7b16f070",
"amount": "10000.00",
"currency": "USD",
"fee": "0.00",
"fee_currency": "USD",
"net_amount": "0.00",
"payment_method": "wire_transfer",
"destination_account_number": "9876543210",
"destination_bank": "ICICI Bank",
"destination_country": "IN",
"reference_number": null,
"status": "rejected",
"message": "Insufficient balance.",
"transaction_id": null,
"requested_at": "2026-04-04T16:09:12.3345671Z",
"performed_at": "2026-04-04T16:10:45.2701234Z"
}
}
Field Reference#
| Field | Type | Description |
|---|
id | string | Globally unique event identifier (evt_ prefix). Use for idempotency |
type | string | Event type. One of withdrawal.completed, withdrawal.rejected |
createdAt | string | ISO 8601 timestamp when the event was created |
withdrawal_id | string | Unique identifier of the withdrawal request |
account_id | string | Bank account debited for the withdrawal |
customer_id | string | Customer who requested the withdrawal |
amount | string | Gross withdrawal amount requested |
currency | string | ISO 4217 currency code (or asset ticker) |
fee | string | Fee applied to the withdrawal. 0.00 when rejected |
fee_currency | string | Currency of the fee |
net_amount | string | Amount paid out after fees. 0.00 when rejected |
payment_method | string | Payout rail — wire_transfer, ach, sepa, upi, crypto |
destination_account_number | string | Beneficiary account number (masked as needed) |
destination_bank | string | Beneficiary bank name |
destination_country | string | ISO 3166-1 alpha-2 country code of the destination |
reference_number | string | null | Bank/network reference for reconciliation. null when rejected |
status | string | Final status (completed, rejected) |
message | string | Human-readable outcome message or rejection reason |
transaction_id | string | null | Ledger transaction identifier. null when rejected |
requested_at | string | ISO 8601 timestamp when the withdrawal was requested |
performed_at | string | ISO 8601 timestamp when the final decision was made |
Status Values Quick Reference#
Bank Account Creation Status#
| Value | Description |
|---|
approved | Account creation request approved and account issued |
rejected | Account creation request rejected (see application_reason) |
Deposit Status#
| Value | Description |
|---|
submitted | Deposit instruction received; awaiting funds |
pending | Funds detected/in transit; awaiting confirmation or compliance review |
approved | Funds confirmed and credited to the account |
Withdrawal Status#
| Value | Description |
|---|
completed | Withdrawal successfully processed and paid out |
rejected | Withdrawal rejected (e.g., insufficient balance, compliance hold, invalid beneficiary) |
Security & Verification#
| Practice | Detail |
|---|
| Signature verification | Compute HMAC-SHA256 of the raw request body using your webhook secret and compare (constant-time) against X-Webhook-Signature |
| Replay protection | Reject events where createdAt is older than 5 minutes, and de-duplicate on id |
| Transport | Endpoints must be HTTPS (TLS 1.2+) |
| Secret rotation | Rotate webhook secrets periodically; both old and new secrets are honored during a grace window |
Error Handling & Retries#
Your endpoint should return an HTTP 2xx status code within 10 seconds to acknowledge receipt. If a non-2xx response is returned or the request times out, the platform retries delivery with exponential backoff (e.g., 1m, 5m, 30m, 2h, 6h, up to 24h).| Scenario | Recommendation |
|---|
| Duplicate events | Use the event id (or deposit_id / withdrawal_id / account_id + type) for idempotency |
| Out-of-order delivery | Use performed_at to determine the latest state; ignore stale events |
| Unknown event type | Acknowledge (200 OK) and ignore gracefully |
| Processing failure | Return 500 to trigger retry |
| Slow processing | Acknowledge immediately and process asynchronously (queue the payload) |
Modified at 2026-08-10 12:32:20