Content

Best Idempotency and Retry Infrastructure for Agents

Who owns the idempotency key, and does a retry actually reuse it? Temporal, Inngest, Trigger.dev, AWS Step Functions and Cloudflare Workflows compared.

EngineeringOct 21, 2026

A support agent issues a refund. The HTTP request reaches Stripe, Stripe processes it, and then the connection drops before the response comes back. Your durable execution engine sees a step that didn't return, does exactly what it was configured to do, and retries. The customer now has two refunds. Every component behaved correctly, the workflow engine's own test suite passes, and you are out $240.

This is the gap between two things that both get called "retries" and are not the same problem. Orchestration-level safety asks: did this step complete, and if the process died, can we resume without redoing finished work? API-level safety asks: if this exact write arrives twice, will the provider treat it as one action? A durable execution engine solves the first and is silent on the second. An idempotency key solves the second and knows nothing about workflows. Most teams build one of the two and discover the other during an incident.

Below are seven options across both layers, with one question applied to each: when a retry happens, who owns the idempotency key, and does the retry reuse it? We also cover where each tool genuinely doesn't fit, ours included.

EnginePricingRetry behaviorDoes a retry reuse completed work?
TemporalGreater of $100/mo or 5% of usageActivities retry indefinitely by default; workflows themselves don't retryYes, via deterministic replay of event history
InngestFree tier, then $99/mo Pro4 retries, plus an onFailure handlerYes, completed steps are memoized and skipped
Trigger.dev$0 base plus usage3 attempts; failed runs can be bulk-replayedNot described as memoized; replay re-runs
AWS Step Functions4,000 state transitions/mo free; $25 per million after3 attempts per Retry blockNo step memoization
Upstash Workflow$0 pay-as-you-go, $1 per 100K steps3 retries with exponential backoff; failures go to a DLQYes, completed steps keep their results
Cloudflare WorkflowsFree tier; $5/mo Workers Paid5 retries per step with exponential backoffStep outputs are retained within a run

A human who isn't sure whether a payment went through opens a dashboard and checks. An agent in a loop retries. That single behavioral difference is the entire risk surface, and it is why agent workloads need both layers rather than whichever one the team built first.

The three jobs

  • Resume without redoing: if a run dies at step 7 of 12, restart at 7, not at 1. This is memoization or event-history replay, and it is what durable execution engines are built for.
  • Make the unavoidable retry safe: some retries must happen, because the first attempt's outcome is genuinely unknown. The provider has to be the one that refuses to run the write twice.
  • Tell the difference between "failed" and "unknown": a 500 and a timeout look similar to code and mean very different things. Retrying the first is usually fine; retrying the second without a key is how duplicates happen.

The four requirements specific to agents

  • Deterministic keys, generated near the call. A key built from the operation and its real identifiers means a retry from anywhere, the engine, the agent's own loop, or a human re-running a failed step, collapses onto the original request. Random keys work only if something reliably persists them across restarts. More on key construction in the complete API idempotency guide.
  • Writes retried only when protected. A GET can be retried freely. A POST without a key should not be retried automatically at all, and most generic retry wrappers don't make that distinction.
  • Awareness of provider TTL. Stripe documents a 24-hour window for idempotency keys. A workflow that sleeps for three days and then retries has no protection left, even though the code looks identical to a retry five seconds later.
  • A record of the attempt, not just the outcome. When you are reconstructing a duplicate-charge incident, you need to know that attempt two carried the same key as attempt one. Without that, you are guessing. See API observability for AI agents.

Where the two layers meet, in code

The shape worth aiming for: the orchestrator owns the workflow's durability, and the call layer owns write safety. Neither tries to do the other's job.

refund-step.js
import { exec } from "@swytchcode/runtime";

// The durable execution engine owns "did this step finish".
// This step owns "is this write safe to retry".
export const refundStep = async (step, ticket) => {
  return step.run("issue-refund", async () => {
    // Deterministic key: same logical action always produces the same key,
    // so a retry from the engine, the agent loop, or a human collapses onto it.
    const idempotencyKey = `refund:${ticket.chargeId}:${ticket.amount}`;

    // exec() checks the method is allowlisted, evaluates policy against the
    // arguments, injects the credential, and retries rate limits with backoff.
    return exec("stripe.refund.create", {
      body: { charge: ticket.chargeId, amount: ticket.amount },
      idempotencyKey,
    });
  });
};

