Linked Transfers
POST /v1/transfers/linked
Linked transfers execute atomically. All succeed or all fail. There is no partial state.
This is not application-level logic. The atomicity guarantee is enforced by the database engine itself. If any single transfer in the batch would fail (insufficient funds, closed account, same account), none of them execute.
When to use
Fee splitting. A customer pays 10,000. 9,500 goes to the merchant, 500 goes to the fee account. Both must happen or neither happens.
Multi-party settlement. Move funds across three or more accounts in a single atomic operation.
Currency exchange. Debit one ledger and credit another through intermediate accounts, all atomically. (Requires accounts on the same ledger for each leg.)
Request
{
"transfers": [
{
"debit_account_id": "CUSTOMER",
"credit_account_id": "MERCHANT",
"amount": 9500,
"ledger": 1001,
"code": 100
},
{
"debit_account_id": "CUSTOMER",
"credit_account_id": "FEE_ACCOUNT",
"amount": 500,
"ledger": 1001,
"code": 300
}
]
}
Minimum 2 transfers required.
What happens if one fails
Nothing. If the customer does not have 10,000, neither transfer executes. The merchant does not get 9,500 without the fee account getting 500. There is no scenario where money moves partially.
If you need to reverse a linked batch, you must reverse the entire batch. Create a new linked transfer that reverses every leg of the original. You cannot reverse one leg and keep the others.
Response 201
{
"data": {
"tenant_id": "f714f6af-...",
"transfers": [
{
"id": "...",
"debit_account_id": "CUSTOMER",
"credit_account_id": "MERCHANT",
"amount": 9500,
"code": 100,
"status": "posted"
},
{
"id": "...",
"debit_account_id": "CUSTOMER",
"credit_account_id": "FEE_ACCOUNT",
"amount": 500,
"code": 300,
"status": "posted"
}
]
}
}
Headers
Authorization: Bearer qk_live_...
Idempotency-Key: <unique-string>
Content-Type: application/json
Errors
| Code | Type | Meaning |
|---|---|---|
| 422 | insufficient_funds | One of the debit accounts does not have enough balance |
| 422 | linked_minimum | Must include at least 2 transfers |
| 422 | account_closed | One of the accounts is closed |