Skip to content

Retry Loops & Backoff

MirApi Gateway’s retry engine automatically re-fires failed requests with exponential backoff and jitter, protecting your integrations from transient upstream failures — timeouts, 5xx errors, and connection drops.

When an upstream request fails (connection error or 5xx response), the gateway waits and retries automatically. The delay follows this formula:

delay = base_delay × 2^attempt + random_jitter (up to 50% of delay)

Maximum delay is capped at 10 seconds per attempt. If one of the retry attempts succeeds, the gateway returns the response to the client along with the diagnostic header X-Rescued: retry. Example with X-Retry-Delay: 200ms and X-Retry-Count: 4:

Initial attempt: → fails (e.g. 503)
Retry 1: wait ~200ms + jitter → retry
Retry 2: wait ~400ms + jitter → retry
Retry 3: wait ~800ms + jitter → retry
Retry 4: wait ~1600ms + jitter → retry or give up

Jitter distributes retry load across multiple clients so they don’t all hammer the upstream at the same time.

HeaderDefaultDescription
X-Retry-Count0Number of retry attempts (0 = disabled, max practical: 10)
X-Retry-Delay100msBase delay for exponential backoff. Accepts Go durations: 100ms, 500ms, 1s
X-Proxy-Timeout30sPer-attempt timeout. Accepts Go durations: 1s, 5s, 30s. Maximum value: 30s.

The most common use case — retry on 5xx or timeout:

Terminal window
curl -X POST https://proxy.mirapi.io/ \
-H "X-MirApi-Key: $MIRAPI_KEY" \
-H "X-Target-URL: https://api.stripe.com/v1/charges" \
-H "X-Identity-Key: Bearer sk_live_..." \
-H "X-Retry-Count: 3" \
-H "X-Retry-Delay: 500ms" \
-H "X-Proxy-Timeout: 5s" \
-H "Content-Type: application/json" \
-d '{"amount": 2000, "currency": "usd", "source": "tok_visa"}'

For payment endpoints, always pair retries with X-Proxy-Idempotency-Key to prevent duplicate charges:

Terminal window
curl -X POST https://proxy.mirapi.io/ \
-H "X-MirApi-Key: $MIRAPI_KEY" \
-H "X-Target-URL: https://api.stripe.com/v1/charges" \
-H "X-Identity-Key: Bearer sk_live_..." \
-H "X-Retry-Count: 3" \
-H "X-Retry-Delay: 1s" \
-H "X-Proxy-Timeout: 10s" \
-H "X-Proxy-Idempotency-Key: order_789_charge_attempt_1" \
-H "Content-Type: application/json" \
-d '{"amount": 9900, "currency": "usd", "source": "tok_visa"}'
# If all 3 retries succeed at different points, only one charge is created
# because Stripe deduplicates on the forwarded Idempotency-Key

If all retries fail, serve the last cached successful response:

Terminal window
curl https://proxy.mirapi.io/ \
-H "X-MirApi-Key: $MIRAPI_KEY" \
-H "X-Target-URL: https://api.exchangerate.host/latest" \
-H "X-Retry-Count: 3" \
-H "X-Retry-Delay: 200ms" \
-H "X-Smart-Cache: 300s"
# If all 3 retries fail:
# → serves last cached exchange rates from Redis
# → response includes: X-Rescued: cache

After all primary retries fail, try a secondary endpoint:

Terminal window
curl -X POST https://proxy.mirapi.io/ \
-H "X-MirApi-Key: $MIRAPI_KEY" \
-H "X-Target-URL: https://primary-bank.com/api/charge" \
-H "X-Failover-URL: https://backup-bank.com/api/charge" \
-H "X-Retry-Count: 2" \
-H "X-Retry-Delay: 500ms" \
-H "X-Proxy-Timeout: 8s" \
-H "Content-Type: application/json" \
-d '{"amount": 5000, "currency": "usd"}'
# primary fails × 2 → tries backup bank
# response includes: X-Rescued: failover

For latency-sensitive AI requests, use tight timeouts to fail fast and retry quickly:

Terminal window
curl -X POST https://proxy.mirapi.io/ \
-H "X-MirApi-Key: $MIRAPI_KEY" \
-H "X-Target-URL: https://api.openai.com/v1/chat/completions" \
-H "X-Identity-Key: Bearer sk-proj-..." \
-H "X-Retry-Count: 2" \
-H "X-Retry-Delay: 100ms" \
-H "X-Proxy-Timeout: 8s" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'

Use X-Webhook-Callback for operations where the upstream may take minutes or hours to recover. The background worker continues retrying across restarts:

Terminal window
curl -X POST https://proxy.mirapi.io/ \
-H "X-MirApi-Key: $MIRAPI_KEY" \
-H "X-Target-URL: https://api.stripe.com/v1/charges" \
-H "X-Identity-Key: Bearer sk_live_..." \
-H "X-Webhook-Callback: https://your-app.com/webhook" \
-H "X-Proxy-Idempotency-Key: order_789_attempt_1" \
-H "X-Retry-Count: 5" \
-H "X-Retry-Delay: 2s" \
-d '{"amount": 9900, "currency": "usd"}'
# Returns 202 immediately
# Worker retries: 2s, 4s, 8s, 10s (capped), 10s+jitter
# POSTs result to callback when Stripe responds
AttemptX-Retry-Delay: 100msX-Retry-Delay: 500msX-Retry-Delay: 1s
1~100ms + jitter~500ms + jitter~1s + jitter
2~200ms + jitter~1000ms + jitter~2s + jitter
3~400ms + jitter~2000ms + jitter~4s + jitter
4~800ms + jitter~4000ms + jitter~8s + jitter
5~1600ms + jitter~8000ms + jitter~10s (capped)

All delays are capped at 10 seconds maximum.