Close a sub-client
Irreversible. Every account under the sub-client must hold a zero balance. On success every IBAN retires; inbound to a retired IBAN is parked by TCB, never credited.
Irreversible. Every account under the sub-client must hold a zero balance. On success every IBAN retires; inbound to a retired IBAN is parked by TCB, never credited.
Authorization
bearer In: header
Path Parameters
The sub-client id.
Header Parameters
Your own key for this request, 1-100 characters. Required: this route takes no body, so the header is the only place to send it. 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.
Act on behalf of one of your sub-clients. The value is that sub-client id, and the request then reads and writes that sub-client's own accounts and registry rows rather than yours. Omit it to act as yourself. A route that does not accept the header refuses it with 400 ON_BEHALF_OF_NOT_ALLOWED_HERE rather than ignoring it — that includes every vault route (deposits, withdrawals, conversions, sub-accounts, positions), the webhook registry, and POST /sub-clients, since a sub-client never has sub-clients of its own. An id that is not one of your sub-clients answers 404 ON_BEHALF_OF_NOT_FOUND; a closed one answers 409 ON_BEHALF_OF_SUB_CLIENT_CLOSED; and a key restricted to a subset of your sub-clients answers 403 ON_BEHALF_OF_NOT_ALLOWED_FOR_KEY for any node outside it.
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/c4f81e2a-9b60-4d37-a512-8e0f3c6b7d95/close" \ -H "Idempotency-Key: string"{ "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"}Append an attestation POST
Your statement, to TCB, that you performed CDD and screening on this customer under your own regulated programme. It is evidence of that work, not what activates the sub-client: activation also requires the mandatory identity data, your screening results and TCB's own screening. An attestation missing a required field, or sent for a sub-client whose mandatory identity data is still outstanding, is refused and nothing is recorded. `text` and `version` must be the wording TCB agreed for your programme, sent verbatim with its version string — a retired or unrecognised version, or text that no longer matches it, is also refused. Append-only: no edit, no delete — a new attestation supersedes a stale one, and the database refuses every UPDATE and DELETE.
Add a currency to a sub-client POST
Creates that currency's MAIN account the same way POST /sub-clients does at creation: it receives on the sub-client's IBAN, and carries local details for its currency where the currency has them. Nothing is active until the sub-client is VERIFIED.