Temporal alternatives for replay versus idempotency
Temporal replays workflow history and does not rerun a completed activity. The provider can charge twice if the activity retries before that result is saved.
Key takeaways
- -In this article we explore Temporal alternatives when replay and provider idempotency get treated as the same fix.
- -To understand how Temporal replay works: completed activities are not run again. An activity that never reports completion can still be retried.
- -Workflows do not retry by default. Activities do, and the default is at least once unless maximumAttempts is 1.
- -maximumAttempts of 1 is at most once, and zero times is possible. It does not mean the provider stored the charge.
A worker finishes a Stripe charge, then crashes before Temporal records the activity result. Temporal retries the activity. Stripe receives a second charge. Replay did not cause that. The missing completion event did.
This post separates durable replay from provider-side idempotency, and shows which problem you still have to solve yourself.
What Temporal actually does on replay
A Temporal workflow is deterministic code plus an event history. The workflow docs say that on resume, Temporal runs the workflow code again and feeds it the recorded history. Completed activities are not executed again. Their recorded result is reused. Timers do not wait again. A network call you made inside workflow code, outside an activity, can return something new and break replay. API calls belong in activities.
Activity docs say you should make activities idempotent because they can run more than once. Completed activities are not re-executed on replay. An activity that succeeds and then fails to report that success is retried, because the history never got the completion. The whole activity runs again, including every side effect inside it.
Retry policies say workflows do not retry by default. Activities do. Temporal's idempotency post says the default is at least once, because activity retries are unlimited unless you set maximumAttempts to 1. That setting is at most once, and zero times is also possible if the attempt never lands.
Replay is a memory trick for the workflow. It is not a promise that Stripe stored your key.
Where durable replay wins
Use Temporal when the job is a long process that must continue after a crash. Sequence steps, wait on a signal, compensate a failure, and keep the history for years if you must. Durable execution platforms compares that category.
You want Temporal when the bug is "the worker died in the middle and I need the same decisions again." You do not want it as a substitute for the provider's idempotency key. Temporal will happily retry an activity that charges a card, and it will tell you to make that activity safe.
Where the provider key still matters
If the activity calls a provider that stores an idempotency key, send the same key on every attempt. Derive it from the workflow run and the activity id, which stay stable across retries. If the provider does not store a key, Temporal cannot invent that storage. A second attempt can create a second charge.
Swytchcode is the check on that outbound call, not a workflow history. POST and PATCH retries need an idempotency key set on the call. Do not treat every exec as exactly once. A policy can still block the call before it is sent. On the October 2026 pricing page, allow and deny are on every plan. Approval starts on Business. Policy as code is the rule file. Use Temporal to resume the process. Use the provider key, and a policy, so a resumed activity does not double the side effect.
Split the activity if it does more than one side effect. Temporal's activity guide uses the example of a lookup, a remote call, and a file write in one function. If the file write fails, the retry repeats the remote call. Three smaller activities record three results. The remote call, once completed, is not repeated on replay. You still send the provider key, because the completion report can be lost. Smaller activities make a longer history, which Temporal warns you about. That trade is worth it for a charge. It is wasteful for a read you can repeat safely. Do the charge in its own activity. Leave the harmless read coarser if you want a shorter history.
Keep the key stable across attempts
Follow this step to install the CLI. Use one of these.
npm install -g swytchcodeirm https://cli.swytchcode.com/install.ps1 | iexcurl -fsSL https://cli.swytchcode.com/install.sh | shConfirm the install, then start the project.
swy --version
swy initSearch the registry for the provider the activity calls. Copy the ID from the local list, then check whether the input has an idempotency field. Add that ID only. Pass the same idempotency value on every attempt of that activity.
swy search <provider>
swy get <name from search>
swy list methods
swy info <canonical_id from swy list methods>
swy add <canonical_id from swy list methods>Connect the provider. There is no .env file in this project. Swytchcode keeps credentials in its own local store and reads them when a call runs. Validate the policy if a field such as amount must stay under a cap.
swy auth connect <provider>
swy policy validatePut the long wait and the crash recovery in Temporal. Put a stable provider key, and a block rule, on the activity that spends money. Replay reuses a completed activity result. It does not store the charge at the provider.
Related reading
- Durable execution platforms. Resume after a crash is its own category.
- Policy as code. A cap still applies on the retry, not only on the first attempt.
- Log every API call an agent makes. History events and provider responses are different records.
- Human approval. A replay should not skip a hold you already required.
FAQ
Does Temporal replay run my API call again?
No. A completed activity's result is read from history. The activity function does not run again during replay. An activity that never reported completion can still be retried, and that retry does call the provider again.
Does setting maximumAttempts to 1 make the charge exactly once?
Temporal's own post says that setting is at most once, and zero times is possible. It does not mean the provider committed the charge. If you need the provider to collapse duplicates, send the provider's idempotency key.
Do workflows retry when an activity keeps failing?
Workflow executions do not retry by default. Activities do, unless you change the retry policy. Retry the activity. Do not restart the whole workflow to "try the charge again." That can schedule a new activity with a new identity.
Should an agent call Temporal or call the provider?
Call Temporal when you need the process to survive a crash and continue. Call the provider, through an allowlist, for the one request inside an activity. The workflow history does not review the amount on that request.
More content
Tray.ai alternatives when agents change permissions
Tray.ai exposes connector operations as MCP tools an admin can open or close. Here is who reviews that change, and what to use when the model picks the call.
Best tools for HR and recruiting AI agents in 2026
An HR agent can write an offer or send a rejection on its own. Compare five tools on candidate PII, blocked writes, and who must approve the change.
Kong alternatives when agent calls leave the gateway
Kong governs traffic that hits a Kong route, including LLM, MCP, and agent-to-agent calls. A direct provider call from the agent never enters that route.
