Errors

Every non-2xx response uses one envelope: a machine-readable code, a human message, the request id, and a link back to the docs.

Envelope

json
{
  "error": {
    "code": "not_found",
    "message": "No such endpoint: GET /v1/nope",
    "request_id": "8eb9cdc8-65ff-4cdb-af14-ca6221fba79e",
    "docs": "https://delilah-api.jsv21b.workers.dev/docs"
  }
}

Always log request_id — quoting it in a support request lets us find the exact call in our access log. The same id is returned on successful responses in the X-Request-Id header. Rate-limit errors add a few extra fields inside error (limit, window, or used and resets_at).

Error codes

CodeHTTPMeaning
bad_request400A parameter failed validation — a non-integer id, a malformed ISO timestamp, a bad topic slug, or an invalid JSON body
unauthorized401Missing X-API-Key header
invalid_api_key401Key does not match an issued key
revoked_api_key401Key has been revoked
not_found404No such record — or no such endpoint
subscription_inactive409The webhook subscription you addressed is not active
rate_limit_exceeded429Burst limit or monthly cap exceeded — honor Retry-After
subscription_limit429The 25 active-webhook ceiling for this key is reached
internal_error500Unhandled server error — quote the request_id
status_unavailable503/v1/status snapshot temporarily unavailable
coverage_unavailable503/v1/coverage snapshot temporarily unavailable

Notes

  • On 429, wait the number of seconds in Retry-After before retrying. A burst rejection sends Retry-After: 1; a monthly-cap rejection sends the seconds remaining until the period resets. See Rate limits.
  • A 404 on a sub-resource path means the parent record does not exist. An existing record with no rows for that sub-resource returns 200 with an empty data array.
  • 503 applies only to the two snapshot endpoints, which are served from a cached materialised view. Retry in a minute.