# Approval, handoff and recovery patterns for AI agents.

> 17 human approval, handoff and recovery patterns for AI agent workflows, each with its intent, when to use it, how it fails and a public example.

Published: 2026-10-08  
Updated: 2026-10-08  
Changelog: 2026-10-08: New guide.  
Canonical: https://agentexperience.tech/insights/approval-handoff-recovery-patterns/  
Tags: delegated action, workflows, recovery, permissions, patterns

**Summary**

This is a pattern library for the human-control side of agent workflows: 9 approval patterns, 3 handoff patterns and 5 recovery patterns, each with its intent, when to use it, how it fails, and a public example checked on 8 October 2026. The library also names two failure modes from 2026 preprints, approval laundering and residual authority. Two ideas run through it: an approval counts only when a known person decided on the exact action that runs, and a failure is useful only when it tells the agent its next move.

1. A human approval workflow is made of several small patterns: approve the plan, set allow, ask or never rules, bind the approval to what executes, and check who is approving.
2. Confirmation is not approval: a client can answer a confirmation prompt automatically, so record whether a known person decided.
3. Keep secrets and consent away from the model: secrets go into a trusted page, and consent failures go to the person as a redirect, not to the model as an error.
4. A handoff carries a small context packet and the reason for the work, and hands back any step the agent should not take.
5. Recovery depends on idempotency keys, checking state before a retry, errors and refusals that name the next step, and exit codes that tell the truth.
6. Design against approval laundering, where the record misses side effects, and residual authority, where an old approval is reused in a new context.

Most of the human side of agent work comes down to a few recurring moments: a person approves something, takes over something, or helps the run recover. Each moment has patterns that work and ways they fail.

**A human approval workflow for AI agents is made of small, reusable patterns: how a person approves, how work changes hands, and how a run recovers when a step fails.** This library names 17 of them, plus two failure modes to design against. Each pattern has the same four parts: its intent, when to use it, how it fails, and a public example. The examples describe documented behaviour of public products and open-source projects as checked on 8 October 2026; products change often, so treat each one as an illustration of the pattern, not an endorsement or a ranking. Where a finding comes from a research paper, the guide says so and gives the paper's own figures with their scope.

For the reasoning behind approval design itself, start with [Human approval workflows for AI agents](/insights/approval-is-a-workflow/). This page is the catalogue that goes with it.

## The patterns at a glance

| # | Pattern | Family | In one line |
| --- | --- | --- | --- |
| 1 | Approve the plan, gate the exceptions | Approval | One approval for the shape of the work; a stop for anything outside it |
| 2 | Allow, ask or never | Approval | Standing rules decide which actions run, stop or never run |
| 3 | Approve what executes | Approval | The person approves the exact operation, and only that runs |
| 4 | Only the requester approves | Approval | The person who asked is the person who approves |
| 5 | Enter secrets out of band | Approval | Secret values go into a trusted page, never through the model |
| 6 | Send consent to the person | Approval | A missing grant becomes a redirect for the person, not an error for the model |
| 7 | Approve per origin or scope | Approval | Approve where the agent may act, and say what that does not cover |
| 8 | Confirmation is not approval | Approval | Record whether a known person decided, or only a client said yes |
| 9 | Pause, hand over, resume | Approval | A named waiting state, then the same run continues |
| 10 | Send a context packet | Handoff | A small structured record instead of a transcript |
| 11 | Return the reason for the work | Handoff | Every handoff and approval carries why, as a field |
| 12 | Hand back the step | Handoff | Prepare the step a person must take, and hand it over read-only |
| 13 | Idempotency keys | Recovery | One key per intent, reused on every retry |
| 14 | Verify before retry | Recovery | Check what happened before repeating a side effect |
| 15 | Errors that name the next step | Recovery | The failure carries the move that fixes it |
| 16 | Exit codes that tell the truth | Recovery | Exit status says whether the promised outcome was achieved |
| 17 | Refusals that name the missing permission | Recovery | A refusal lists the permission that would make the call succeed |

