Activating Bank Account Details
Activate ACH, SPEI and Faster Payments details, and read the account details for incoming transfers.
Before You Start
Read the following guides before proceeding:
| Guide | Why |
|---|---|
| Getting Started | Platform overview and setup |
| Api Basics | Required headers and request configuration |
| Authentication | How to obtain the corporation token |
| Capabilities | Account activation is capability-gated |
| Verification (KYB) | Verification unlocks the capability |
Overview
A corporate bank account is a set of fiat details in the corporation's own name — an IBAN, a routing and
account number pair, a sort code and account number, or a CLABE. Funds received into them are credited
to the corporation's on-chain balance.
Details are activated per rail. One account can carry details of several types, and the details for a
given rail are what make deposits on that rail possible.
Which Rails Are Activated Through the API
| Rail | account_type | Activated by |
|---|---|---|
| ACH | Ach | POST /api/v1/bank/accounts |
| SPEI | Spei | POST /api/v1/bank/accounts |
| Faster Payments | FasterPayment | POST /api/v1/bank/accounts |
| SEPA | Sepa | Not through this endpoint — provisioned automatically once the corporation is verified |
| SWIFT | Swift | Not activatable — the value is accepted by the schema and rejected by the handler |
Sepais rejected by validation with400 ErrorInvalidField,
"expected": "Ach|Spei|FasterPayment". SEPA details are provisioned automatically on verification;
watchSepaAccountonGET /api/v1/corporationsand read the details from
GET /api/v1/bank/accountswhen it turnsActive.
Swiftpasses the request schema — it is a validAccountTypevalue — and is then refused by the
handler with400 ErrorInvalidFieldandInvalid value for account type. There is no SWIFT
activation flow.
Step 1: Check the Capability
Read GET /api/v1/corporations and find the capability for the rail:
account_type | Capability | Status that permits activation |
|---|---|---|
Ach | AchAccount | ActivationNotStarted |
Spei | SpeiAccount | ActivationNotStarted |
FasterPayment | FasterPaymentsAccount | ActivationNotStarted |
The endpoint requires the capability to be exactly ActivationNotStarted. Any other status is
refused with 400 and Capability does not need activation — including Active, which means the
details already exist, and NotFulfilled, which means verification is incomplete.
Equivalently, look for ActivateAchDetails, ActivateSpeiDetails or ActivateSepaDetails in the
corporation's actions array — the action is present exactly when the activation call will be accepted.
Step 2: Activate the Details
POST /api/v1/bank/accounts
Requires TransactionSu, AccountSu or AccountCreate.
Request body:
{
"account_type": "Ach"
}| Field | Type | Required | Description |
|---|---|---|---|
account_type | string | Yes | Ach, Spei or FasterPayment |
Response:
{
"details_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}| Field | Description |
|---|---|
details_id | Identifier of the created details. It is the second half of the composite account_id used by transfers |
How the Account Is Chosen
Each rail maps to a currency, and the handler looks for an existing Active account in that currency:
account_type | Currency |
|---|---|
Ach | USD |
Spei | USD |
FasterPayment | GBP |
Sepa | EUR |
If an Active account in that currency exists, the new details are attached to it. Otherwise a new
account is created. Either way the response carries only details_id — read
GET /api/v1/bank/accounts to see which account it landed on.
AchandSpeiboth map to USD. Activating SPEI when an ACH account already exists attaches the
SPEI details to that same USD account rather than creating a second one.
Code
const response = await fetch(`${baseUrl}/api/v1/bank/accounts`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${corporationToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ account_type: 'Ach' })
});
const { details_id: detailsId } = await response.json();response = requests.post(
f"{base_url}/api/v1/bank/accounts",
headers={
"Authorization": f"Bearer {corporation_token}",
"Content-Type": "application/json",
},
json={"account_type": "Ach"},
)
details_id = response.json()["details_id"]body, _ := json.Marshal(map[string]string{"account_type": "Ach"})
req, _ := http.NewRequest("POST", baseURL+"/api/v1/bank/accounts", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer "+corporationToken)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var activateResp struct {
DetailsId string `json:"details_id"`
}
json.NewDecoder(resp.Body).Decode(&activateResp)Step 3: Read the Account Details
GET /api/v1/bank/accounts
Requires TransactionSu, TransactionCreate or AccountView.
Query parameters:
| Parameter | Description |
|---|---|
page_number | 1-indexed page number |
page_size | Page size. Defaults to 25 |
sort | name (default, ascending) or usage (descending usage count) |
Response:
{
"data": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6:64120850-73a1-4df5-a074-d463258c9deb",
"currency": "EUR",
"status": "Active",
"account_holder": "Acme Inc.",
"account_type": "Sepa",
"created_at": "2024-01-01T10:00:00Z",
"details": {
"iban": "DE89370400440532013000",
"bic": "COBADEFF",
"account_number": "",
"sort_code": "",
"routing_number": "",
"clabe": "",
"mandatory_reference": "#Acme Inc."
}
}
]
}| Field | Description |
|---|---|
id | Composite identifier — <accountId>:<detailsId>. This whole string is the account_id transfers take |
currency | ISO 4217 currency of the account |
status | Active, Pending, Blocked or Closed |
account_holder | Name the bank holds against the account |
account_type | Sepa, Swift, FasterPayment, Ach or Spei |
created_at | ISO 8601 creation timestamp |
details.iban / details.bic | Populated for Sepa and Swift |
details.account_number | Populated for FasterPayment and Ach |
details.sort_code | Populated for FasterPayment |
details.routing_number | Populated for Ach |
details.clabe | Populated for Spei |
details.mandatory_reference | When present, the sender must put this string in the transfer reference for the deposit to be credited |
idis two UUIDs joined by a colon, and transfers want the whole thing. A caller that sends only
the account half is rejected with400 ErrorInvalidFieldandInvalid format for account id. Never
split it.
mandatory_referenceis not optional when it is present. A deposit that arrives without it
cannot be matched to the account. Surface it wherever you show account details to whoever is sending
the money.
Receiving Deposits
Once details are Active, the corporation receives funds by giving the sender the values from
details. Deposits credit the corporation's on-chain balance and appear in
GET /api/v1/activity/feed.
The capability governing receipt is separate from the one governing the account itself:
SepaIn1stParty and SepaIn3rdParty distinguish transfers from the corporation's own accounts from
transfers sent by third parties, and the same split exists for ACH and SPEI. Check the one that matches
where the money is coming from.
What Happens Next
- Details are created and the capability moves to
InProgresswhile they arePending. - When the provider issues the account, the details become
Activeand the capability follows. - The corporation's
actionsarray loses theActivate*Detailsentry and gains the matching
Receive*andSend*entries as their capabilities activate.
There is no webhook for bank account activation. Poll GET /api/v1/bank/accounts.
Error Handling
{
"error_reason": "ErrorInvalidField",
"error_description": "Invalid value for account type",
"error_category": {
"category": "CategoryValidationFailure",
"http_status_code": 400
},
"error_details": [
{ "key": "field", "details": "account_type" },
{ "key": "expected", "details": "Ach|Spei|FasterPayment" }
]
}Validation Errors (400)
| Error Reason | Error Details | Description | Resolution |
|---|---|---|---|
ErrorMissingField | field: account_type | account type is required | Send Ach, Spei or FasterPayment |
ErrorInvalidField | expected: Ach|Spei|FasterPayment | Sepa was sent | SEPA is provisioned automatically |
ErrorInvalidField | field: account_type | Invalid value for account type | Swift or an unrecognised value |
ErrorGeneral | — | Capability does not need activation | The capability is not ActivationNotStarted. Read GET /api/v1/corporations |
Permission Errors (403)
| Error Reason | Description | Resolution |
|---|---|---|
ErrorPermissionDenied | User does not have required permissions | Activation needs AccountCreate, AccountSu or TransactionSu |
Server Errors (500)
| Error Reason | Description | Resolution |
|---|---|---|
ErrorGeneral | Failed to get bank accounts | The bank service was unavailable. Retry |
ErrorGeneral | Failed to create bank account details | The provider rejected the details request. Retry, then contact Wirex |
ErrorGeneral | Failed to create bank account | No account existed and creation failed. Retry |
ErrorGeneral | Failed to create bank account details with a corporation_id detail | The provider returned no details. Contact Wirex — the request may have partially applied |
Updated 20 days ago

