Skip to content

Errors

Every error response uses the same envelope so clients can implement a single parser.

{
    "error": {
        "code": "invalid_request",
        "message_key": "errors.common.invalid_request",
        "message": "Request validation failed.",
        "details": { ... },
        "request_id": "019e32b5-..."
    }
}
Field Type Purpose
code string Stable, machine-readable identifier. Safe to switch on.
message_key string i18n key. Translate on the client; never display the raw value.
message string Plain-English fallback. Useful for logs, not for end users.
details object | null Error-specific structured payload. Schema documented per error.
request_id string | null Mirrors the X-Request-Id header for correlation with server logs / traces.

Error catalog

error.code is stable; branch on it, not on message. Codes below are taken from the source of the API. Endpoint pages list the codes specific to each route.

Authentication and access

HTTP code When
401 unauthorized Missing, malformed, expired or revoked credential. details.reason says which.
401 no_principal The route needs a caller and none was authenticated.
403 missing_scope The credential lacks the scope the route needs. details.required names it.
403 admin_scope_forbidden A non-admin tried to create a key with the admin scope.
403 plan_feature_unavailable The endpoint uses an LLM and your plan has none (Free). details.plan, details.feature. See Paid (LLM) endpoints.
403 plan_not_available Switching to a plan that is not self-service.
403 api_key_limit_reached Your plan's active-key limit is reached. details.plan, details.limit. Revoke a key first.

Request problems

HTTP code When
422 invalid_request Body or query failed validation. details.errors[] has the field breakdown.
422 confirmation_required DELETE /v1/tenant/data without the exact confirmation phrase.
422 invalid_date_range, invalid_range, range_too_long, range_too_large, invalid_window Range bounds reversed, missing a timezone, or longer than the route allows.
422 invalid_datetime_timezone, naive_datetime, at_must_be_timezone_aware, event_date_must_be_timezone_aware, sunrise_must_be_timezone_aware A datetime without a timezone offset.
422 unsupported_astrology_system A system-specific route got a chart of the other system.
422 unsupported_house_system house_system is not supported by the route.
422 duplicate_relationship_charts Both sides of a relationship request are the same chart.
422 invalid_return_location Solar/lunar return relocation with only one coordinate.
422 invalid_plan_tier, invalid_scope Unknown plan tier or key scope.
422 unknown_planet, unknown_theme, house_number_out_of_range, unsupported_muhurta_activity_type A path or body value outside the allowed set.
422 rectification_grid_input_invalid The rectification grid request does not describe a valid window.
422 chart_missing_moon, moon_not_in_chart, missing_ascendant_or_moon The chart lacks a body the calculation needs.
422 <technique>_failed (e.g. panchanga_failed, muhurta_failed, varna_profile_failed, theo_house_strength_failed, vaishnava_calendar_failed) The calculation could not be done for these inputs (for example no sunrise at an extreme latitude). The message says why.
501 not_implemented The route exists but the feature is not available yet.

Not found and conflicts

HTTP code When
404 chart_not_found Chart not found, or owned by another account.
404 report_not_found, compatibility_report_not_found, interpretation_not_found, feedback_not_found, api_key_not_found, tenant_not_found That object is not in your account.
404 http_error Some routes answer a missing object with this generic code and a message naming it (for example an unknown chart on /profile/varna or /compatibility/pair-facts, or an unknown statement_id on POST /v1/feedback).
409 idempotency_conflict Idempotency-Key reused with a different body.

Limits

HTTP code When
429 rate_limited Burst bucket empty. Respect Retry-After.
429 too_many_requests Daily or monthly quota used up (details.reason).
429 llm_budget_exceeded Paid plan: hourly LLM spend cap reached.
429 llm_tier_rate_limited Too many LLM requests for one quality tier.
429 demo_rate_limit_exceeded, anonymous_auth_rate_limit_exceeded Too many anonymous demo or sign-in attempts from one address.

Server and providers

HTTP code When
500 internal_error Unexpected failure. Reported automatically; include request_id if you contact us.
503 llm_all_providers_failed, llm_timeout, llm_unavailable, llm_rate_limited The LLM provider failed. Safe to retry later.
503 gazetteer_unavailable The place database is unavailable; let the user enter coordinates.

Correlation IDs

Every response — error or success — echoes X-Request-Id. Pass that header in your support tickets; server logs and OTel traces are keyed on it.

If the client provides X-Request-Id on the inbound request the server honours that value end-to-end. Otherwise a fresh UUIDv7 is generated.

Idempotency

Mutating endpoints accept an optional Idempotency-Key header. The first request with a given key is processed and its response cached; subsequent requests with the same key return the cached response (HTTP status included).

If a request with the same Idempotency-Key carries a different body, the server returns HTTP 409 idempotency_conflict rather than silently overwriting. Keys live for 24 hours.

Use idempotency for any client-driven retry path — most notably POST /v1/reports and POST /v1/interpretations.