Authentication
One header, one key, and a small set of errors that each mean something specific.
The header
Send your key as X-API-Key on every request. There is no OAuth flow, no token exchange and nothing to refresh.
curl -X POST https://api.occultapi.com/api/astro/tithi/ \
-H "X-API-Key: yt_live_a1b2c3d4_x9K2mQ7vB4nR8sL1wY6tZ3pC5hJ0dF" \
-H "Content-Type: application/json" \
-d '{ "date_time": "2026-09-16T06:00:00+05:30", "latitude": 26.9124, "longitude": 75.7873, "timezone_as_float": 5.5 }'Key format
Keys look like yt_live_a1b2c3d4_x9K2mQ7vB4nR8sL1wY6tZ3pC5hJ0dF — brand, environment, an eight-character public prefix, then the secret.
yt_live_…spends real credits against your balance.yt_test_…is for development and is labelled as such in your usage records.
The prefix is public and indexed on purpose: if a key is ever leaked in a public repository, it can be found and revoked by its prefix alone, without anyone needing the secret half.
Shown once, stored as a hash
A key is displayed exactly once, when you create it. We store only a SHA-256 hash, so neither an administrator nor a database dump can recover it — which also means we genuinely cannot send it to you again. Afterwards you see only the prefix and last four characters, which is enough to tell two keys apart in a list.
Lost a key? Create a new one and revoke the old one. That is faster than asking us, and it is the only thing we could do anyway.
Errors, and which are not auth problems
Every error uses the standard envelope with is_error: true and a stable machine code in message. Branch on the code, not on the prose.
| Status | message | What it means | What to do |
|---|---|---|---|
| 401 | invalid_api_key | The key is missing, malformed, revoked or expired. | Check the X-API-Key header actually reached us. If you rotated, deploy the new key. |
| 402 | insufficient_credits | The key is valid. The balance is empty. | Recharge. This is not an auth problem — regenerating the key will not help. |
| 403 | endpoint_not_allowed | That endpoint is not enabled for API keys. | Ask us to turn it on. |
| 403 | scope_not_allowed | The key lacks the scope this endpoint needs. | Create a key with the right scopes, or leave scopes empty for all of them. |
| 429 | api_key_rate_limited | Too many requests in one minute for this key. | Back off and retry after the seconds in the Retry-After header. |
| 400 | (field errors) | The request body was wrong. message names each field at fault. | Read message — it is specific. Never charged. |
The one worth repeating: 402 is not an auth failure. The key is good and the balance is empty. Regenerating the key is the common wrong move and changes nothing.
Credit headers
Every response carries what the call cost and what is left, so you can track spend without a second request.
X-Credits-Cost: 1 # what this endpoint costs
X-Credits-Charged: 1 # what you were actually billed — 0 on any error
X-Credits-Remaining: 149 # balance after this callX-Credits-Charged is the one to log. A failed request always reports 0: the credit is reserved before the calculation runs and released if it does not return cleanly, so a bad integration cannot drain a balance while you debug it.
Rate limits
Limits are per key, per minute, and exist to contain a leaked key rather than to ration you. When you exceed one you get a 429 with a Retry-After header in seconds — wait that long rather than retrying immediately. Responses also carry X-RateLimit-Limit and X-RateLimit-Remaining.
A 429 is never charged. If you are hitting the limit in normal operation, ask us to raise it.
Keeping a key safe
- Call from your server, not the browser. A key in a front-end bundle or a mobile app is a public key, whatever it is named. Anyone can read it and spend your balance.
- Keep it in an environment variable or a secret manager. Never commit it.
- Use separate keys per environment so you can revoke one without taking the others down.
- Rotate by creating the new key, deploying it, then revoking the old one — in that order, so nothing is down in between.
- Revoke immediately if a key may have leaked. Revocation takes effect at once, and your remaining credits are unaffected.
Manage all of this on your keys page.