How to Add Automatic Retry to Any HTTP Request

HTTP requests fail. Servers go down, networks hiccup, rate limits trigger, and deployments cause brief outages. If your application calls external APIs, payment processors, or webhook endpoints, you need retry logic.

Most developers end up writing their own — and it’s always more complex than expected.

The DIY Retry Trap

Here’s what “just add retry” typically looks like:

async function sendWithRetry(url, data, maxRetries = 3) {
  for (let i = 0; i <= maxRetries; i++) {
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      if (response.ok) return response;
      if (response.status === 429) {
        // Rate limited — need to parse Retry-After header
        const retryAfter = response.headers.get('Retry-After');
        await sleep(parseRetryAfter(retryAfter));
        continue;
      }
      if (response.status >= 500) {
        await sleep(Math.pow(2, i) * 1000); // Exponential backoff
        continue;
      }
      return response; // 4xx errors shouldn't be retried
    } catch (err) {
      if (i === maxRetries) throw err;
      await sleep(Math.pow(2, i) * 1000);
    }
  }
}

Looks reasonable. But now you need: - Persistence — what if your server restarts mid-retry? - Observability — which requests are failing? How many retries? - Rate limit handling — parsing Retry-After headers correctly - Backoff strategies — exponential? Linear? Jitter? - Dead letter handling — what happens after max retries? - Manual retry — can you retry a specific failed request from a dashboard?

You’ve just built a message queue. Congratulations.

The One-Line Alternative

Instead of building retry infrastructure, proxy your request through Zeplo:

# Original request (no retry)
curl -X POST https://api.stripe.com/v1/charges \
  -H "Authorization: Bearer sk_live_..." \
  -d amount=2000

# With automatic retry (3 attempts, exponential backoff)
curl -X POST "https://zeplo.to/https://api.stripe.com/v1/charges?_retry=3&_token=YOUR_TOKEN" \
  -H "Authorization: Bearer sk_live_..." \
  -d amount=2000

The only change: prefix the URL with zeplo.to/ and add ?_retry=3. Zeplo proxies the request, and if it fails (5xx or timeout), retries with exponential backoff.

Handling Rate Limits Automatically

APIs like Stripe, Twilio, and SendGrid return 429 Too Many Requests with a Retry-After header. Zeplo reads this header automatically and waits the specified time before retrying:

curl -X POST "https://zeplo.to/https://api.sendgrid.com/v3/mail/send?_retry=5&_token=YOUR_TOKEN" \
  -H "Authorization: Bearer SG.xxxxx" \
  -H "Content-Type: application/json" \
  -d '{"personalizations":[{"to":[{"email":"user@example.com"}]}],"subject":"Hello","content":[{"type":"text/plain","value":"Hi!"}]}'

If SendGrid rate limits you, Zeplo pauses and retries after the cooldown. No code changes needed.

Visibility Into Every Request

Every request — successful or failed — is logged in the Zeplo dashboard with:

  • Request headers and body (what you sent)
  • Response status code, headers, and body (what came back)
  • Timing information (how long each attempt took)
  • Retry history (which attempts failed and why)

When something goes wrong, you can see exactly what happened and manually retry with one click. No log diving required.

Common Use Cases

Payment processing: Retry failed charges without double-charging (use idempotency keys in your request body).

Webhook delivery: If your webhook endpoint is briefly down during a deployment, Zeplo retries until it comes back.

Third-party API calls: Email providers, SMS gateways, analytics services — all have occasional downtime. Retry transparently.

Data synchronization: Sync data between systems with retry on failure, ensuring eventual consistency without custom queue infrastructure.

Getting Started

No SDK or library needed. If your application can make HTTP requests, you can add retry:

  1. Create a free account (500 requests/month included)
  2. Get your token from the dashboard
  3. Change https://api.example.com to https://zeplo.to/https://api.example.com?_retry=3&_token=YOUR_TOKEN

Every request is logged, every retry is tracked, and you didn’t write a single line of queue code.


Zeplo adds retry, delay, and scheduling to any HTTP request. No infrastructure required. Start free →

Return to Blog