Aller au contenu

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 (validation above) is the code. There is no top-level code field; parse it from type.

  • 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_case on 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 on 422 validation responses. One entry per offending field with field (JSON path), code (machine-readable — e.g. email_invalid, client_not_found, min_length, duplicate_entry_id), and message.

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.

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.

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.