![Where the patterns apply in a run, in six moments from top to bottom. 1. Before the run: approve the plan; allow, ask or never. 2. At a step that matters, highlighted: approve what executes; only the requester approves; secrets go out of band. 3. When the agent needs a person: pause and resume; send consent to the person; approve per origin. 4. When a step fails: errors name the next step; refusals name the permission; exit codes tell the truth. 5. Before a retry: verify first; reuse the idempotency key. 6. At a handoff: a context packet; the reason for the work; hand back the step. Below them, in a dashed box, the failure modes to design against: approval laundering, residual authority, and a confirmation taken for approval.](https://agentexperience.tech/diagrams/approval-handoff-recovery-patterns.svg)

*Figure: Where each pattern applies in a run, and the failure modes to design against.*

## Approval patterns

### 1. Approve the plan, gate the exceptions

**Intent.** Let a person approve the shape of the work once, instead of every step, and still stop for anything that falls outside it.

**Use when.** The task has many low-risk steps and a few consequential ones, and the plan can be written down before the work starts.

**How it fails.** Plan approval quietly becomes approval for everything that follows, including steps the plan never mentioned. A 2026 preprint by [Salerno and colleagues](https://arxiv.org/abs/2610.06047), based on interviews with 18 practitioners and a survey of 115, recommends that permission systems separate what an agent is allowed to do from what the user intended, and separate rejecting one action from rejecting the whole approach. A plan approval meets both only if steps outside the plan still stop.

**Public example.** Anthropic's Claude Code has a [plan mode](https://code.claude.com/docs/en/permissions) in which the agent reads files and runs read-only commands but does not edit source files, so a person can review a plan before any change. Its manual mode asks before each action that needs approval.

### 2. Allow, ask or never

**Intent.** Decide in advance, by rule, which actions run without asking, which stop for a person, and which never run.

**Use when.** The same kinds of action recur and a person can name them, such as "run the tests" or "push to the main branch".

**How it fails.** People keep choosing "ask", so the rules settle little and approvals become routine. In a preprint by [Ting Yan](https://arxiv.org/abs/2608.27443) (August 2026), 113 participants without software backgrounds supervised a simulated day of 18 agent actions, seven of which went beyond what was asked. Participants who wrote their own allow, ask or never rules set 114 of their 140 rules to "ask", and that condition blocked 20.1 percentage points less overreach than approving each action separately; of the 148 overreaching actions that ran under the rules, 133 ran after a person approved them. These are the paper's figures for one simulated setting with one participant pool. The useful finding is that many actions outside the original request went through after people approved them, so an "ask" should show what falls outside the request.

**Public example.** Claude Code's [permission rules](https://code.claude.com/docs/en/permissions) come in three kinds, allow, ask and deny, and are evaluated in a fixed order: deny first, then ask, then allow, with the first match deciding.

### 3. Approve what executes

**Intent.** The person approves the exact operation, shown from the call itself, and the system runs that operation and nothing else.

**Use when.** The action spends money, sends something, deletes something, publishes, or widens access.

**How it fails.** The approval screen shows the agent's own summary rather than the call, or the pending call changes after the person approves it. Both failures, and the preprints that demonstrate them, are covered in [Bind the approval to what executes](/insights/approval-is-a-workflow/).

**Public example.** Stripe's [Link agent wallet](https://docs.stripe.com/agentic-commerce/agents/link-agent-wallet/use-link-wallet-pay-online) has the agent create a spend request for a specific amount and seller, with a description of at least 100 characters that the customer reads when deciding. The customer approves on the Link website or app, which the agent does not control, and Link then issues a one-time payment credential for that purchase. A request that is not answered within 10 minutes expires.

### 4. Only the requester approves

**Intent.** The person whose request started an action is the person who approves it.

**Use when.** Agents work in shared spaces, such as a team chat thread, where several people can see an approval button.

**How it fails.** Anyone in the thread can approve, so one person can run a tool under another person's request. The opposite failure is a rule so strict that a legitimate second approver, such as a manager, has no way to be named.

**Public example.** Vercel's open-source agent framework eve changed this in [version 0.72.0](https://github.com/vercel/eve/releases/tag/eve%400.72.0) (7 October 2026). Approvals without a response policy can now be approved or cancelled only by the person whose turn requested the call, so a shared thread no longer lets someone else run a tool under the requester's turn. Tools that need other approvers declare them in an `approval.response` policy.

### 5. Enter secrets out of band

**Intent.** A secret value never passes through the model. The person types it into a trusted page, and the agent only ever handles its name.

**Use when.** An agent needs to set an API key, a password or a token.

**How it fails.** The client cannot open the trusted page, so the agent asks the person to paste the secret into the chat, where it ends up in the transcript and the logs.

**Public example.** Supabase's [MCP server](https://supabase.com/docs/guides/ai-tools/mcp#elicitations) has a tool, `create_edge_function_secret`, that asks for the secret's name and project but not its value. The value is entered in the Supabase Dashboard through a URL handoff, and the documentation says secret values belong only there, never in chat, model input or tool arguments. The tool is offered only when the client supports that kind of handoff. Stripe's Link documentation makes a related point for card details: hosted agents should write them to a file rather than print them, where they can persist in transcripts and logs.

### 6. Send consent to the person, not the model

**Intent.** When a person must grant access, the request reaches them as a redirect or a prompt, not the model as an error message.

**Use when.** An agent connects to a service on a person's behalf through OAuth.

**How it fails.** The missing grant shows up inside a tool result. The model reads it as an error to work around, and may retry, switch tools or give the person a vague explanation.

**Public example.** Vercel's [Connect integration for TanStack AI](https://vercel.com/changelog/vercel-connect-tanstack-ai) (24 September 2026) fails client creation with a consent challenge before the model runs, and the application redirects the person to the consent page. Vercel gives the reason directly: otherwise a consent error raised within a tool call would reach the model as an error string rather than the user as a redirect.

### 7. Approve per origin or scope, and say what it does not cover

**Intent.** Approve where the agent may act, such as a website or a project, separately from what it does there.

**Use when.** Approving every action would mean a prompt every few seconds, as in browsing.

**How it fails.** A person reads approval of a place as approval of every action in it.

**Public example.** OpenAI's [computer use tool in the Agents API](https://developers.openai.com/api/docs/guides/agents-api/tools/computer-use) requires the user's approval before the browser accesses each new website origin, including public sites. The documentation is explicit about the limit: origin approval does not enforce confirmation before individual actions. If an application must guarantee confirmation before purchases or destructive changes, it should restrict the hosted browser or use a browser runtime it controls, because asking through a function tool relies on the agent choosing to call it.

### 8. Confirmation is not approval

**Intent.** Keep two things apart in the record: a client said yes, and a known person decided.

**Use when.** Your system receives yes or no answers from a protocol prompt, a command-line prompt or an "are you sure?" dialog.

**How it fails.** The server logs every yes as a person's approval, when some of them came from a hook, a rule or an automatic answer.

**Public example.** Supabase's [MCP documentation](https://supabase.com/docs/guides/ai-tools/mcp#elicitations) asks for confirmation before creating paid projects and before destructive SQL, using the protocol's elicitation feature. It says plainly that this is separate from the client's own approval of tool calls, that some clients support hooks or rules that answer elicitations automatically, and that the prompts are a guardrail rather than a guarantee of human review. Users can also switch them off per tool with `skip_elicitations`. Where an approval must be real, collect it on a surface the agent cannot answer, as Stripe does with the Link app in pattern 3, and record which kind of yes you received.

### 9. Pause, hand over, resume

**Intent.** The agent stops in a named waiting state, a person does what only they can do, and the same run continues.

**Use when.** A run meets a one-time code, a sign-in, a CAPTCHA or a judgement call partway through.

**How it fails.** The pause loses the run's state, so resuming means starting again. Or the person's input travels back through the transcript: a one-time code typed into a resume message becomes part of the run's text and its logs. A short life does not undo that, so have the person enter codes and passwords on a protected page instead (pattern 5).

**Public example.** Browserbase [added pause and resume for agents](https://www.browserbase.com/changelog/pause-and-resume-for-agents) on 24 September 2026. A run takes a plain-language `pauseWhen` condition, such as a verification code being required; the agent enters a `PAUSED` state when it is met, and a follow-up task resumes the same browser session.

## Handoff patterns

### 10. Send a context packet, not a transcript

**Intent.** The next actor receives a small, structured record: the intent, the constraints, what has already changed, the authority used, the evidence, and the open question.

**Use when.** Work passes from an agent to a person, to another agent or to a sub-agent.

**How it fails.** Either the whole transcript is passed on, so the receiver has to dig through it and private detail travels with it, or nothing is passed on and the receiver starts again.

**Public example.** In OpenAI's [Agents SDK](https://openai.github.io/openai-agents-python/handoffs/), a new agent sees the entire previous conversation by default, and an `input_filter` changes what history it receives. The fields worth putting in the packet are set out in [An agent context handoff should carry the reason for the work](/insights/preserve-context-through-handoffs/).

### 11. Return the reason for the work

**Intent.** Every handoff and every approval request carries why the work is happening, in a field the receiver can read and the system can store.

**Use when.** Escalations, approvals and purchases, or anywhere a person will be asked to judge a proposal.

**How it fails.** The reason lives only in the transcript, is lost at the boundary, or is written after the fact to justify what already happened.

**Public example.** The same Agents SDK lets a handoff declare an `input_type`; its documentation shows an escalation that carries a `reason`, validated and passed to a callback for logging, and suggests small fields such as reason, priority or summary. Stripe's Link spend request in pattern 3 makes the reason mandatory: the agent must state what it is buying and why, and that is the text the customer reads.

### 12. Hand back the step the agent should not take

**Intent.** When the next step belongs to a person, the agent prepares it and hands it over in a read-only form, rather than attempting it or stopping without saying why.

**Use when.** Production deployments, DNS changes, claiming an account, accepting terms, or any interactive wizard.

**How it fails.** The agent starts an interactive command and hangs on a prompt, or reports the task as done without saying that the last step is still open.

**Public example.** Clerk's [accountless set-up post](https://clerk.com/blog/accountless-setup-clerk-init-nextjs) (30 September 2026) leaves two steps to the person: claiming the app, and running `clerk deploy`, an interactive wizard for the production instance, its DNS records and its OAuth providers. Clerk says that, as a result, an agent gets a read-only handoff from it rather than a deploy. The wider pattern is described in [Let agents start before anyone signs up](/insights/let-agents-start-before-sign-up/).

## Recovery patterns

### 13. Idempotency keys

**Intent.** Let a client repeat a write without repeating its effect.

**Use when.** Any create or update with a side effect, especially money, messages and provisioning.

**How it fails.** A new key is generated for each retry, which defeats the point; the same key is reused for a different intent; or the retry arrives after the server has forgotten the key.

**Public example.** Stripe's API [stores the status code and body of the first request](https://docs.stripe.com/api/idempotent_requests) made with each idempotency key and returns the same result to later requests with that key, including server errors. It compares the parameters of a repeated request with the original and returns an error if they differ, and keys can be removed once they are at least 24 hours old. Stripe's Link documentation applies the same idea to agents: give each spend request a key that represents that purchase intent, so the agent can retry safely.

### 14. Verify before retry

**Intent.** After a timeout or an unclear result, find out what actually happened before repeating anything with a side effect.

**Use when.** Timeouts, dropped connections, crashed workers and any response the agent cannot interpret.

**How it fails.** A timeout is read as "nothing happened", and the side effect runs twice.

**Public example.** OpenAI's computer use guide tells developers to wait for the agent's turn to finish and verify its result, and, if the connection drops, to recover the same session before retrying. The site's synthetic [worked example on timeout recovery](/examples/timeout-recovery-verify-before-retry/) walks through the decision step by step, and [Agent error recovery belongs on the main path](/insights/design-for-recovery/) explains the correlation key that makes the check possible.

### 15. Errors that name the next step

**Intent.** A failure carries the move that would fix it, in a form the agent can act on.

**Use when.** Always, but most of all where the fix needs a person, a different input or a different route.

**How it fails.** The hint is prose that only a person can follow, or it names a command, flag or page that no longer exists.

**Public example.** Stripe's Link agent wallet returns a `next_action` block when a spend request needs attention. It includes a `resolution` with a closed set of values: resume automatically after the customer acts, create a new request, or create a new request after the customer finishes the action at a given URL. The documentation tells agents to branch on the resolution rather than the type. Vercel's [Sandbox CLI 4.0.1](https://vercel.com/changelog/the-vercel-sandbox-cli-is-now-more-agent-friendly) (August 2026) changed its not-found error to suggest the command that lists existing sandboxes, so each message carries the action to take next. Neon's claimable project errors include a `retryable` field and say to retry only when it is true.

### 16. Exit codes that tell the truth

**Intent.** A command's exit status says whether it achieved the outcome it promises.

**Use when.** Any command-line tool an agent might run.

**How it fails.** A command that failed, was refused or cancelled the requested change exits with status 0, and the agent, which often reads the exit code as its main signal, reports success. The opposite mistake is to treat every empty result as a failure. A search that finds nothing, or a change that was already in place, can exit 0 if the command's contract counts it as success, as long as the output says so plainly.

**Public example.** The [Command Line Interface Guidelines](https://clig.dev/) state the rule: return zero on success and non-zero on failure, because scripts rely on it. Cloudflare's new `cf` command-line tool, which is in beta, documents the gap in its own [guide for coding agents](https://developers.cloudflare.com/cf/agents/): in a non-interactive session, a destructive command run without `--force` prints `Aborted.` to standard error, makes no change and exits with status 0. The documentation warns that a successful exit does not mean the resource was deleted. An agent working with that tool has to read standard error as well as the exit code; a tool designed for agents would exit non-zero when the requested change did not happen.

### 17. Refusals that name the missing permission

**Intent.** A refusal says exactly which permission would make the call succeed.

**Use when.** Any API, tool or command that checks scopes or roles.

**How it fails.** A bare "forbidden" leaves the agent to retry, try other tools, or ask the person for a broader token than the task needs.

**Public example.** Supabase made scoped personal access tokens generally available on [6 October 2026](https://supabase.com/changelog/scoped-personal-access-tokens-ga). When a token lacks a permission, the Management API's 403 response lists the missing ones in a `missing_permissions` array; each MCP tool checks the token's permissions, and the dashboard shows which tools a token can call. A token's access cannot be changed after creation, so the fix is a new, correctly scoped token rather than a wider one. Neon's claimable projects return `scope_insufficient` and `capability_requires_claim`, two different refusals for two different fixes.

## Failure modes to design against

Two recent preprints name failures that the approval patterns above do not prevent on their own. Both terms come from the papers, not from any standard. The figures are the papers' own, from their own test sets, and have not been reproduced here.

### Approval laundering

[Agent Approval Laundering](https://arxiv.org/abs/2609.28586) by Jinqian Zhang and colleagues (preprint, 23 September 2026) describes an approval record that names the command or tool call a person approved but leaves out the effects of the workflow that call sets off. A package installation can run its own lifecycle scripts and write files; a tool call can use network access. The person approved something real, but the record does not cover everything that ran under it. Across 111 fixed pairs of approval records and execution traces, the paper reports that records missing some effect fell from 40 when only explicit fields were used, to 17 with knowledge of what commands do, to 13 with metadata available at decision time: better records narrow the gap without closing it. Its proposed remedy is to bind each invocation, before authorisation, to a prediction of the effects its workflow can have, and to keep that prediction with the decision.

**Design response.** Show known side effects on the approval card, not just the command, and store them with the decision.

### Residual authority

[When Consent Outlives Context](https://arxiv.org/abs/2609.33910) by Zhihao Zhang and colleagues (preprint, 27 September 2026) describes approvals that persist across tasks or sessions and can be reused later without fresh consent, after the context that justified them has gone. The paper reports that, with this residual authority in place, attack success rose by up to 35.1 percentage points across 508 attack cases from the AgentDojo benchmark and six model families, and by 24.9 points on average across 55 live Terminal-Bench cases on three production coding agents.

**Design response.** Give approvals an expiry, tie them to the task that justified them, and treat "do not ask again" as a standing grant that someone should review.

A third failure, Loopjacking, where the approved operation is swapped or misdescribed, is covered in [Human approval workflows for AI agents](/insights/approval-is-a-workflow/).

## A worked example

This example is invented. Ledgerline is not a real product, and the steps describe no real API.

Tomás runs a bakery. He asks his agent to pay a supplier's invoice of £1,240 through Ledgerline, his payments app.

1. **Allow, ask or never (2).** Tomás's rules say payments are "ask", so the agent prepares the payment and stops.
2. **Approve what executes (3) and the reason for the work (11).** The agent creates a payment request with the payee, the amount, the invoice number and its reason: "Invoice 4471 from Hillside Flour, due Friday, matches the delivery note of 2 October." Ledgerline renders the approval card from the request itself and shows it in Tomás's app.
3. **Only the requester approves (4).** The request was Tomás's, so only Tomás can approve it, even though his business partner can see the same thread.
4. **Errors that name the next step (15) and pause, hand over, resume (9).** The bank asks for strong authentication. Ledgerline returns a next action with a link for Tomás and a resolution of "resume automatically". The agent pauses, Tomás completes the check, and the same request continues.
5. **Idempotency keys (13) and verify before retry (14).** The payment call times out. The agent does not send a new payment. It looks up the payment by its idempotency key, finds it went through, and records the result.
6. **Send a context packet (10).** The agent hands the bookkeeping to Tomás's bookkeeper with a short record: what was paid, the reference, the reason, and one open question about which cost category to use.

At no point did the agent hold Tomás's bank credentials, guess whether the payment had gone through, or ask Tomás to approve something other than the payment that ran.

## Where to start

Take one consequential action in your product, such as a payment, a deletion or an outbound message, and walk it through the six moments in the map above. For each moment, ask whether the matching pattern is present, partly present or missing. Then fix the first missing pattern on the path, not the most interesting one.

If you use the [Open Agent-Readiness Rubric](/insights/agent-readiness-rubric/) (v0.3), the patterns line up with its checks. Pattern 3 is the substance of [Your system enforces approval](/insights/agent-readiness-rubric/#act-02): approval enforced by your system and bound to the exact action. Patterns 4 and 8 are [Approval comes from the person](/insights/agent-readiness-rubric/#handback-05): an approval counts only when a person your policy allows gave it, through a route the agent cannot operate. Pattern 5 is [Secrets never pass through the agent](/insights/agent-readiness-rubric/#bound-05). Pattern 13 is [Writes are safe to retry](/insights/agent-readiness-rubric/#act-03). Patterns 5, 6 and 17 support [Agent access can be narrow](/insights/agent-readiness-rubric/#act-05), which asks for narrow and revocable access. Patterns 14 and 15 cover the checks from [Errors carry a fixed code](/insights/agent-readiness-rubric/#recover-01) to [The agent can check what happened](/insights/agent-readiness-rubric/#recover-03), pattern 17 is [Refusals name the missing permission](/insights/agent-readiness-rubric/#recover-05), and pattern 16 is [Command-line tools report the real outcome](/insights/agent-readiness-rubric/#recover-06). Pattern 8 also serves [Agents are told apart from people](/insights/agent-readiness-rubric/#handback-03), and patterns 1 and 2 serve [Approvals are few and show the real action](/insights/agent-readiness-rubric/#handback-04). Recovery that keeps a record of each attempt is the subject of [Record agent retries as product history](/insights/retries-are-product-history/).

## Frequently asked questions

**What is human-in-the-loop authorisation for AI agents?**
Human-in-the-loop authorisation is the point in an agent run where a person grants or refuses the authority for a specific action the agent has proposed. It only works as a control when three things hold: the person sees the exact action that will run, the system knows which person decided, and the approval cannot be reused later for something else. A confirmation prompt that a client can answer automatically does not meet that bar.

**How do you add a human in the loop to an AI agent?**
Decide in your system which actions need a person, usually by effect: spending, sending, deleting, publishing and widening access. At those points, pause the run in a named waiting state, show the person the real action and the reason for it, accept approve, change, ask or reject, and resume the same run from their answer. Keep secrets and consent on surfaces the agent cannot read or answer, and give approvals an expiry.

**What is the difference between confirmation and approval?**
A confirmation is any yes the system received; an approval is a decision a known person made about a specific action. The two often look the same to a server. Supabase's MCP documentation warns that some clients answer its confirmation prompts automatically through hooks or rules, so it treats them as a guardrail rather than proof of human review. Record which of the two you received, and collect real approval on a surface the agent cannot answer.

**Should an AI agent ask for approval before every action?**
No. Asking for everything trains people to click yes. Approve the plan once, set standing rules for routine actions, and stop only for actions that are consequential or outside the original request. Be aware that standing rules do not remove the decision: in a 2026 preprint study, participants who wrote allow, ask or never rules chose ask for most of them, and many out-of-scope actions still ran after a person approved them.

**What is approval laundering?**
Approval laundering is a term from a September 2026 preprint by Zhang and colleagues. It describes an approval record that names the command or tool call a person approved but leaves out the effects that call sets off, such as a package installation that runs its own scripts and writes files. The person approved something real, but the record does not cover everything that happened under that approval.

**Why do AI agents need idempotency keys?**
Because agents retry, and a retry after a timeout can repeat a side effect such as a payment. An idempotency key is a value the client sends with a write so the server can recognise a repeat. Stripe's API stores the result of the first request for each key and returns the same result to later requests with that key, and rejects a reused key whose parameters differ. Use one key per intent and reuse it on every retry of that intent.

Pick one consequential action in your product and walk it through the six moments in the map. The missing pattern is usually easy to spot.
