Skip to main content

Resource IDs

Every Moda resource has a prefixed wire ID like cvs_01HT9WK8N3M2J4A5Z6P7Q8R9TV. The prefix disambiguates the resource type on sight and prevents cross-resource lookup mistakes.

Prefixes

Encoding: Crockford base32 (no I, L, O, U to avoid visual confusion). Case-insensitive.

The two strictness rules

Body fields — strict (prefixed only)

Bare UUIDs in body fields get rejected. Responses always come back prefixed, so if you store the ID from a response and pass it in later, you’re fine.

Path parameters — tolerant (either form)

Path-parameter tolerance is a convenience for integrators who already hold raw UUIDs from an older system. Always prefer prefixed form in new code.

Why this design

  • Prefixed IDs are self-describing. Pasting one in a log or a PR makes it immediately clear what kind of object it is.
  • Strictness in bodies prevents accidental cross-resource confusion (passing a canvas_id where a brand_kit_id was expected — the server catches it at validation).
  • Tolerance in paths avoids breaking older callers who already hold bare UUIDs.

In responses

Every id field in response bodies is prefixed:
Store the prefixed form for future calls.

Webhook payloads

Webhook events carry a prefixed evt_… id:
Use id (the event ID) as an idempotency key in your webhook handler — it’s stable across retries.

Common wrong guesses

  • Sending a bare UUID in a JSON body. 400 invalid_request. Always use prefixed IDs in bodies.
  • Storing bare UUIDs from older responses. They work in path params today, but storing the prefixed form (from any current response) is safer for future use.
  • Parsing the prefix at the client to dispatch on resource type. Don’t — use the kind field on task envelopes or the response shape. Prefixes are for humans.
  • Assuming upl_ and file_ are interchangeable. upl_ is legacy; current uploads return file_. Don’t mix.

Upstream

docs.moda.app/api/authentication#resource-id-formats