The runtime details are in the JavaScript SDK docs, the retry semantics in the retries guide, and key handling in the idempotency guide. Working examples live in swytchcode-examples.

1. Swytchcode (the call layer)

Overview. Swytchcode is not a workflow orchestrator and does not compete for ownership of the run. It governs the individual call: POST and PATCH are retried on rate-limit errors only when an idempotency key is set, which means the default behavior for an unprotected write is to surface the failure rather than quietly double it. Response validation also catches the 200 OK with an error in the body case, which otherwise reads as success and prevents a legitimate retry from ever happening.

Pricing. Free for 100 live commands/month, Pro $29/month for 10,000, Business $149/month for 1,000,000, Enterprise custom. Flat tiers rather than per-call metering, which is the main cost difference against per-execution engines at volume. Details on pricing.

Best for. Agents making write calls where a duplicate is expensive: payments via Stripe, outbound mail via Gmail, CRM writes via Salesforce, or issue creation via GitHub.

Pros

  • Write safety is the default, not a configuration you remember. No key, no automatic retry of a write. This was not described in Arcade's, Composio's or Nango's public docs as of October 2026.
  • Framework-agnostic. The same behavior whether the call came from a CLI run, an SDK call, or an MCP client, so swapping orchestrators doesn't re-open the question. See CLI, MCP and SDK compared.
  • Response validation before the retry decision, so a soft failure is classified correctly instead of being recorded as a success.
  • Audit of every attempt and every refusal, written locally, which is what you actually need when reconstructing a duplicate incident.

Cons

  • No durable workflow state. If your process dies mid-run, Swytchcode will not resume it. You still want Temporal, Inngest or an equivalent above it.
  • No sleeps, schedules or fan-out primitives. It is deliberately not a scheduler, so long-running multi-day flows need the orchestrator to own timing.
  • Provider TTL still governs. Setting a key correctly cannot extend Stripe's 24-hour window, so very delayed retries remain your design problem.

2. Temporal

Overview. The most battle-tested durable execution engine in the list, and the one most likely to already be in a large enterprise. Durability comes from replaying event history, which is why workflow code must be deterministic. Activities retry indefinitely by default; workflows themselves do not retry. Workers run on your own infrastructure, which is a meaningful advantage for data residency.

Pricing (per a July 2026 comparison). Temporal Cloud is the greater of $100/month or 5% of usage, metered on Actions and storage.

Best for. Long-running, high-value workflows in organizations that can absorb the determinism constraint and already have platform engineers.

Pros

  • Indefinite activity retries with full history, so a transient provider outage doesn't lose the run.
  • Seven official SDK languages and self-hosted workers, which suits polyglot enterprises.
  • Signals and updates give you a clean way to inject a human approval decision into a paused run.

Cons

  • Determinism is a real constraint and an awkward one for agent code, where the whole point is that the next step is chosen at runtime by a model. Agent reasoning belongs in activities, not workflow code.
  • Hard limits to design around: event history caps at 51,200 events or 50 MB, payloads at 2 MB, and long-lived workflows need Continue-As-New.
  • Indefinite retries plus an unprotected write is the most dangerous combination in this entire article.

3. Inngest

Overview. Steps run inside your own app over HTTP, and completed steps are memoized, so a re-invoked run skips work it already finished. That memoization is the closest thing in this category to built-in duplicate protection, with the important caveat below. Events are matched with CEL expressions, and sleeping runs don't count against concurrency.

Pricing (July 2026). Free tier, then $99/month Pro, metered on executions. Max sleep one year (7 days on free), run length 30 days on free up to 366 days on Pro, 1,000 steps per run, 4 MiB step outputs.

Best for. Teams who want durable steps without running workers, and who like keeping step logic inside their existing application.

Pros

  • Step memoization, which prevents the most common class of accidental re-execution.
  • An onFailure handler alongside 4 retries, so terminal failures get an explicit path instead of disappearing.
  • Low operational overhead, with no separate worker fleet to run.

