IBAN Add API
Description: Create a new IBAN account record. If iban is provided in the request, it will be validated for format and uniqueness first. If iban is omitted, one will be allocated automatically from the pre-generated IBAN pool and bound to the current api_account.
Production API URL: #/api/iban/add
Sandbox API URL: https://ibantest.yabandpay.com/api/iban/add
Method: POST
Header:
Authorization: Bearer {api_account_token}
Content-Type: application/json
1. Request Format (Unified)
| Field | Type | Description | Required |
|---|---|---|---|
| uid | string | API account unique id (matches iban_api_account.uid) |
Required |
| timestamp | integer | Request Unix timestamp in seconds. Server validates clock skew and rejects stale requests. | Required |
| nonce | string | 10-character random string, unique per request for replay prevention | Required |
| sign | string | Signature, see signature algorithm below | Required |
| data | object | Business parameters, see table below | Required |
1.1 data Object (Business Parameters)
| Parameter | Type | Description | Required |
|---|---|---|---|
| request_id | string | Client request id (recommended globally unique for idempotency and tracing; echoed back in response) | Optional |
| customer_id | string | Unique customer id in the caller's business system | Required |
| customer_type | string | Customer type: legal_entity for company / individual for person. Defaults to legal_entity. |
Optional |
| holder_name | string | IBAN holder name. If omitted, it is auto-generated as {customer_type}_{customer_id}. |
Optional |
| alternative_name | string | Alias or additional name | Optional |
| creditor_identifier | string | Creditor identifier. Defaults to holder_name when omitted. |
Optional |
| iban | string | Explicit NL IBAN. If provided, its format and uniqueness are validated; otherwise the API allocates one from the pool automatically. | Optional |
| access | integer | Access permission: 0=none, 1=full, 2=inbound, 3=outbound. Defaults to 1. | Optional |
| status | integer | Status: 0=inactive, 1=active. Defaults to 1. | Optional |
| remark | string | Remarks | Optional |
1.2 Signature Algorithm (HMAC-SHA256)
Client-side calculation steps (strict order):
- Remove the
signfield from the raw request body. If arolefield exists, it must also be excluded. - Flatten every field inside
datato the top level, together withuid / timestamp / nonce. - Sort the flattened fields by key in ascending dictionary order (
ksort()). - Concatenate them as a query string in the form
k1=v1&k2=v2&k3=v3. - Compute
HMAC-SHA256with the accountsecret_key, and lowercase the hex digest as the value ofsign.
Signature formula:
sign = hash_hmac('sha256', implode('&', ksort(merge(data, {uid,timestamp,nonce})) ), secret_key)
Signature example (PHP):
$secretKey = 'your_account_secret_key';
$body = [
'uid' => '900001',
'timestamp' => 1731926400,
'nonce' => 'Qe3CkH2xP8',
'data' => [
'request_id' => 'req_202411180049',
'customer_id' => 'CUST20260001',
'timezone' => 'Asia/Shanghai',
'customer_type' => 'legal_entity',
'holder_name' => 'Yabandpay B.V.',
],
];
$sign = getSignByYabandPayV3($body, $secretKey);
$body['sign'] = $sign;
2. Request Example
{
"uid": "900001",
"timestamp": 1731926400,
"nonce": "Qe3CkH2xP8",
"sign": "A1AC665F9B40F7C51212BCE080F5B987",
"data": {
"request_id": "req_202411180049",
"customer_id": "CUST20260001",
"customer_type": "legal_entity",
"holder_name": "Yabandpay B.V.",
"alternative_name": "YB HQ",
"creditor_identifier": "YABAND001",
"access": 1,
"status": 1,
"remark": "Dutch HQ corporate account"
}
}
3. Response Example
Success (200)
{
"status": true,
"code": "200",
"data": {
"id": 1001,
"customer_type": "legal_entity",
"customer_id": "CUST20260001",
"holder_name": "Yabandpay B.V.",
"alternative_name": "YB HQ",
"creditor_identifier": "YABAND001",
"bic": "YABNNL22",
"iban": "NL08YABN0187654321",
"currency": "EUR",
"balance": "0.00",
"access": 1,
"access_label": "full",
"status": 1,
"status_label": "active",
"remark": "Dutch HQ corporate account",
"api_account_id": 1,
"created_at": 1784851200,
"updated_at": 1784851200,
"request_id": "req_202411180049",
"response_id": "TRADE20260819XXXXXX"
},
"message": ""
}
Common Failure Codes
| code | Description |
|---|---|
| 401 | Missing headers, invalid token format, missing required fields like uid/sign/timestamp/nonce/data, etc. |
| -1001 | Signature error |
| -1010 | API account does not exist or has been disabled (middleware / account disabled) |
| -2001 | Account cache is empty or uid is not present in the account registry |
| -3001 | Database write failed / record not found |
| -3002 | Invalid business parameters (e.g. customer_id/timezone missing) |
| -3004 | NL IBAN Mod97 validation failed |
| -3035 | IBAN already exists |
| -3036 | Source IP is not in the whitelist |
| -3100 | Token and uid mismatch |
| -1000 | IBAN pool is empty and no explicit iban was provided |
Invalid parameters example:
{
"status": false,
"code": "-3002",
"message": "The given data was invalid.",
"data": {}
}
Invalid IBAN format example:
{
"status": false,
"code": "-3004",
"message": "invalid NL IBAN",
"data": {}
}
4. Special Notes
About the
verify.api.signmiddleware:- Validates that the header
Authorization: Bearer {token}matchesuid; - Checks the IP whitelist;
- Re-computes the signature and compares it;
- Once passed, flattens all business fields inside
dataonto the request top level and injectsiban_api_user_info(account details array).
- Validates that the header
About automatic IBAN allocation:
- If
data.ibanis not provided, the API fetches one row from theiban_generatedpool in a concurrency-safe manner (FOR UPDATE SKIP LOCKED + transaction + conditional UPDATE to ensure different accounts never share the same IBAN); - Once allocated, both
iban.api_account_idandiban_generated.api_account_idare immediately set to the current API account; - The pool lock TTL defaults to 1800 seconds (30 minutes). Stale locks are released by a scheduled job.
- If
About NL IBAN format validation (when explicitly provided):
- The rule is: must start with
NL, and the overall Mod97-10 remainder must be 1; - Current default pattern requires
YABNfollowed by01 + 8 digits(the account part totals 10 digits).
- The rule is: must start with
Callers can use
request_idfor idempotency: we echo it in responses for bilateral correlation.