Financial API Failover Strategy: Timeouts, 429s, Staleness and Fallbacks
A financial API failover strategy for FX feeds: error classes, timeouts, retries with backoff, 429 and Retry-After, stale caches and data-quality guards.

- Classify errors: client errors (401/403/422) need a fix, 429 needs backing off, 5xx and timeouts can be retried.
- Serve from a cache with a last-good copy, mark data as stale and never show zero or blank prices.
- Guard against bad data as well as missing data: low-source flags, jump limits and timestamps.
A pricing page that crashes when the data provider hiccups is bad. A pricing page that silently shows a wrong number is worse. A solid financial API failover strategy covers both: availability problems and data-quality problems. This guide lays out the patterns with EZRate’s error model as the example.
429 using Retry-After, and treat 401/403/422 as bugs to fix. Always read from a cache that keeps a last-good copy; show it with a “stale” notice if the feed is down. Check low_sources and updated_at, cap sudden jumps, and keep a secondary source for critical flows.Part of the Iranian Rial exchange rate API guide.
Error model
{ "error": { "code": "rate_limited", "message": "…" }, "meta": { "reset_at": "2026-10-20T00:00:00Z" } }| Status / code | Meaning | Action |
|---|---|---|
401 invalid_api_key | Key missing or wrong | Fix configuration; do not retry |
403 forbidden | IP or domain not allowed for the key | Fix key restrictions; do not retry |
404 not_found | Unknown symbol or market | Fix the request |
422 validation_failed | Bad parameter; fields explains | Fix the request |
429 rate_limited | Per-second or quota limit hit | Wait Retry-After; check caching |
5xx / timeout | Transient failure | Retry with backoff, then fall back |
Response headers X-RateLimit-Remaining-Day, X-RateLimit-Remaining-Month and Retry-After let you act before you hit a wall. Full details: JSON reference.
Retry with backoff
async function getJson(url: string, key: string, tries = 3): Promise<any> {
for (let i = 0; i < tries; i++) {
try {
const r = await fetch(url, { headers: { "X-API-Key": key }, signal: AbortSignal.timeout(10_000) });
if (r.ok) return r.json();
if (r.status === 429) {
const wait = Number(r.headers.get("retry-after") ?? 60);
throw Object.assign(new Error("rate_limited"), { retryAfter: wait, final: true });
}
if (r.status < 500) throw Object.assign(new Error(`client ${r.status}`), { final: true });
} catch (e: any) {
if (e.final || i === tries - 1) throw e;
}
await new Promise(res => setTimeout(res, 500 * 2 ** i + Math.random() * 250)); // jitter
}
}Cache with a last-good copy

- Fresh key with TTL =
freshness_sec. - Last-good key with a long TTL (e.g. 24 h).
- Background refresh from a scheduler, so user requests never wait on the upstream.
- Stale flag in your own payload so the UI can show “last updated 14 minutes ago”.
Implementations: Laravel, Python/Django, Node.js.
Data-quality guards
| Guard | Rule of thumb |
|---|---|
| Low sources | If low_sources is true, display with a badge and pause automatic repricing |
| Staleness | If updated_at is older than N minutes, show a warning |
| Jump limit | If a price moves more than X% since the last accepted value, hold it for review |
| Sanity bounds | Reject zero, negative or wildly out-of-range values |
| Unit assertion | Check quote is what you expect (IRT vs IRR) |
EZRate already applies median filtering and a jump guard upstream (see outlier detection); your own guards protect against integration bugs and edge cases.
US Dollar271,740Toman−0.02%Secondary sources
For flows where downtime costs money (checkout, trading), keep a second source. Use it only when the primary is stale beyond a threshold, log every switch, and never average two sources with different methodologies without understanding them.
Monitoring
- Alert on cache age, not just HTTP errors.
- Track 429s: they usually mean caching broke.
- Track the remaining quota from headers or
/usage. - Synthetic check: request one symbol every minute from outside your network.

Designing for degraded modes
Decide in advance how each part of your product behaves when data is old: product pages keep showing prices with a notice; checkout may refuse to finalise a price older than a threshold; automated repricing pauses. Writing these rules down turns an outage from an emergency into a documented, expected state.
Practise these modes too: occasionally block the upstream host in staging and confirm that pages, checkout and jobs behave exactly as documented.
Related live rates: US dollar rate, 18K gold price, Emami coin price.

Comments (0)
Comments are shown after review. Sign-in is needed to send.


