v2 is not being shut off on any fixed date announced here — v3 is additive. Migrate resource by resource, at your own pace, using the ID-mapping tool below to keep records correlated across both APIs during the transition.
IDs: opaque prefixed strings, not raw UUIDs
Every v3 resource is identified by an opaque, prefixed public ID instead of a raw UUID — e.g. a user isusr_a1B2c3D4e5F6g7H8i9J0k, an offramp is offramp_a1B2c3D4e5F6g7H8i9J0k. The prefix tells you what kind of resource you’re looking at just from the string.
Map v2 IDs to v3 IDs
GET /v3/id-mappings takes a batch of { v2Id, resourceType } pairs and returns the corresponding v3 ID for each one you own. Up to 1,000 IDs per call.
Request
mapped: false means either the ID doesn’t belong to your profile, doesn’t exist, or is for a resource type this endpoint doesn’t support mapping for yet — it’s not an error, so a batch with some unmapped entries still returns 200.
Supported resourceType values today:
Pagination: one envelope for every list endpoint
v2’s list endpoints were inconsistent — some returned{ count, users }, others { count, wallets, nextCursor }, with cursors that were sometimes an opaque value and sometimes just a raw timestamp. Every v3 list endpoint uses the same shape:
startingAfter / endingBefore query params, both set to a resource ID (not a timestamp or offset) — startCursor and endCursor are just the first/last resource ID in the page you got back, not separate opaque tokens.
Errors: a single typed shape
v2’s error body varied by endpoint and generally looked like{ code, error, errorDetails }, with error being a loose string constant. Every v3 error is:
type is a stable machine-readable error code (safe to switch on), message is human-readable, and fields (when present) points at exactly which request field(s) caused the error — useful for surfacing per-field validation errors in a UI without string-matching message.
Idempotency: a real header, not a body field
v2 had no general request-idempotency mechanism — a couple of endpoints (like ToS link generation) took an ad hocidempotencyKey body field, but most didn’t support safe retries at all. Every v3 endpoint that creates or mutates something accepts a standard Idempotency-Key header: