Skip to main content
Every resource in v3 (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, and l to 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.
Encoding is a pure, stateless, reversible function of the UUID: the same UUID always produces the same readable ID, and two different UUIDs never collide. There’s no database column or backfill involved — the UUID remains the internal primary key, and the readable ID is derived from it on every response. Any ID that fails to decode, or whose prefix names a different resource type than the field expects, is rejected at the validation layer with 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.
The stability contract is the same contract that makes idempotency keys useful: if you persist a resource ID at write time and the network drops the response, that ID will still resolve to the same record on retry.

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 id from 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 quoteId with Idempotency-Key on the trade execution call. quoteId goes in the JSON body, Idempotency-Key goes 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.