Quote, Trade, Deposit, Withdrawal, WithdrawalAccount) carries an id that the server assigns at creation, plus an object field naming the resource type. IDs are readable: a lowercase 3-to-5-letter prefix identifies the resource type, followed by a Base58 encoding of the underlying 128-bit UUID. Two fields in v3 reference these IDs across resources: quoteId on a trade points at a Quote.id, and withdrawalAccountId on a withdrawal points at a WithdrawalAccount.id.
v3 emits readable IDs on every response. Bare UUIDs never appear in a v3
response body — the UUID stays the internal primary key; the readable ID is
the public identifier. For backward compatibility, v3 accepts either a
readable ID or a bare UUID v4 wherever an ID is expected on input (path
parameters, query parameters, and request-body foreign keys) — both decode to
the same underlying record. New integrations should use the readable form
returned by the API.
Format
<prefix>_<base58(uuid)> — a lowercase 3-to-5-letter type prefix, an underscore, and the Base58 encoding of the resource’s 128-bit UUID.
Pair and Balance have no resource UUID — a pair is identified by its (buyCurrency, sellCurrency) combination, and a balance by currency, not by an id field.
- The Base58 alphabet excludes
0,O,I, andlto avoid visual ambiguity:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz. - The encoded body is at most 22 characters and is not a fixed length — 21–22 characters for a typical random UUID, shorter only for near-zero values (the nil UUID encodes to 16 characters).
- Regex pre-filter:
^[a-z]{3,5}_[1-9A-HJ-NP-Za-km-z]{1,22}$. This is a loose shape check; the authoritative validation is a successful decode back to exactly 16 bytes. A value that matches the regex but doesn’t decode to 16 bytes is rejected the same as a malformed ID. - Base58 is case-sensitive. There is no case normalization — a mis-cased but otherwise well-formed ID decodes to a different value (or fails to decode) and is rejected.
400 VALIDATION_QUERY_FAILED (query and body) or 400 VALIDATION_PATH_FAILED (path parameters).
Stability
- IDs are permanent. Once issued, the underlying UUID never changes and never gets reused, so its readable encoding doesn’t either.
- Safe to store as foreign keys in your database. Index the readable ID, the underlying UUID, or both, depending on what your queries need.
- Safe to log in audit trails. IDs carry no PII — the prefix reveals only the resource type, and the body is an opaque, lossless encoding of the UUID.
- Safe to share in support tickets and idempotency-key collision reports.
Cross-resource references
Some fields are foreign keys pointing at IDs on other resources. The table below lists every such reference in v3:
Anything else that looks like an ID (a transaction hash, a currency code) is not a foreign key into another v3 resource.
ID vs Idempotency-Key
Two ID-shaped fields in v3 serve different purposes:
The two are complementary: you generate an idempotency key before the request, the server returns a resource ID in the response, and you persist both alongside each other. The idempotency key lets you safely retry the write; the resource ID lets you look up the result for the rest of time. See Idempotency → Crash recovery for the persist-both pattern.
Common mistakes
- Treating IDs as transient. They aren’t. Persist them.
- Parsing or decoding the readable ID yourself. The prefix tells you the resource type; don’t try to derive anything else from the body. Treat the body as an opaque string, even though it happens to be reversible server-side.
- Reading the
idfrom your own DB row instead of the API response on a write. If you assigned an identifier locally and sent it as the request body, that’s not the resource ID. The server generates its own. Always trust the response, not your draft. - Confusing
quoteIdwithIdempotency-Keyon the trade execution call.quoteIdgoes in the JSON body,Idempotency-Keygoes in the header. They’re unrelated. - Storing only the readable ID and losing the ability to index efficiently. Both the readable ID and its underlying UUID identify the same record — store whichever shape fits your schema, or both.
- Assuming a hardcoded body length. The encoded body is at most 22 characters but isn’t fixed-width. Validate by prefix and successful decode, not by string length.
What’s next
Idempotency
Client-generated keys vs server-generated IDs.
Pagination
Opaque cursors — distinct from resource IDs. Pass them back verbatim.
Errors
When you’ll see
*_NOT_FOUND and how to handle it.