Kaal Jyoti APIGet a key

Errors

Every failure has the same shape, and it always names a code and links back to this page:

{
  "status": "error",
  "error": {
    "code": "validation_error",
    "message": "give either timezone or utc_offset, not both",
    "field": "birth.utc_offset",
    "docs": "https://kaaljyoti.com/api/docs/errors#validation_error"
  }
}

Branch on code, never on message. Messages are written for people and get clearer over time; codes are the contract and do not change. field appears when the API knows which part of the body was wrong, as a dotted path.

None of these costs a credit. The credits are reserved before the calculation and given back the moment a request is refused, so only answers are charged for — see Credits per API. Refusals do appear in your usage as errors, because your error rate is worth seeing.

Every response, successful or not, carries X-KJ-Request-Id. Quote it when you write to us: it lets us find the exact request without you having to tell us what was in it — we do not log bodies.

At a glance

CodeHTTPMeans
validation_error400The request body is not one this endpoint accepts.
invalid_key401No key, or not a key we know.
key_revoked401That key existed and was revoked.
quota_exceeded402This period's credits are used up, or not enough are left for this request.
pdf_quota_exceeded402This period's PDFs are used up.
forbidden_origin403A publishable key, used from an origin it does not list.
plan_required403This endpoint is not open to this key, or it is a PDF on the Free plan.
not_found404No such path.
not_computable422The request was valid, but no answer exists for it.
rate_limited429Too fast.
engine_error500Our fault.
service_disabled503The API is deliberately turned off.

validation_error — HTTP 400

The request body is not one this endpoint accepts.

A missing or misspelled field (bodies are strict, so an unknown key is an error rather than a silent default), a date that is not a real calendar date, a year outside 1800–2400, a latitude beyond ±89.9°, both timezone and utc_offset given at once, a window longer than 366 days or with to before from, an unknown ayanamsa slug, or a body over 8 KB. The response names the offending path in error.field.

Costs no credits.

invalid_key — HTTP 401

No key, or not a key we know.

The same answer is given for a missing key and a wrong one, on purpose. It is also what you get when a secret key (kj_live_… or kj_test_…) is sent in the query string: only publishable keys may travel in a URL.

Costs no credits.

key_revoked — HTTP 401

That key existed and was revoked.

Create a new one in the dashboard. A revoked key can keep answering for up to a minute — the gateway caches a key record for sixty seconds — so revoke before you finish a rotation, not after.

Costs no credits.

quota_exceeded — HTTP 402

This period's credits are used up, or not enough are left for this request.

The account has spent its monthly credits — the plan, anything added to the account, and any credit packs it can draw on — or has fewer left than this request costs; the message says which, and a cheaper request may still go through. It clears when the month turns, when you buy a credit pack, or immediately on an upgrade. Nothing is throttled silently and nothing extra is billed without you choosing it. A publishable key has two more causes: it has reached its own daily credit cap (the message says so; it clears at 00:00 UTC, and the owner can change the cap on the Sites page), or the period's credits are gone and the key is not allowed to draw on credit packs.

Costs no credits.

pdf_quota_exceeded — HTTP 402

This period's PDFs are used up.

The account has made every PDF its plan includes this period (POST /v1/pdf/*: Starter 50, Growth 200, Scale 500, Enterprise 2,500 or as the contract says). It clears on the account's billing day; a credit pack does not raise it. The same PDF asked for again within 24 hours still comes back — a cached PDF uses no allowance — and every other route keeps working: this is the PDF count, not the credits.

Costs no credits.

forbidden_origin — HTTP 403

A publishable key, used from an origin it does not list.

Add the origin to the key in the dashboard. The match is exact — scheme and port are part of an origin — and * is not a wildcard. This is also the code the edge returns for a request that did not come through it.

Costs no credits.

plan_required — HTTP 403

This endpoint is not open to this key, or it is a PDF on the Free plan.

No plan gates an API, with one exception: a PDF (/v1/pdf/*) on the Free plan — every paid plan has them. The other causes are per-request branding on a PDF below Enterprise, and a publishable key asking for something publishable keys never get: /v1/transit/scan, /v1/match/batch or a PDF on any plan, or embed_font: true on a chart. The key's kind is checked before the plan.

Costs no credits.

not_found — HTTP 404

No such path.

Check the version prefix — every endpoint lives under /v1 — and the reference list name on GET /v1/reference/{list}.

Costs no credits.

not_computable — HTTP 422

The request was valid, but no answer exists for it.

The arithmetic has no result for these inputs rather than a wrong one: a sunrise that does not occur at that latitude on that day is the usual case. The message says what could not be computed. Retrying will not help; changing the place or the date will.

Costs no credits.

rate_limited — HTTP 429

Too fast.

Your key's token bucket is empty. Retry-After says how many seconds to wait, and X-RateLimit-Remaining and X-RateLimit-Reset let you pace yourself before it happens. Heavy endpoints have their own ceiling of 10 a minute on top of the plan's rate. A publishable key is also limited per site, at our edge, and more tightly on the routes that cost five credits or more; that refusal says so, carries Retry-After: 60 and has no X-RateLimit-* headers.

Costs no credits.

engine_error — HTTP 500

Our fault.

Something failed inside the calculation that should not have. It is reported to us automatically with the request id; send us X-KJ-Request-Id from the response and we can find the exact request without you telling us what was in it.

Costs no credits.

service_disabled — HTTP 503

The API is deliberately turned off.

The kill switch is on — an incident, or maintenance. GET /v1/health keeps answering throughout, so it is the thing to poll. This is never a way of shedding load from one account.

Costs no credits.

Which of these are worth retrying

  • rate_limited — yes, after Retry-After. With backoff, not in a tight loop.
  • engine_error — once, then tell us. Twice in a row is not a transient.
  • service_disabled — poll GET /v1/health rather than the endpoint you wanted.
  • Everything else — no. The same request will be refused the same way; fix the request, the key or the plan.