Customer VIBANs
Per-customer virtual IBANs that allow your end-users to receive money in GBP / USD / EUR. Each VIBAN is bound to a single verified customer + currency.
CAD doesn’t use VIBANs — it uses Interac e-Transfer auto-deposit emails. Set the customer’s interac_email at create time + our FX rail routes inbound Interac transfers to your wallet automatically.
The customer-VIBAN object
{
"object": "virtual_account",
"id": "ckva_xxxxxxxxxxxx",
"customer_id": "ckcust_xxxxxxxxxxxx",
"customer_reference": "pouch-user-12345",
"currency": "GBP",
"env": "live",
"status": "active",
"account_number": "12345678",
"account_name": "TECHNEST/POUCH-USER-12345",
"bank_name": "Clear Junction Limited",
"bank_code": "200000",
"provider_ref": "blz_va_xxx",
"created_at": "2026-01-15T10:00:00Z"
}Status values: provisioning (awaiting upstream activation webhook) → active (ready to receive) | failed | closed.
Provision a VIBAN
POST /v1/customers/{id}/virtual_accounts
Pre-conditions:
- Remittances feature flag enabled on your merchant account
- API key has
virtual_account_createpermission (Owner-only by default) - Customer status =
verified - Currency must be
GBP/USD/EUR - Merchant has an active wallet for that currency in this env
Request
{
"currency": "GBP"
}That’s it — Swappr resolves the upstream wallet identifier from your account config + provisions the VIBAN linked to the customer.
Example
curl https://api.swappr.me/v1/customers/ckcust_xxx/virtual_accounts \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "currency": "GBP" }'Response
201 Created (new VIBAN) or 200 OK (idempotent — VIBAN already exists for this customer + currency).
If account_number is empty in the response, the VIBAN is in provisioning status — the upstream rail hasn’t returned the real account number yet. Subscribe to the virtual_account_activated webhook to be notified when the real account number lands.
Errors
| Code | HTTP | Cause |
|---|---|---|
customer_not_found | 404 | Wrong customer id or doesn’t belong to you |
customer_not_verified | 422 | Customer KYC not approved yet — verify first |
customer_not_provisioned | 422 | Customer was never successfully created upstream |
wallet_not_found | 422 | No active wallet for that currency in this env |
rail_not_configured | 503 | This currency’s VIBAN rail isn’t configured for your account. Contact support. |
provider_error | 502 | Upstream rail error — retry with same idempotency key |
List a customer’s VIBANs
GET /v1/customers/{id}/virtual_accounts
| Param | Notes |
|---|---|
limit | 1-100, default 50 |
starting_after | Cursor |
status | Filter by status |
Returns all VIBANs belonging to the specified customer.
Response
{
"object": "list",
"has_more": false,
"data": [
{ "object": "virtual_account", "id": "...", "currency": "GBP", "status": "active", ... },
{ "object": "virtual_account", "id": "...", "currency": "USD", "status": "active", ... }
]
}Sandbox limitation
Per our FX rail’s documentation:
In the development environment, only NGN virtual bank accounts settle.
GBP / USD / EUR VIBANs can be provisioned in sandbox + show as provisioning in our DB, but the account_number field stays empty because no real bank-rail account number is issued. Real settle validation requires live env.
Use sandbox for end-to-end integration testing of the customer-create + VIBAN-provision flow; switch to live for actual inflow testing.
Inflow webhooks
When money lands at a customer’s VIBAN, Swappr fires a wallet_funded event with a customer block identifying which end-user the inflow belongs to:
{
"event": "wallet_funded",
"merchantId": "ckxxxxxxxxxxxxxxxxxx",
"virtualAccount": {
"provider": "blaaiz",
"accountNumber": "12345678",
"bankName": "Clear Junction Limited",
"bankCode": "200000"
},
"amountMinor": "5000000",
"currency": "GBP",
"customer": {
"id": "ckcustxxxxxxxxxxxxxxxxxx",
"customer_reference": "your-user-reference"
},
"sender": {
"name": "EMILY HARRIET ASHWORTH",
"accountNumber": "87654321",
"sortCode": "203000",
"bankName": "Barclays UK"
},
"narration": "Top-up from Emily",
"ledgerEntryId": "ckxxxxxxxxxxxxxxxxxx",
"providerEventId": "ckxxxxxxxxxxxxxxxxxx",
"receivedAt": "2026-05-05T12:34:56.789Z"
}Use customer.customer_reference to attribute the inflow back to the right user in your system. The merchant wallet (your business wallet) is credited; per-user accounting on your side is your responsibility.
For the CAD-Interac rail, the sender block uses interac_email instead of bank-rail fields:
"sender": {
"interac_email": "demo.sender@example.ca",
"name": "MARGARET CHANTAL DUBOIS"
}Same wallet_funded event name — branch on event.virtualAccount.provider === 'blaaiz' plus the presence of sender.interac_email to detect Interac flows.