API conventions
Every versioned developer endpoint (/v1/*) follows this contract. Module pages only
document behavior that differs from these defaults.
Naming and types
Requests and responses deliberately use different casing:
Common scalar types are described consistently throughout these docs:
Optional fields may be omitted from a request. Nullable response fields are present with
null when the value is known to be absent. Do not send an empty string in place of
null.
Success responses
Single-resource and action responses use:
{
"message": "Contact created",
"data": {
"id": "6c68ea57-8a2e-44d1-b42f-1ab3b5241e1d"
}
}Collection responses place the array in data. Paginated collections also include
meta. An action with no resource to return may omit data.
Error responses
All /v1/* errors use the same machine-readable envelope:
{
"error": "validation_error",
"message": "The customer_phone field must be defined",
"details": [
{
"field": "customer_phone",
"message": "The customer_phone field must be defined"
}
]
}HTTP statuses
Resource lookups are business-scoped. A resource belonging to another business returns
404, not 403, so its existence is not disclosed.
Pagination
Paginated endpoints accept page and limit. Defaults and maximum values are listed on
the endpoint when they differ by module.
GET /v1/vox/calls?page=2&limit=20{
"message": "Vox calls retrieved",
"data": [],
"meta": {
"total": 137,
"page": 2,
"perPage": 20,
"totalPages": 7,
"hasMore": true
}
}Idempotency
Send an Idempotency-Key header on resource-creating POST requests. Use a UUID or
another unique value for each logical operation and reuse it only when retrying that same
operation.
Idempotency-Key: 9b2e1c7a-1f3d-4c2a-b8e1-7d6f5a4c3b2a- Same key and same request body: the original response is replayed with
Idempotency-Replayed: true. - Same key and different body:
409 idempotency_key_reused. - Same key while the original request is still running:
409 request_in_progress. - Keys are retained for 24 hours.
Some older create endpoints also accept idempotency_key in the body. Prefer the header;
it is the canonical mechanism and works consistently across modules.
Rate limits and retries
Developer API keys receive 120 requests per minute per key. A 429 response includes a
Retry-After header in seconds and the same value in meta.retryAfter when available.
Retry only requests that are safe to repeat:
- Retry
429and transient5xxresponses with exponential backoff and jitter. - Honor
Retry-Afterwhen present. - Retry writes only when they carry an
Idempotency-Key. - Do not automatically retry other
4xxresponses.
Timeouts have an unknown outcome. Treat them like transient failures: retry an idempotent request with the same key instead of creating a new operation.
Compatibility
The major version is part of the path. Additive changes - new optional fields, new endpoints,
and new event types - may ship within v1. Breaking field removals, type changes, or semantic
changes require a new major version. Clients should ignore response fields they do not use.