Ids and correlation
Every v2 resource exposes an id, and that same value both re-fetches it and locates it
in the ledger. This page is the whole contract: what id each resource returns, and how to
hop between them.
The rule, in one line
A withdrawal's, deposit's or fill's
idis exactly the value its ledger entry publishes assource.id.
Which is why you never scan the ledger looking for something — you filter by it.
Resources and their ids
| Resource | id | Re-fetch it with |
|---|---|---|
| Withdrawal | withdrawal id | GET /v2/withdrawals/{id} |
| Deposit | deposit id | GET /v2/deposits/{id} |
| Order | order id (your client order id) | GET /v2/orders/{id} |
| Fill | fill id | GET /v2/fills?orderId=… |
| Ledger entry | entry id | GET /v2/ledger/{id} |
The ledger points back
Every GET /v2/ledger entry carries a source object naming what caused it:
{
"id": "lm_998877",
"source": { "type": "withdrawal", "id": "wd_123" },
"type": "WITHDRAWAL",
"subType": "EXTERNAL_CRYPTO",
"assetSymbol": "USDT",
"amount": "150",
"fee": "0.5",
"total": "150.5",
"balance": "849.5",
"createdAt": "2026-07-09T14:11:05.501Z"
}
source.type is one of withdrawal, deposit, fill or other, and source.id is that
resource's id. It is the same pattern as Stripe's balance_transaction.source.
The hops you will actually make
From a withdrawal or deposit to its ledger entries
GET /v2/ledger?assetSymbol=USDT&sourceId=wd_123
One call. sourceId filters on the same value the resource publishes as its id.
From an order to every entry it produced
An order is completed by 1..N fills, and each fill books ledger entries. Rather than
chaining requests, the orderId filter resolves the whole chain for you:
GET /v2/ledger?assetSymbol=CLP&orderId=clord_01H…
A conversion moves two assets (say BTC and CLP), and assetSymbol is required on the
ledger: it selects which leg you are looking at. To see both, make one call per asset.
From an order to its fills
GET /v2/orders/{id}/fills # nested
GET /v2/fills?orderId={id} # equivalent, filtering the global collection
Both return the same resource. Both exist because Coinbase and Binance both have them and different clients reach for different ones. Both are cursor-paginated.
From a fill back to its order
A fill carries orderId, and also embeds the order's cumulative state so you do not have
to re-read the order after every execution:
{
"id": "1096473",
"orderId": "clord_01H…",
"sequence": 2,
"side": "BUY",
"market": "BTC-CLP",
"baseAmount": "0.004",
"quoteAmount": "260000.00",
"rate": "65000000.00",
"multiplier": "1",
"onCredit": true,
"executedAt": "2026-07-09T14:07:11.000Z",
"order": {
"status": "PARTIALLY_FILLED",
"filledBaseAmount": "0.008",
"filledQuoteAmount": "520000.00"
}
}
sequence is the fill's position within its order, starting at 1.
Orders and fills
An order is what you create by confirming a quote. A fill is each execution against it.
- A normal conversion → exactly one fill.
- An on-credit order (
onCredit: true) → several fills, as the debt is paid down.
That is why filledBaseAmount can sit below baseAmount for a while, and why the
fill.created webhook can arrive more than once for the same orderId.
Amount conventions
| Convention | What it means |
|---|---|
| Positive magnitudes | amount, fee and total are always positive on every resource. Direction comes from the resource type or the entry's type, never from the sign. |
balance IS signed | It is a state (the balance after the entry), not a movement, so it is not converted to a magnitude. |
| UPPERCASE | status, type, subType and side are always uppercase: FILLED, WITHDRAWAL, EXTERNAL_CRYPTO, BUY. |
| Decimals as strings | Amounts travel as strings so no precision is lost. Parse them with a decimal type, never a float. |