Skip to main content

Idempotency

Every write tool — every tool that is not a read — accepts an optional idempotency_key argument. It is sent to the endpoint as the X-Idempotency-Key header the REST API already honours.

{ "name": "dunning_charges_create",
"arguments": {
"person_id": "…",
"original_amount": 1500.00,
"issue_date": "2026-07-10",
"due_date": "2026-08-10",
"idempotency_key": "7c4a8d09-ca37-4f21-b1f0-3d2f2b8c9a11"
} }
FormatOpaque string, 1 to 255 characters. A UUID is the usual choice.
Replay, same bodyReturns the recorded response, without running the operation again.
Replay, different bodyConflict — 409 IDEMPOTENCY_KEY_REUSED, returned as a tool error.

The key is an argument of the tool, not part of the body: it never reaches the endpoint as a field. How keys are stored, for how long and what happens on a conflict is the API's behavior, unchanged — see Idempotency in the API documentation.

Why an agent needs this more than your backend does​

An MCP client that times out and tries again, or a model that decides "I am not sure that worked, let me redo it", is exactly the pattern that creates the second charge, the second agreement and the second debtor. Your backend has a retry loop you wrote; the agent has a judgement call.

Send a key whenever the operation creates something or reaches the outside world. Reads take no key.

:::warning The ones that reach the debtor dunning_charges_notify, dunning_notifications_create and dunning_notifications_resend send a message every time they run, and dunning_webhook_endpoints_test and dunning_webhook_deliveries_retry deliver again — they are marked idempotentHint: false. Reporting to a credit bureau (dunning_negativations_create) and protesting (dunning_protests_create) produce an effect outside Régua de Cobrança that no _delete undoes. Send an idempotency_key on those even when you think you will not repeat. :::

Idempotency and confirmation​

Destructive tools are confirmed by the user before they run — see Confirming destructive tools. The two protections are different: confirmation makes sure a person wanted the action; the key makes sure a retry does not run it twice. A confirmation is single-use, so a re-sent confirmed call is refused (confirmation_replayed) rather than repeated; a new call, confirmed again, with the same idempotency_key and the same body returns the recorded response instead of sending the message a second time.