Skip to main content

Errors

The RedPennon API returns standard HTTP status codes and a predictable JSON shape for failures.

Error response shape

Authentication errors (401) return only the error field:

{ "error": "Invalid or missing API key." }

Governance errors (403, 429, 400 governance) always include a code field for stable programmatic matching:

{
"error": "Rate limit exceeded. Retry after a short delay.",
"code": "rate_limit_exceeded"
}
  • error — human-readable message.
  • code — stable machine identifier; present on governance errors only. Auth (401) responses do not include code.

Branch on code (or status) in SDKs — do not pattern-match on error text.

Governance errors (POST /v1/variables, /v1/variables batch, /v1/events)

StatuscodeMeaning
403organisation_suspendedOrganisation suspended by staff
403organisation_inactiveOrganisation is not on the Free plan and has no active subscription
403monthly_active_users_exceededPlan MAU cap for this calendar month
429rate_limit_exceededPer-organisation rate limit (shared across API workers via Postgres; retry with backoff)
400batch_too_largeToo many keys in a batch evaluate request
400events_batch_too_largeToo many events in one ingest request

When governance returns 403 or 429, the request is rejected before evaluation — use your code default for flags; do not treat these as fail-open value: null responses.

Evaluation endpoints

StatusTypical cause
200Success (including fail-open value: null for unknown keys)
400Invalid JSON, bad user shape, missing keys / events, batch too large
401Missing or invalid X-API-Key
403Governance (see table above)
405Wrong HTTP method
429Rate limit

Code references (POST /v1/code-references)

The code references ingest endpoint authenticates with an organisation API token, not the X-API-Key, so its error shape differs:

StatusTypical cause
200Snapshot accepted ({accepted, matched, unknown_keys})
400Invalid JSON, missing project/branch, malformed repository, non-github provider, bad references entry
401Missing, malformed, unknown, or revoked organisation API token (rpa_…)
402Organisation's plan does not include code references
404Unknown project slug

Health

Endpoint200503
GET /healthYesYes

503 is only used by /health when the database is unreachable.

To disable a cap (local development only), set the corresponding _DISABLED environment variable to true — setting the numeric variable to 0 does not disable enforcement; non-positive values fall back to the built-in default instead.

CapDisable with
EVAL_API_RATE_LIMIT_PER_MINUTEEVAL_API_RATE_LIMIT_DISABLED=true
EVAL_API_MAX_BATCH_KEYSEVAL_API_MAX_BATCH_KEYS_DISABLED=true
EVAL_API_MAX_EVENTS_BATCHEVAL_API_MAX_EVENTS_BATCH_DISABLED=true

Evaluation endpoints fail open for unknown variable keys (200 with value: null and a reason) so SDKs can use code defaults. Governance errors above are not fail-open.

Anonymous evaluation traffic (no user.id or user.email) counts as a single shared MAU slot (anon:unidentified) per organisation per month.

Retry policy
  • 400 and 405 are caller errors. Don't retry — fix the request.
  • 401 is a credential problem. Don't retry — refresh the API key.
  • 403 for organisation_inactive or organisation_suspended — fix billing or contact support; don't retry.
  • 403 for monthly_active_users_exceeded — upgrade plan or wait for next month; returning users already counted this month are not blocked.
  • 429 — retry with jittered backoff.
  • 5xx and connection errors are safe to retry with jittered backoff. Evaluations are read-only, so retries are idempotent for the same user context.