To retry astrology API requests safely, send a stable Idempotency-Key header that stays identical across every retry of the same logical operation, and only retry on transient failures (429 and 5xx) using exponential backoff with jitter. On Vedika, a duplicate request carrying a key the server has already seen returns the original stored result instead of running a second billed computation — so a flaky network never turns one chart into two charges. This guide shows the exact request shapes, a retry policy that won't double-charge, and the edge cases that bite teams in production.
Why retries are dangerous for a billed astrology API
Every call to the Vedika API costs money — roughly $0.01 to $0.05 per query depending on the path and plan, drawn from your wallet balance. There is no free tier on production keys; the free sandbox exists precisely so you can build retry logic without spending anything. That billing model makes naive retries risky. The classic failure looks like this:
- Your client sends
POST /api/v1/astrology/query. - Vedika computes the chart, runs the AI interpretation, debits the wallet, and sends the response.
- The response is lost on the way back — a dropped connection, a load-balancer timeout, a 504 from an intermediary proxy.
- Your HTTP client sees a failure and retries.
- Without protection, the server treats the retry as a brand-new request: it computes again and debits again.
The work succeeded the first time; only the acknowledgement was lost. Charging twice for one user action is the single most common integration bug we see, and it is entirely preventable.
Idempotency keys: one logical request, one charge
An idempotency key is a client-generated identifier you attach to a request so the server can recognise duplicates. The contract is simple: the first time the server sees a key, it does the work and remembers the outcome against that key. Any later request carrying the same key — within the retention window — gets the stored response replayed back, with no recomputation and no second debit.
Generate the key once, reuse it on every retry
The mistake that defeats the whole mechanism is generating a fresh key inside the retry loop. The key must be created once per logical operation and reused across every transport-level retry of that operation. A new key is only appropriate when the user genuinely wants a new query.
KEY=$(uuidgen)
curl -sS https://api.vedika.io/api/v1/astrology/query \
-H "Authorization: Bearer vk_live_YOUR_API_KEY" \
-H "Idempotency-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"question": "When is a favourable window for changing jobs?",
"birthDetails": {
"datetime": "1991-03-14T07:25:00",
"latitude": 18.5204,
"longitude": 73.8567,
"timezone": "Asia/Kolkata"
}
}'
If that curl fails with a network error, rerun the exact same command with the same $KEY. If the first attempt actually reached the server and completed, the second call returns the same answer and your wallet is debited once. If the first attempt never landed, the second call runs normally. Either way you pay for exactly one chart.
What makes a good key
- Unique per operation. A UUID (v4) is the safe default. Tie it to the user action that triggered the request — a button press, a queued job — not to wall-clock time.
- Stable across retries. Persist it alongside the in-flight operation so a process restart or a worker handoff reuses the same value.
- Not derived from the payload alone. Two legitimately distinct queries can carry identical birth details; let the key represent the intent to run once, not the inputs.
Which failures are safe to retry
Idempotency protects you from double-charging, but it doesn't tell you when to retry. Retry only on transient conditions. Hammering the API on a permanent error wastes quota and delays the real fix.
| Status | Meaning | Retry? |
|---|---|---|
| 200 | Success | No — you're done |
| 400 / 422 | Malformed request or invalid birth details | No — fix the payload first |
| 401 | Bad or missing API key | No — check the Authorization: Bearer header |
| 402 | Insufficient wallet balance | No — top up, then send a fresh request |
| 429 | Rate limited | Yes — honour Retry-After, then back off |
| 502 / 503 / 504 | Transient server or gateway error | Yes — back off and retry with the same key |
A subtle case: a 4xx that you retry with the same idempotency key still won't succeed, because the request body is the problem, not the network. Reserve retries for 429 and 5xx, and resolve 4xx by correcting input.
Exponential backoff with jitter
Immediate retries make outages worse — every client reconnecting in lockstep produces a thundering herd. Space attempts out with exponential backoff, and add randomised jitter so clients don't synchronise. A small, bounded loop is enough.
// Generic fetch client — swap in your own HTTP library as needed.
import { randomUUID } from 'node:crypto';
async function queryWithRetry(body, { maxRetries = 4 } = {}) {
const idempotencyKey = randomUUID(); // once per logical operation
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch('https://api.vedika.io/api/v1/astrology/query', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.VEDIKA_API_KEY}`,
'Idempotency-Key': idempotencyKey,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
if (res.ok) return res.json();
const retryable = res.status === 429 || res.status >= 500;
if (!retryable || attempt === maxRetries) {
throw new Error(`Vedika query failed: ${res.status}`);
}
// Honour Retry-After on 429; otherwise exponential backoff + jitter.
const headerWait = Number(res.headers.get('retry-after')) * 1000;
const backoff = Math.min(2 ** attempt * 500, 8000);
const jitter = Math.random() * 250;
await new Promise(r => setTimeout(r, (headerWait || backoff) + jitter));
}
}
queryWithRetry({
question: 'Is this a good year for property investment?',
birthDetails: {
datetime: '1991-03-14T07:25:00',
latitude: 18.5204,
longitude: 73.8567,
timezone: 'Asia/Kolkata',
},
}).then(console.log);
The key is created outside the loop, so all four attempts share it. The backoff caps at eight seconds; on a 429 it defers to the server's Retry-After value when present.
Python equivalent
import os, time, uuid, random, requests
def query_with_retry(body, max_retries=4):
key = str(uuid.uuid4()) # once per logical operation
headers = {
"Authorization": "Bearer " + os.environ["VEDIKA_API_KEY"],
"Idempotency-Key": key,
"Content-Type": "application/json",
}
for attempt in range(max_retries + 1):
r = requests.post(
"https://api.vedika.io/api/v1/astrology/query",
json=body, headers=headers, timeout=30,
)
if r.ok:
return r.json()
if r.status_code != 429 and r.status_code < 500:
r.raise_for_status() # 4xx — don't retry
if attempt == max_retries:
r.raise_for_status()
wait = float(r.headers.get("retry-after", 0)) or min(2 ** attempt * 0.5, 8)
time.sleep(wait + random.random() * 0.25)
Computation endpoints, streaming, and where idempotency matters most
Vedika exposes 704 operations across 25 domains (704 enumerated as of June 2026), and the retry strategy differs by endpoint class.
- AI query —
POST /api/v1/astrology/queryis the billed, interpretation-heavy path where double-charging is the real risk. Always attach an idempotency key here. - V2 computation — the
/v2/astrology/*family takes flatdatetime,latitude,longitude,timezonefields and returns deterministic chart math (positions, dashas, divisional charts). These are cheap and deterministic, but most of them do not accept a retry key. Send one to birth chart, kundli, panchang, horoscope or the matrimony routes and you get422 IDEMPOTENCY_NOT_SUPPORTED, with nothing charged. Only tithi, nakshatra, yoga, karana, the dasha endpoints, Ashtakoota matching and the Vastu calculation routes accept one; the API reference has the full list. Every successful call is charged, so cache chart results you will show again instead of requesting them twice. - Streaming —
POST /api/v1/astrology/query/streamemits Server-Sent Events. Because the output is incremental, you can't simply replay a partial stream. On disconnect, reconcile on your side or restart; for billing-critical calls prefer the non-streaming endpoint with a key, then render the full payload when it lands.
All paths authenticate with Authorization: Bearer vk_live_* over the base URL https://api.vedika.io. The same three astrology systems — Vedic sidereal, Western tropical, and KP — are served from one API. Retry keys are not uniform across it: send one only to an endpoint that accepts it, and call the others without the header.
A note on determinism
Chart mathematics is deterministic: the underlying XALEN Ephemeris (Vedika's own open-source engine, validated against JPL DE440 and swetest with no chart deviating beyond 0.1° across a five-million-chart test) returns identical planetary positions for identical inputs. That ephemeris precision means a retried computation endpoint yields byte-stable geometry. The AI interpretation layer, by contrast, is what you pay per call for and what idempotency keys protect — a replayed key returns the same stored interpretation, not a freshly generated one.
Key facts
- Attach a stable
Idempotency-Keyheader to AI queries and to the other endpoints that accept one; reuse it across all retries of the same logical operation. Most/v2chart endpoints refuse it with422, so call those without it. - Every successful call is charged, including a repeat request for a chart you already fetched. A retry key only covers retries within 24 hours; cache results you will show again.
- The server replays the stored response for a duplicate key within the retention window — one charge, not two.
- Retry only on 429 and 5xx; never retry 400, 401, 402, or 422.
- Use exponential backoff capped at a few seconds, plus random jitter, and honour
Retry-Afteron 429. - Generate the key once per operation — a fresh key per retry defeats the protection.
- Prototype your retry loop for free against the no-key sandbox before pointing at
vk_live_*. - Per-query cost runs $0.01–$0.05; plans start at $12/mo — see pricing.
Putting the pieces in place
Safe retries come down to two independent decisions. Idempotency answers “what if the work already happened?” — solved by a stable client key. Retry policy answers “when should I try again?” — solved by classifying the status code and backing off. Get both right and a lost response, a 503 during a deploy, or a momentary rate limit becomes a non-event for your users and your wallet. Build the loop once against the sandbox, confirm a deliberately repeated key returns one charge, and ship it. For the full endpoint catalogue and request schemas, see the API documentation.