Errors

Every failure is an RFC 9457 problem with a stable machine-readable code. Parse the code; show the detail.

Every non-2xx response from /api/v1 is an application/problem+json body in the same shape:

{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "ttlSeconds must be between 60 (one minute) and 86400 (24 hours), or omitted for a permanent endpoint.",
  "code": "validation_failed",
  "traceId": "00-4085a4896459004c…"
}

Two fields carry the contract:

  • code — stable, machine-readable, never changes meaning within v1. Branch on this.
  • detail — human-readable, may be reworded any time. Show it; don't parse it.

traceId correlates the response with our logs — quote it in a support request and we can see exactly what happened.

Codes

codeTypical statusMeaning
unauthorized401No key, unknown key, or revoked key.
api_access_disabled403Valid key, but the workspace's plan doesn't include API access.
feature_not_in_plan403The operation (e.g. bulk replay) isn't part of the plan.
not_found404The endpoint or request doesn't exist in this workspace — a real id you don't own answers the same as no id at all.
validation_failed400A body field or query parameter is out of bounds; detail says exactly which and what the bounds are.
forwarding_disabled400Replay was asked of an endpoint with forwarding turned off.
rate_limited429Per-key budget spent; honor Retry-After.
request_invalid400The request body couldn't be read at all (malformed JSON, wrong content type).
internal_error500Our fault. The traceId is already in our logs.

Handling pattern

RESP=$(curl -s -w '\n%{http_code}' )
STATUS=$(echo "$RESP" | tail -1)
BODY=$(echo "$RESP" | head --1)

case "$STATUS" in
  2*) ;;                                        # success
  429) sleep "$(echo "$BODY" | jq -r '.detail' | grep -o '[0-9]*')" ;;  # or read Retry-After
  *)  echo "API error: $(echo "$BODY" | jq -r '.code + " — " + .detail')" >&2; exit 1 ;;
esac

Where next?

On this page