Create a sub-client
Creates a sub-client and, atomically, reserves one MAIN account per requested currency. Every one of them receives on the sub-client's IBAN, which carries its own legal name as the payee name, and each also carries local details for its currency where the currency has them. Nothing is live yet: every capability is false and the details are inactive until the sub-client is VERIFIED — it must not be given out, is not entered into verification of payee, and accepts no funds. `identity` and `attestation` are both optional on this call: omitting either leaves the sub-client REQUIREMENTS_DUE, which names what is still outstanding, rather than rejecting the call. Cannot be called under x-on-behalf-of — a sub-client never has sub-clients.
Creates a sub-client and, atomically, reserves one MAIN account per requested currency. Every one of them receives on the sub-client's IBAN, which carries its own legal name as the payee name, and each also carries local details for its currency where the currency has them. Nothing is live yet: every capability is false and the details are inactive until the sub-client is VERIFIED — it must not be given out, is not entered into verification of payee, and accepts no funds. identity and attestation are both optional on this call: omitting either leaves the sub-client REQUIREMENTS_DUE, which names what is still outstanding, rather than rejecting the call. Cannot be called under x-on-behalf-of — a sub-client never has sub-clients.
Authorization
bearer In: header
Header Parameters
Your own key for this request, 1-100 characters. Required, here or as the idempotencyKey body field; sending both is allowed only if they match. Replaying a key returns the first result without executing anything a second time, and sets replayed to true where the response carries that field. Sending the same key with different parameters is refused with 409 IDEMPOTENCY_KEY_REUSED — use a new key for a different request. While the first call is still running, a second call with the same key answers 409 IDEMPOTENT_REQUEST_IN_PROGRESS. A key is remembered for 24 hours from the first call; after that it is forgotten and reusing it starts a new request.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
A new end customer, together with the currencies it should hold a MAIN account in.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/partner/v1/sub-clients" \ -H "Content-Type: application/json" \ -d '{ "attestation": { "cddPerformedAt": "2026-08-28T09:00:00.000Z", "cddStandard": "standard", "idempotencyKey": "acme-2026-09-02-0001", "pepStatus": "none", "riskRating": "low", "screeningResult": "clear", "text": "We have performed customer due diligence and screening on this customer under our agreed reliance programme.", "verificationMethod": "documentary", "verificationResult": "verified", "verifierRef": "acme-case-88214", "version": "reliance-2026-09" }, "currencies": [ "EUR" ], "externalRef": "acme:cust-04231", "idempotencyKey": "acme-2026-09-02-0001", "identity": { "address": { "city": "Manama", "country": "BH", "line1": "14 Road 2825" }, "dateOfBirth": "1988-04-17", "firstName": "Fatima", "lastName": "Al-Khalifa", "nationality": "BH" }, "kind": "person", "legalName": "Fatima Al-Khalifa", "metadata": { "onboardedBy": "app", "segment": "retail" } }'{ "data": { "accounts": [ { "accountId": "7e2a0c53-4d81-49b6-8f37-1a5c9e0b2d74", "balance": { "available": "1000.00", "reserved": "0.00", "total": "1000.00" }, "capabilities": { "holdCrypto": true, "holdSavings": false, "receive": true, "sendCrypto": true, "sendExternal": false, "sendInternal": true }, "createdAt": "2026-08-14T08:42:11.000Z", "currency": "EUR", "disclosure": { "items": [ "ENVIRONMENT_IS_TESTNET: The environment is a testnet (Arbitrum Sepolia). No mainnet deployment exists.", "YIELD_IS_SIMULATED: The vault rate is set administratively and the interest it produces is minted as fresh underlying, not earned. It does not represent a return generated by deployed capital.", "FIAT_RAILS_ARE_MOCKED: No real fiat movement occurs. Balances are ledger entries against a sandbox provider.", "CONVERSION_RATES_ARE_MARKET_QUOTED_OR_REFUSED: A conversion is priced only by an external venue that quotes independently of TCB. When no such venue can price the pair, the conversion is refused rather than priced from an internal table. Read rate.pricingModel on every conversion: MARKET is a venue quote; any other value is not a market rate and must not be presented as one.", "CONTRACTS_ARE_UNAUDITED: No audit has been performed. Mainnet is gated on a two-firm audit that has not been commissioned.", "CUSTODY_IS_TCB_SUBACCOUNT: Everything held for the client — its vault shares, and the tcbUSD it holds between the steps of the tokenised deposit chain — is held in TCB custody, in the one TCB wallet assigned to the client. The client holds no keys and moves those tokens only through this API; each sub-account's shares and tcbUSD are book entries against what that wallet holds.", "INTEGRATION_AGREEMENT_ONLY: Fees as published on the rate card; no yield share, no return commitment." ], "summary": "This is a pilot integration on a testnet. Nothing in this system earns anything: the yield is simulated and the fiat rails are mocked.", "version": "2026-10-27" }, "externalRef": "acme:payroll-eur", "iban": { "active": false, "bic": "TCBKBHBMXXX", "holderName": "Fatima Al-Khalifa", "iban": "BH29TCBK00001234567890" }, "label": "Payroll reserve", "localRails": [ { "active": false, "bankAddress": "Wiesenstrasse 17, 8952 Schlieren, Switzerland", "bankName": "InCore Bank AG", "beneficiaryName": "Fatima Al-Khalifa", "bic": "INCOCHZZ", "currency": "EUR", "iban": "CH0508799123456789012", "paymentReference": "TCB-7K2M9QXA", "rail": "SEPA / SEPA Instant" } ], "ownerId": "c4f81e2a-9b60-4d37-a512-8e0f3c6b7d95", "ownerType": "SUB_CLIENT", "role": "MAIN", "status": "ACTIVE" } ], "caps": { "USD": { "daily": "50000", "perTransfer": "10000" } }, "country": "BH", "createdAt": "2026-08-14T08:42:11.000Z", "cryptoAccounts": [ { "accountId": "3b9e2f71-0c4d-4a58-9e16-7d2c5a8f1b40", "address": "0x5c1f0a2b3d4e5f60718293a4b5c6d7e8f9012345", "balances": [ { "asset": "USDC", "balance": "250.5" } ], "chain": "ARBITRUM", "status": "ACTIVE" } ], "disclosure": { "items": [ "ENVIRONMENT_IS_TESTNET: The environment is a testnet (Arbitrum Sepolia). No mainnet deployment exists.", "YIELD_IS_SIMULATED: The vault rate is set administratively and the interest it produces is minted as fresh underlying, not earned. It does not represent a return generated by deployed capital.", "FIAT_RAILS_ARE_MOCKED: No real fiat movement occurs. Balances are ledger entries against a sandbox provider.", "CONVERSION_RATES_ARE_MARKET_QUOTED_OR_REFUSED: A conversion is priced only by an external venue that quotes independently of TCB. When no such venue can price the pair, the conversion is refused rather than priced from an internal table. Read rate.pricingModel on every conversion: MARKET is a venue quote; any other value is not a market rate and must not be presented as one.", "CONTRACTS_ARE_UNAUDITED: No audit has been performed. Mainnet is gated on a two-firm audit that has not been commissioned.", "CUSTODY_IS_TCB_SUBACCOUNT: Everything held for the client — its vault shares, and the tcbUSD it holds between the steps of the tokenised deposit chain — is held in TCB custody, in the one TCB wallet assigned to the client. The client holds no keys and moves those tokens only through this API; each sub-account's shares and tcbUSD are book entries against what that wallet holds.", "INTEGRATION_AGREEMENT_ONLY: Fees as published on the rate card; no yield share, no return commitment." ], "summary": "This is a pilot integration on a testnet. Nothing in this system earns anything: the yield is simulated and the fiat rails are mocked.", "version": "2026-10-27" }, "externalRef": "acme:cust-04231", "kind": "person", "lastActivityAt": "2026-09-20T14:12:00.000Z", "legalName": "Fatima Al-Khalifa", "status": "ACTIVE", "subClientId": "c4f81e2a-9b60-4d37-a512-8e0f3c6b7d95", "totalHeldUsd": "1250.00", "updatedAt": "2026-08-28T09:00:00.000Z", "verification": { "attestedAt": "2026-08-28T09:00:00.000Z", "capabilities": { "holdCrypto": true, "holdSavings": false, "receive": true, "sendCrypto": true, "sendExternal": false, "sendInternal": true }, "level": "RELIANCE", "requirements": { "currentlyDue": [ "identity.person.dateOfBirth", "attestation", "screening" ], "disabledReason": null, "eventuallyDue": [], "pastDue": [] }, "status": "VERIFIED", "verifiedAt": "2026-08-28T09:00:00.000Z" } }, "success": true, "timestamp": "2026-09-02T10:15:30.000Z"}List your sub-clients GET
Registry rows, newest first, each carrying its own `totalHeldUsd` and `lastActivityAt` (#109 MR B). Money held for a sub-client is money you ADMINISTER — it is never part of your own balances, and no aggregate ACROSS sub-clients is returned here.
Fetch one sub-client by id GET
One of your end customers. Each sub-client holds its own account with TCB, in its own name; you collect the identity information, TCB accepts it, and you instruct on the sub-client's behalf. Returned: its identity handles, where it stands in verification, what it may do today, its accounts and the transfer ceilings you set on it. An id outside your tree answers 404 rather than 403, so an id cannot be probed for existence.