Skip to main content

Error format

All errors return a consistent JSON structure:
{
  "error": {
    "code": "not_found",
    "message": "Human-readable description of what went wrong."
  }
}

Status codes

CodeNameDescription
400Bad RequestInvalid request body, missing required fields, malformed parameters
401UnauthorizedInvalid, expired, or revoked API key
402Payment RequiredNo credentials provided. Response includes payment_options with x402 and API key signup details
403ForbiddenValid credentials, but insufficient scopes for this operation
404Not FoundResource doesn’t exist or belongs to another tenant
409ConflictDuplicate resource (e.g., duplicate slug)
429Too Many RequestsRate limited. See Retry-After header for when to retry
500Internal Server ErrorSomething broke on our end. Logged and tracked automatically
501Not ImplementedFeature exists in the API surface but isn’t live yet

402 Payment Required

The 402 response is unique — it includes payment options so clients can self-serve:
{
  "error": {
    "code": "payment_required",
    "message": "Authentication required. Provide a Bearer API key or x402 payment."
  },
  "payment_options": {
    "x402": {
      "scheme": "exact",
      "network": "eip155:8453",
      "token": "USDC",
      "description": "Backside.app PIM API access"
    },
    "api_key": {
      "signup_url": "https://backside.app/signup"
    }
  }
}

Rate limiting

When rate limited, the API returns 429 Too Many Requests with standard headers:
HeaderDescription
Retry-AfterSeconds until the limit resets
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the window resets