2xx status code and a JSON body with a machine-readable error code, a human-readable message, and the numeric status:
Authentication failures raised before your request reaches the application (at the gateway authorizer) return a bare body without an
error field — { "message": "Unauthorized" } for 401 (no API key) or { "message": "Forbidden" } for 403 (a present-but-invalid key, or a bad/missing bearer token alongside a key). Always branch on the HTTP status code, not only on the body shape.Status codes
Response body examples
Concrete examples of each error response body:Business rules that can block a request
Beyond authentication and scopes, several rules are enforced before a write reaches Daysync’s services:Subscription requirement (402)
Write operations against an organization that has no active subscription are rejected with 402 SUBSCRIPTION_REQUIRED. Organizations flagged as unlimited-free, trial, or beta are exempt. This applies to writes where the organization is identified by the request — in practice, tour creation (POST /v1/tours).
Deleted tours (404)
Any request that references a tour which has been soft-deleted returns 404 TOUR_NOT_FOUND — for both reads of its children and writes against it.
Endpoints requiring several scopes (403)
GET /v1/tours/{tourId}/data returns data from six resources, so it requires the read scope for all of them. A partial grant is rejected with 403 INSUFFICIENT_SCOPE, and the message names exactly which scopes are missing:
Direct messages are not exposed (404)
The chat endpoints cover channels and group chats only. Calling one with a 1:1 direct message conversation or a message inside one returns 404 NOT_FOUND:
404 rather than 403 deliberately — the response does not confirm whether the conversation exists. DMs are also filtered out of every chat list and search, so a valid integration should never encounter this. See Chat.
Input validation (400)
Tour create/edit requests are validated up front:
namemust not be empty and must be ≤ 500 characters,end_datemust not be beforestart_date,timeZonemust be a valid IANA time zone (e.g.Australia/Sydney).
400 with a descriptive message.
Error messages are sanitized
Internal errors (database constraints, SQL details, internal paths) are never returned verbatim. Such cases are collapsed to a generic message and typically a409. Build error handling around the status and error code rather than parsing message text.
Handling tips
- Treat
401as “fix your credentials/token” and403as “you are authenticated but not permitted” — they require different responses (re-auth vs. request more scopes). - On
402, surface a subscription/billing prompt to the user; retrying will not help. - On
5xx, retry with backoff; these are transient or upstream.