Cons

  • Memoization protects the engine's view, not the provider's. If a step times out after Stripe already processed the charge, Inngest believes the step failed and will retry it. Memoization cannot know what the provider did.
  • Execution-metered pricing means a chatty agent's cost scales with its retry behavior.

4. Trigger.dev

Overview. Tasks run on Trigger's managed machines, deployed through its CLI, with a strong dashboard story: failed runs can be bulk-replayed by a human, which is genuinely useful during an incident and genuinely dangerous without idempotency keys, because a bulk replay of 400 unprotected writes is 400 new writes. Waits over five seconds are checkpointed on cloud so they don't burn compute.

Pricing (July 2026). $0 base plus usage, metered on compute-seconds plus a per-run fee.

Best for. Product teams who want managed execution and a good operator UI without running infrastructure.

Pros

  • Bulk replay from the dashboard, which shortens recovery when a provider outage fails a thousand runs.
  • Checkpointed waits keep cost down for workflows that spend most of their life waiting on a human.

Cons

  • Replay is not memoization. The comparison we reviewed does not describe completed steps being skipped on replay, so a replay re-runs work. Treat idempotency keys as mandatory before anyone uses that button.
  • Self-hosted loses checkpointing, so the cost profile for long waits changes if residency rules push you off their cloud.

5. AWS Step Functions

Overview. JSON state machines orchestrating AWS services, with IAM as the access boundary and the lowest adoption friction of the group if you are already on AWS. Retry blocks give three attempts by default. The limits are the thing to read carefully before committing an agent workload: Standard executions max out at one year and 25,000 history events with 256 KiB payloads per state, Express caps at five minutes, and direct HTTP tasks time out at 60 seconds, which is short for a model call.

Pricing (July 2026). 4,000 state transitions per month free, then $25 per million transitions.

Best for. AWS-native teams orchestrating AWS services, especially alongside Bedrock AgentCore.

Pros

  • No new vendor or identity model for an AWS shop, which shortens security review considerably.
  • Task-token pausing is a clean fit for human-in-the-loop approval gates on Standard executions.

Cons

  • No step memoization, so safe resumption is entirely your design responsibility.
  • 60-second HTTP task timeout and 256 KiB payloads are tight for agent steps that carry conversation state.
  • JSON state machines are a poor authoring experience for branching agent logic compared with code-defined graphs.

6. Upstash Workflow

Overview. Steps run as HTTP calls in your app while Upstash holds the state, with no monthly platform fee. The failure handling is the most agent-friendly design in the list: three retries with exponential backoff, then the run lands in a dead-letter queue where you can resume from the failed step with completed steps keeping their results, restart, or re-fire a callback.

Pricing (July 2026). $0 pay-as-you-go, $1 per 100K steps. Sleeps up to a year on pay-as-you-go, 1,000 steps per run and 100 MB accumulated state by default.

Best for. Serverless teams who want DLQ semantics and per-step pricing without a platform fee.

Pros

  • Resume-from-failed-step with results preserved, which is exactly the behavior you want after fixing a bug mid-incident.
  • A real dead-letter queue, so failures are inspectable rather than just logged.
  • No platform fee, which makes low-volume evaluation genuinely free rather than nominally free.

Cons

  • Smaller ecosystem than Temporal, with fewer patterns documented for complex enterprise topologies.
  • Still no outbound idempotency handling. Resuming safely inside the engine says nothing about what the provider already did.

7. Cloudflare Workflows

Overview. Runs on Cloudflare Workers with five retries per step by default and exponential backoff, sleeps up to 365 days, and idle time that isn't billed. step.waitForEvent buffers events for up to a year, which is a tidy approval-gate primitive.

Pricing (July 2026). Free tier, then $5/month Workers Paid, metered on requests, CPU and steps. 1,024 steps per run on free, 25,000 on paid, 1 MiB step outputs.

Best for. Teams already on Cloudflare's edge platform wanting cheap, long-waiting workflows.

Pros

  • Cheapest entry point in the list for a team already paying for Workers.
  • Idle time isn't billed, which suits approval workflows that wait on a person for days.

Cons

  • Five default retries per step is the most aggressive default here, which is the worst default to pair with unprotected writes.
  • 1 MiB step outputs and Workers runtime constraints limit what agent steps can carry between stages.

