Skip to content

Errors

All error responses share the same shape:

json
{
  "error": {
    "code":    "insufficient_scope",
    "message": "Missing required scope: cases:write.",
    "required_scope": "cases:write"
  }
}

The fields you can rely on:

  • error.code — a stable string. Match on this, not on message.
  • error.message — human-readable; safe to surface to a logged-in admin but don't echo back to an end-user verbatim.
  • Some codes carry extra context fields (required_scope, bucket, errors, etc.).

Status code mapping

HTTPWhen
400The request shape is wrong (bad URL, malformed JSON, oversized body).
401The token is missing, invalid, revoked, or expired.
403The token is fine but the request is not allowed (missing scope, IP not allowed).
404The resource doesn't exist (case id, ticket id, etc.).
409Idempotency-Key reused with a different body.
422Validation failed (per-field; error.errors is keyed by field name).
429Rate-limited. Honour Retry-After.
5xxWe broke. Retry with backoff; we're alerted automatically.

Code catalogue

Authentication

error.codeStatusNotes
missing_token401No Authorization: Bearer … header.
invalid_token401Token doesn't exist, is revoked, or expired. No distinction between these on purpose — don't leak existence to a probing attacker.
https_required400Production endpoint reached over plain HTTP.
not_authenticated401The scope middleware ran without an upstream token bind. Should be unreachable in production.

Authorisation

error.codeStatusNotes
insufficient_scope403Token lacks the required scope. Carries error.required_scope.
ip_not_allowed403Request came from outside the token's IP allowlist.

Rate limiting

error.codeStatusNotes
rate_limited429Hit the per-token bucket. Carries error.bucket (read or write) and Retry-After.

Idempotency

error.codeStatusNotes
idempotency_key_reused409Same Idempotency-Key used with a different request body.
idempotency_key_too_long400Keys must be ≤ 128 characters.

Validation

error.codeStatusNotes
validation_failed422Per-field validation errors. error.errors is keyed by field name with the messages as arrays.
invalid_user_id400A user id path/query parameter is not a Discord snowflake (17–20 digits).
balance_would_be_negative422/economy/adjust would push the balance below zero.

Not found

error.codeStatusNotes
not_found404The resource id is not in this guild (or has been deleted).

Replay header

http
HTTP/1.1 200 OK
Idempotent-Replay: true

A response carrying this header was served from the idempotency cache; the handler did not run again. Treat it as a successful "your previous call already did this" rather than a fresh execution.

Phantom is a product of Hydra Labs. The bot is run as a managed service; you do not need to host it yourself.