Data model
Every Orbit endpoint — REST request, REST response, and webhook delivery — follows the same conventions. This page is the canonical reference for those conventions: the response envelope, identifier shapes, idempotency, pagination, time formats, and webhook event envelopes. Per-endpoint field schemas live in the API reference; this page defines the shared frame those schemas sit inside.Envelope: data and meta
Every successful response returns adata object (or array) plus a meta object. Errors return an error object plus the same meta.
On an error,
error.code is the machine-readable value (stable enough to switch on), and meta.request_id is still present for support triage. The full code catalog is the error codes reference.
Identifier shapes
Every resource id carries a prefix naming its entity type, so an id is self-describing in logs, webhook payloads, and support tickets. Suffixes are lowercase hex (32 characters, 16 random bytes). Ids are unique per environment — no two tenants ever receive the same id, and ids always refer to a single tenant’s resource. Common prefixes:
Treat ids as opaque strings. Prefixes let you tell resource types apart; they carry no semantic content you should parse. The glossary catalogs term-level vocabulary; this table is the id-shape reference.
Idempotency and retries
EveryPOST that creates a resource accepts an Idempotency-Key header. Send one on every creation call.
- Same key + same body → Orbit returns the cached original response. No duplicate message is sent, no duplicate charge is posted.
- Same key + different body →
409 IDEMPOTENCY_KEY_REUSED. Keys are scoped to one operation shape — generate a fresh key per logical send (an order id, a UUID, anything unique per attempt). - Key expired (over 24 hours) → the request is treated as new and may create a second resource.
Idempotency-Key equal to the event id, so your receiver can dedup retries safely. See Webhook event shapes below.
Pagination: cursor, not offset
List endpoints are cursor-paginated. Offset pagination is not offered — offsets drift under concurrent inserts, cursors do not.?cursor=<meta.pagination.cursor> (and optionally &limit=<n>, default 20, maximum 200) to fetch the next page. Stop when has_more is false. Pass cursors verbatim — they are opaque and URL-safe. Implementation detail is in the pagination guide.
The unified Interaction Search surface returns rows ordered by last_activity_at descending with this cursor contract — the dashboard and CSV export share it.
Time formats
All timestamps are ISO-8601 in UTC — response fields, request fields you send, andexpires_at-style deadlines.
- Write: send (
Send) objects withsend_atfields accept an ISO-8601 instant; a future instant schedules the send and returns202, a past instant (or omission) sends immediately. - Read: every timestamp you receive (
created_at,meta.timestamp, messagetimestamp) is UTC with aZsuffix. Convert client-side for display. - Deadlines: fields like
expires_at(verification sessions) state the last valid instant; requests that land after it return a terminal 4xx such as410 EXPIRED_TOKEN.
Webhook event shapes
Webhook deliveries follow a fixed envelope — distinct from the REST envelope above:Related reading
- API overview — base URL, authentication, rate limits, and per-service endpoint groups.
- Error codes — the full
error.codecatalog, including the idempotency errors. - Glossary — product vocabulary.
- Tenant isolation — why ids and data never cross tenant boundaries.