Comparison of idempotency and retry infrastructure

ToolLayerPricingDefault retriesReuses completed workMain tradeoff
SwytchcodeCall layerFree / $29 / $149 flat tiersRate limits only; writes only with a keyN/A (per-call)Not a workflow engine
TemporalOrchestrationGreater of $100/mo or 5% of usageActivities retry indefinitelyYes, deterministic replayDeterminism constraint; aggressive retries
InngestOrchestrationFree, then $99/mo Pro4 retries + onFailureYes, step memoizationMemoization can't see provider state
Trigger.devOrchestration$0 base + compute-seconds and per-run fee3 attemptsNot described as memoizedBulk replay is unsafe without keys
AWS Step FunctionsOrchestration4,000 transitions/mo free, then $25/million3 per Retry blockNo60s HTTP task timeout; JSON authoring
Upstash WorkflowOrchestration$1 per 100K steps, no platform fee3 with backoff, then DLQYes, resume with results keptSmaller ecosystem
Cloudflare WorkflowsOrchestrationFree, then $5/mo Workers Paid5 per stepStep outputs retained in runMost aggressive retry default

None of the six orchestration engines documented idempotency-key handling on the outbound HTTP call as a feature of the orchestration layer in the materials we reviewed. That is the column that does not exist in most comparisons of this category, and it is the one that decides whether a retry costs you money.

How to choose: kill the process mid-write, twice

Run this against a sandbox account for whichever provider matters most to you, before you commit to a stack.

  1. Pick one non-idempotent write. A charge, a refund, an email send. Something where two is obviously wrong.
  2. Kill the process after the request leaves but before the response lands. A proxy that drops the response, or a hard kill on a timer. Then let the engine do whatever it does.
  3. Count the side effects at the provider. Not the log lines, the actual charges. One is correct. Two means your stack has the gap this article is about.
  4. Repeat with a 48-hour delay before the retry. This is where provider TTL bites: the same code that was safe at five seconds is unprotected past the window.
  5. Press the bulk-replay button on 50 failed runs. If that produces 50 new side effects, the operator UI you were relying on during incidents is an incident amplifier.
  6. Read back the audit trail and try to prove what happened. You want attempt one, attempt two, the key each carried, and the provider's response to both. If you can't reconstruct that, see how to log every API call an AI agent makes.

FAQ: idempotency and retries for AI agents

Does a durable execution engine make idempotency keys unnecessary?

No, and this is the single most expensive misconception in this category. An engine reduces how often a retry happens and can skip steps it knows finished. It cannot know what the provider did during a request whose response never arrived. That specific case, which is also the most common one, is only covered by the provider refusing to run the same keyed write twice.

Where should the key be generated?

As close to the call as possible, derived deterministically from the operation and its real identifiers. Generated at the top of a workflow and passed down, it gets lost on restarts. Generated randomly per attempt, it defeats its own purpose. Derived from the charge ID and amount, it is the same key no matter who triggers the retry.

Which APIs actually support idempotency keys?

Support is inconsistent and payment APIs are the best-covered category. Stripe documents an Idempotency-Key header with a 24-hour window. Email providers are the clearest gap, which we break down provider by provider in which email APIs support idempotency keys. Always verify against the provider's current docs rather than a blog post.

What if the provider has no idempotency support at all?

Then you cannot make the retry safe at the provider, and you have to make it unnecessary instead: do not auto-retry that write, surface the ambiguous state to a human or a reconciliation job, and check whether the action already happened via a read before attempting again. A policy rule that holds the retry for approval is a reasonable stopgap for high-value operations.

How does this change with MCP, now that it's stateless?

Statelessness moves the question of where the key lives, since the server can no longer rely on session memory to recognize a repeat. We work through the options in MCP went stateless, so where do idempotency keys live now? and the broader protocol changes in the MCP 2026-07-28 spec guide.

Can we use two of these together?

That's the recommended shape: one orchestration engine for workflow durability, one call layer for write safety and policy. They solve different problems and the combination is cheaper than building either half yourself, which we argue through in build your own MCP server or buy an execution layer. Framework setup guides for LangGraph and the Anthropic SDK show the wiring.

More content