Axios retry: retry a POST safely with an idempotency key
Use axios-retry for network errors, 429 and 5xx with exponential backoff, and retry a paid POST only when it carries an Idempotency-Key.

To retry Axios requests, install axios-retry and call axiosRetry(client, { retries, retryCondition, retryDelay }): a failed request that matches retryCondition is sent again after retryDelay. Axios's own docs show the same idea written by hand as a response interceptor. Against a paid API, retry network errors, 429, and 5xx with exponential backoff, and retry a POST only when it carries an Idempotency-Key, so a resend returns the original job instead of starting and billing a second one.
axios-retry facts come from its README and source, Axios facts from its Retry and error recovery, Error handling, and Request config pages, and Sume facts from Errors and rate limits, Errors and spend, and Create a run. All were read on 2026-09-27. Axios reaches Sume over plain HTTPS; there is no Sume plugin for it.
What does axios-retry retry by default?
More than you may want for a paid create. The default condition, isNetworkOrIdempotentRequestError, accepts network errors on any method, POST included, apart from codes it treats as unsafe to retry, plus a 429 or 5xx on GET, HEAD, OPTIONS, PUT, or DELETE. It never retries a timed-out request (ECONNABORTED), and it skips a canceled POST. By default the resends go out with no delay, although every built-in delay function takes the larger of its own value and the Retry-After header.
| Option | Default | Effect |
|---|---|---|
retries | 3 | Retries before failing |
retryCondition | isNetworkOrIdempotentRequestError | Network errors on any method; 429 and 5xx on idempotent methods only |
retryDelay | No delay | exponentialDelay or linearDelay add backoff |
shouldResetTimeout | false | The request timeout covers the whole lifecycle, not each retry |
Why is retrying a POST risky, and what makes it safe?
A network error or a timeout does not tell you whether the server got the request. If it did, a blind resend of a create starts a second paid job, which is why Sume's docs say not to retry unsafe submit requests without an Idempotency-Key. With a key, the resend is safe:
- Same key, same body:
200with the original receipt andidempotency_hit: true. No second run, no second charge. - Same key while the first request is still in flight:
409 idempotency_key_in_use, retryable; wait about a second and resend. - Same key after a create that failed with
402,503, or similar: the key was released, so once the cause is fixed, a retry with the same key can start the run. - Derive the key from the thing being made, such as an order id plus a version, not from the moment of asking. axios-retry resends the same request config, so every attempt carries the same key.
How do I write the retry condition?
Refuse POSTs without a key first. Then retry what has no response, except a request you canceled yourself. When a response carries Sume's error envelope, trust its retryable flag; otherwise fall back to 408, 429, and 5xx, the same set Sume's own SDK retries. The delay reuses exponentialDelay with a 500 ms factor, about 1, 2, and 4 seconds plus up to 20% jitter, and waits longer when Retry-After or the envelope's retry_after_seconds asks. Send the key on each create, for example { headers: { "Idempotency-Key": "order-1042-promo-v1" } } as the third argument of sume.post.
import axios from "axios";
import axiosRetry, { exponentialDelay } from "axios-retry";
const sume = axios.create({
baseURL: "https://api.sume.com",
timeout: 30_000,
headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` },
});
axiosRetry(sume, {
retries: 3,
shouldResetTimeout: true, // every attempt gets the full 30 s
retryDelay: (count, error) => {
const hint = error.response?.data?.error?.retry_after_seconds ?? 0;
return Math.max(exponentialDelay(count, error, 500), hint * 1000);
},
retryCondition: (error) => {
const { config, response } = error;
if (config?.method === "post" && !config.headers?.["Idempotency-Key"]) return false;
if (!response) return error.code !== "ERR_CANCELED"; // network error or timeout
const envelope = response.data?.error;
if (typeof envelope?.retryable === "boolean") return envelope.retryable;
return response.status === 408 || response.status === 429 || response.status >= 500;
},
});Which errors should not be retried automatically?
Most 4xx answers. A 4xx at create means nothing ran and nothing was charged, so fix the call; Sume's docs call a 403 insufficient_scope retried in a loop the most common and most expensive mistake.
402 insufficient_credits: top up first; retrying returns the same answer.409 idempotency_conflict: the key was already used with a different body. Fix the key derivation.502 attachment_fetch_failed: despite the5xx, it is your input; the API reference example showsretryable: falseandnext_action: fix_input. A rule based on status codes alone would resend it, so read the envelope before the status.- Canceled requests: Axios marks them
ERR_CANCELED, and nobody is waiting for the answer.
Does a retry fix an Axios network error in the browser?
Not always. Axios's docs say that in a browser, ERR_NETWORK can also be a CORS or mixed-content policy violation, and resending the same request does not change the policy. For a paid API the question is moot: Sume's docs keep API keys out of frontend JavaScript, so this client belongs on your server. CORS error calling the Sume API from a browser explains the fix.
On the server, Sume's TypeScript SDK makes axios-retry unnecessary: createSumeClient already retries 408, 429, 5xx, and transport failures twice by default, with exponential backoff and jitter, honors retry-after, and retries a POST only when it carries an Idempotency-Key; see the Sume TypeScript SDK quickstart.
Sources
- Errors and rate limits
- Errors and spend
- Create a run
- Waiting for runs
- Authentication
- API reference
- Sume API reference
- axios-retry README (read 2026-09-27)
- axios-retry source (src/index.ts) (read 2026-09-27)
- axios: Retry and error recovery (read 2026-09-27)
- axios: Error handling (read 2026-09-27)
- axios: Request config (read 2026-09-27)
Related posts
More in Integrations
- Azure Functions timeout: don't wait for an AI video job
Azure Functions time out after 5 minutes by default on Consumption, and HTTP triggers must answer in 230 seconds. Submit video jobs with a callback.
- Bubble API Connector: generate AI video with the Sume API
Set up Bubble's API Connector for Sume: the key in a private header, a manual response so setup costs nothing, and a backend poll of the job.
- Claude Agent SDK MCP server: connect Sume with an API key
Add Sume's hosted MCP server to the Claude Agent SDK with an API-key header, allow only the tools you need, and dry-run paid calls before submitting.
- Claude API MCP connector with Sume: what works today
The Claude API MCP connector has no documented way to authenticate to Sume's hosted MCP today. Why, and what to use instead, like the Agent SDK.
Written by Sume