All errors follow a consistent shape:

{
  "error": {
    "code": "not_found",
    "message": "Authorization not found"
  }
}

Validation errors include a fields array:

{
  "error": {
    "code": "validation_error",
    "message": "Invalid request",
    "fields": [
      { "field": "body.expires_at", "message": "expires_at must be in the future" }
    ]
  }
}

Error codes

HTTP StatusCodeDescription
400bad_requestMalformed request
401unauthorizedMissing or invalid API key
402payment_requiredBilling setup, paid tier, or quota/payment gate required
403forbiddenValid key but not permitted
404not_foundResource does not exist
409conflictState conflict (e.g. already revoked)
410goneNonce expired or consumed
422validation_errorRequest body failed validation
500internal_errorUnexpected server error
503service_unavailableService temporarily unavailable

Budget note: creating a budgeted authorization on Free/Starter returns 402 budget_plan_required. Missing estimated_cost_micros on a budgeted authorization, or sending multiple scopes on a budgeted check, returns 422 validation_error. An over-budget action is not an API error; /check returns decision: "deny" with reason: "budget_exceeded" and writes a receipt.

SDK error handling

Python

from allowly import Allowly, AllowlyAPIError

allowly = Allowly(api_key="allowly_l1_s001_2y6r..._k9m3...")

try:
    result = await allowly.check(authorization_id="auth_...", scopes=["x"])
except AllowlyAPIError as e:
    print(e.status)   # 401
    print(e.code)     # "unauthorized"
    print(str(e))     # "Invalid or revoked API key"

TypeScript

import { Allowly, AllowlyAPIError } from "@allowly/sdk";

const allowly = new Allowly({ apiKey: "allowly_l1_s001_2y6r..._k9m3..." });

try {
  const result = await allowly.check({ authorizationId: "auth_...", scopes: ["x"] });
} catch (e) {
  if (e instanceof AllowlyAPIError) {
    console.log(e.status);  // 401
    console.log(e.code);    // "unauthorized"
    console.log(e.message); // "Invalid or revoked API key"
  }
}