Idempotent AI Agent Actions: Stop Duplicate Invoices and Bookings
Make AI agent write actions safe to retry so a repeated call never creates a second booking, invoice or message. Practical steps, checks and approval rules.

An idempotent agent action is a write that produces the same result no matter how many times the same request is sent. To make an AI agent safe to retry, give every write a stable key tied to the business event, check a ledger before acting, and record the outcome before reporting success. This is what stops a timeout or a repeated tool call from creating a second booking, invoice or message.
Key takeaways
- Retries are normal. A timeout does not tell the agent whether the write happened, so the agent will be tempted to try again.
- Build each key from the business event (customer, service period, slot, order), not from a random identifier generated for each attempt.
- Write a pending record before the call and an outcome record after it. Check that ledger before every write.
- Use the provider's idempotency feature where it exists, and build your own check where it does not.
- Treat messages, payments and bookings as the strictest cases, because a second attempt is visible to a customer or moves money.
Why retries create duplicates in the first place
An agent does not experience a write the way a person does. It sends a request, waits, and receives either a result, an error or nothing at all. If the connection drops after the invoicing system has already saved the invoice, the agent sees a timeout. From its point of view, the action failed, so the reasonable next step is to call the tool again.
The same thing happens in other places. A webhook may be delivered twice. A queue may redeliver a job after a worker restarts. A user may write "try again" in chat because nothing visible changed. Each of these produces a second request that looks like a new instruction. Unless the system remembers the first request, the second one creates a second record. Rate limits and backoff rules decide when retries happen, but they do not decide whether a retry is safe. For that, see AI Agent Rate Limit Handling: Retry, Backoff and Queue Rules.
How do you design the idempotency key?
The key must answer one question: "Is this the same business action as before?" A random identifier generated for each tool call cannot answer that, because every retry gets a new one. A key built from the business event can.
Useful keys combine the fields that define the action. Some examples:
- Invoice: customer identifier, service period and the originating request identifier from the conversation.
- Booking: resource identifier, start time and the requesting customer.
- Message: recipient, template identifier and the triggering event identifier.
- Order update: order identifier, the field being changed and the version you expect to replace.
Keep the key stable across retries and unique across different actions. Store it with the request, not only in the model's context, because context can be trimmed or lost between attempts.
Illustrative scenario: a customer asks in chat to be invoiced for March services. The agent calls the invoicing tool, the request times out after the invoice was created, and the agent retries. Without a key, the customer receives two invoices. With a key built from the customer, the service period and the conversation's request identifier, the second call returns the invoice that already exists.
Use the provider's idempotency feature first
Some business APIs already support idempotency. Stripe, for example, documents idempotent requests: a client sends an idempotency key with a write, and if the same request is repeated with that key, the API returns the saved result instead of performing the action again. The provider stores the result for the key, so the retry is harmless. Read the vendor's documentation for three things: whether the feature exists for the exact endpoint you use, how long keys are honored, and whether a retry with the same key but different parameters is rejected. Do not assume that a feature exists for every endpoint of a platform.
Many business systems have no such feature, or support it only for some operations. The check is part of planning. If you are unsure what a system exposes, start with Does Your Software Have an API? A Quick Check Before AI. Where the provider offers a key, pass your business key through it. Where it does not, your own ledger has to do the work.
A retry is safe only when the system can recognize the first attempt.
Build a ledger the agent must check before every write
A ledger is a simple table or document store that records each write attempt, its key, its status and the external identifier returned by the target system. It does not need to be complicated. It does need to be read before every write and written at the right moments.
A practical sequence for each write:
- Step 1: Compute the business key from the event data, before calling any tool.
- Step 2: Look up the key in the ledger.
- Step 3: If the status is succeeded, return the stored result and do not call the tool again.
- Step 4: If the status is pending or unknown, do not call the tool. Move to reconciliation.
- Step 5: If no record exists, write a pending record with the key, the timestamp and the requesting event, then call the tool.
- Step 6: On success, store the external identifier and mark the record succeeded.
- Step 7: On a clear, definitive error, mark the record failed so a corrected retry is allowed.
Log every step. Logs that record which key was used, what the tool returned and how long the call took make duplicate attempts visible to whoever reviews the system. The OpenTelemetry observability primer describes the general idea of traces, logs and metrics that make distributed behavior inspectable, which is exactly what you need when an agent's retries are the question.
What to do when the outcome is unknown
The hardest case is not a clear success or a clear failure. It is a timeout, a dropped connection or a response that cannot be parsed. The system may or may not have performed the write. The rule should be simple: unknown means look, not repeat.
Reconciliation works like this. Search the target system for the key, if the provider stores it, or for the business fields that define the action: the customer, the period, the slot. If you find a matching record, store its identifier and mark the attempt succeeded. If you find nothing after a defined check, mark it failed and allow a retry. If the search itself fails, keep the record unknown and escalate. An agent that cannot reach the target system should not guess. For the broader recovery pattern, including what the agent should do when access itself has lapsed, read What should an AI agent do when a connection expires?.
Protect messages, payments and bookings differently
The three most common duplicate actions have different consequences, so they need different controls.
- Messages: a second message is visible to the recipient and cannot be recalled. Store a send record for each outgoing message, and require a human review before any resend.
- Payments: a duplicate payment is a financial error. Put a hard amount limit on what the agent can initiate, require approval above that limit, and keep payment writes outside free-form model output. The limits to set first are covered in Can an AI Agent Make Payments? Safe Limits to Set First.
- Bookings: reserve the slot in the ledger before writing to the calendar, so two requests for the same time cannot both succeed.
- Record changes: use version checks, so an update is accepted only if the record still has the version the agent read. A stale retry then fails instead of overwriting newer data.
For each of these, decide in advance whether the agent may act alone, may prepare the action for approval, or may only report what it found. Retry rules and approval rules should be written together, not in separate documents.
Test retries before you trust them
Idempotency is a claim about behavior under failure, so test the failure cases. Useful tests include sending the same request three times in a row and confirming that one record exists. Simulate a timeout after the target system has already saved the write, then confirm that reconciliation finds it and does not create another. Change a single field, such as the service period, and confirm that a new key is produced. Run the same tests in a sandbox before connecting production systems. Recurring evaluations are a standard way to keep these tests meaningful over time; the approach is described in [Anthropic's guidance on demystifying evals for AI agents](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents).
Be Human designs and operates this kind of control as part of a managed service. In a first engagement, the team defines which writes need business keys and ledgers, sets the approval boundaries for messages and payments, and agrees on one observable success criterion, such as zero duplicate records in a defined test set. In ongoing operations, monitoring watches for repeated keys and unknown states, permissions are reviewed as systems change, and incidents are handled with a written reconciliation record. The service is remote, in English and Portuguese, and it does not depend on the client building an internal platform team first.
The first useful step is to list every write your agents could perform and mark which ones could be repeated by accident. The free Be Human AI diagnostic can help you find the first task worth handing to an agent, and the duplicate-safety rules above belong in that decision from the start.
Frequently asked questions
Does idempotency mean the agent can never make a mistake? No. Idempotency prevents one specific failure, which is performing the same write twice because a retry was sent. It does not check whether the write was the right one, whether the amount is correct or whether the customer wanted it. Those questions need approval boundaries, input validation and review.
What if the target system has no idempotency key support? Build the check in your own ledger. Store the business key and the external identifier returned by the system, and read the ledger before every write. Where the system can be searched by business fields, use that search during reconciliation before any retry.
Can I just tell the model not to retry? Instructions help, but they are not a control. A model can lose track of earlier attempts, a timeout can happen outside its view, and a framework may retry automatically. The safety has to live in the tool layer, where the ledger and key check run regardless of what the model decides.
How long should a ledger keep its records? Keep them as long as your reconciliation, audit and dispute needs require, and define that period with the people responsible for finance and operations. The point is that a retry days later can still be recognized. Access to those records should follow the same least-privilege rules as the rest of the agent's data.
Your next step
See where an AI agent fits in your company first.
Take the free Be Human AI diagnostic. A few questions about your work show which task to hand to an agent first, what it needs to know and where a person approves.
Be Human editorial guidance. Examples are illustrative unless explicitly attributed. Sources provide background; implementation choices depend on your workflow.


