Creating accounts
Open the account a card will spend from.
Before you begin
- A cardholder — see cardholders and KYC.
- The
program_idof the product you are opening the account under.GET /v1/programsreturns the ids you may use; Settings → Programs in Cockpit shows the same list for reading by hand. Most organizations hold one. - A currency the program supports. Nothing here rejects an unsupported one on our side — it is refused when the account is opened at the processor — so check with your account contact if you are unsure which are available.
How it works
An account holds value in exactly one currency, belongs to exactly one cardholder and exactly one program, and is what its card spends from.
program_id is where a program is named. Everything drawn on the account
inherits it — the cards, and the authorizations and transactions those cards
produce — so no call on the account's own path asks you for it again. It is fixed
at creation: there is no call that moves an account to another program.
Send it even if you hold a single program. We could default to it, and that would be right until the day a second product went live, after which accounts would quietly open under the wrong one.
It opens active, with all three balances at zero:
ledger_balance 0 money that has settled
held_balance 0 reserved by authorizations that have not cleared
available_balance 0 ledger − held, the spendable figure
A cardholder who needs two currencies needs two accounts, and the API never converts between them.
Steps
1. Create the account
Call Create an account. The request
names the program_id, the cardholder_id, the currency and, if you have one,
your own reference. Send an Idempotency-Key so a retry doesn't open a second
account.
The response is the account: active, in the currency you sent, with all three
balances at zero.
2. Set reference while you are here
reference is your own identifier. It is filterable, and it appears in every
webhook payload for this account — which is what turns an incoming
account.funded event into a row you can find in your own database without
keeping a lookup table. List accounts
takes it as a filter.
Retrofitting it later means backfilling every account you have already created. Set it now.
Verifying
Read the account back with Get an account, or list the cardholder's accounts with List accounts.
You should see status: "active", the program_id you sent, and three zero
balances. account.created fires on your webhook endpoint.
The list takes a program_id filter too, which is the shape to reach for if you
run more than one product. Omit it and the page spans every program your
organization holds — one credential covers all of them.
Common errors
| Status | code | Fix |
|---|---|---|
400 | missing_parameter | program_id was not sent. It is required even when you hold one program |
400 | invalid_parameter | program_id is malformed, or is not a program your organization holds. The two read the same on purpose — the API will not confirm that an id it refused exists somewhere else |
404 | cardholder_not_found | cardholder_id is wrong, or belongs to another organization. The two are deliberately indistinguishable |
409 | idempotency_key_reuse | Same Idempotency-Key, different body — usually a bug in retry logic |
422 | program_not_provisioned | The program is real and yours, but cannot serve this request. A configuration matter on our side — raise it rather than retrying |
Note what is not in that list: there is no kyc_not_approved. That error
belongs to issuing and activating a card, not account creation.