Errors
Every error response uses RFC 7807
Problem Details for HTTP APIs, encoded as application/problem+json.
{ "type": "https://docs.tickr.coderise.cloud/errors/validation", "title": "Validation failed", "status": 422, "detail": "Validation failed", "correlationId": "01HXYZ....", "errors": [ { "field": "email", "code": "email_invalid", "message": "..." } ]}-
type— stable URI and the source of truth for the machine-readable error code. The trailing path segment (validationabove) is the code. There is no top-levelcodefield; parse it fromtype. -
title— short, human-readable HTTP reason phrase. -
detail— the error message (often the same as the code for top-level errors; field-level messages are more descriptive). -
correlationId— include this when reporting a problem to the support team. It links to the server logs.This single property uses camelCase, unlike the rest of the API, which uses
snake_caseon the wire. The reason is convention: RFC 7807 Problem Details is traditionally serialised in camelCase, and our Problem Details factory follows that convention rather than overriding it for one outlier field. -
errors[]— present on422 validationresponses. One entry per offending field withfield(JSON path),code(machine-readable — e.g.email_invalid,client_not_found,min_length,duplicate_entry_id), andmessage.
Common codes
Section titled “Common codes”The top-level code is the trailing segment of type
(https://docs.tickr.coderise.cloud/errors/<code>). Field-level codes live in
errors[].code on 422 responses.
| HTTP | code |
Meaning |
|---|---|---|
| 401 | unauthorized |
API key missing, malformed, revoked, or session expired. |
| 403 | forbidden |
Authenticated but not authorized for this resource. |
| 403 | forbidden (analyst_read_only) |
Analyst role attempted a mutation (carried in detail). |
| 403 | forbidden (not_project_member) |
Workspace User without project membership. |
| 403 | forbidden (workspace_mismatch) |
Cross-workspace reference rejected. |
| 404 | not_found |
Resource does not exist or is not visible to you. |
| 409 | conflict |
Server-side state conflict (e.g. concurrent edit). |
| 413 | payload_too_large |
Request body exceeds the documented size cap. |
| 422 | validation |
Input validation failed; see errors[] for per-field codes. |
| 422 | validation (duplicate_entry_id) |
Same entry id sent more than once in one bulk batch — see below. |
| 429 | rate_limited |
See Rate limits. |
| 503 | calendar_disabled |
The Microsoft Calendar feature is not enabled on this instance. |
| 503 | calendar_token_revoked |
The user’s Microsoft refresh token was revoked. Reconnect required. |
| 503 | calendar_provider_unavailable |
Transient error reaching Microsoft Graph. Retry later. |
| 429 | calendar_provider_throttled |
Microsoft Graph throttled the call. See Retry-After header. |
| 400 | pkce_state_not_found |
OAuth state expired or replayed. Restart the connection flow. |
| 400 | microsoft_oauth_error |
Microsoft rejected the OAuth exchange (e.g. user cancelled consent). |
Sub-codes shown in parentheses (analyst_read_only, not_project_member,
workspace_mismatch) are not separate top-level codes — they are carried
in the detail field of a forbidden response. Match on the pair when
you need to distinguish them.
This list is not exhaustive — the full catalogue lives in the source code
(ErrorCodes).
New codes are added as new features ship; existing codes are never removed
without a major version bump.
Duplicate ids in a bulk batch
Section titled “Duplicate ids in a bulk batch”POST /api/v1/entries:bulk rejects the whole batch with 422 when the
same id appears more than once. Two instructions about the same entry have
no correct outcome to guess, and applying them in order used to resolve the
billable rate from stale state — a wrong amount, with no error raised.
Every offending row is reported, keyed by JSON path, so you can fix the exact lines rather than parse a message:
{ "type": "https://docs.tickr.coderise.cloud/errors/validation", "status": 422, "errors": [ { "field": "items[0].id", "code": "duplicate_entry_id", "message": "Duplicate entry id …" }, { "field": "items[2].id", "code": "duplicate_entry_id", "message": "Duplicate entry id …" } ]}Nothing is written when a batch is rejected — it is all-or-nothing.
404 is intentional
Section titled “404 is intentional”Tickr returns 404 not_found instead of 403 forbidden when the caller is
authenticated but the resource is in a different workspace, or in a private
project they don’t belong to. This is on purpose — it prevents leaking
existence via probe requests. If you genuinely cannot see a resource you
expected to, double-check the API key’s workspace and your project membership.