ADACTION
DOCK

ACTIONDOCK FIELD NOTES

AI Agent API Retries: Idempotency and Unknown Outcomes

Learn when an AI agent can retry an API write, what an idempotency key protects, and how to reconcile execution_unknown without duplicate side effects.

Repeated request pulses converging into one durable job before a hazy unknown-outcome boundary.

The direct answer

An AI agent should retry an ActionDock submission only with the same idempotency key and the same action input. That protects the submission to ActionDock: if the first request created a job but the client missed the response, the repeated request resolves to that existing job instead of creating another one.

That key does not make the external API operation exactly once. ActionDock consumes the key at its own boundary and does not forward it as a provider idempotency key. If the provider might have accepted a write but ActionDock cannot establish the outcome, the job ends in execution_unknown. The safe response is to stop, inspect the provider’s state, and reconcile it before anyone submits another write.

This distinction matters because one agent action crosses several separate boundaries:

  1. The agent submits intent to ActionDock.
  2. ActionDock creates one durable job and, for a side effect, waits for owner approval.
  3. ActionDock sends the approved request to the provider.
  4. The provider changes—or does not change—its own state.
  5. ActionDock receives—or fails to receive—a usable response.

An ActionDock idempotency key covers step 1. A provider-specific idempotency mechanism, when available, covers a different boundary at steps 3 and 4. Reconciliation handles the remaining uncertainty at step 5.

For the wider transaction boundary around policy, credentials, and evidence, start with the first safe AI-agent API write. For the decision before execution, read human-in-the-loop approval for AI agents.

What idempotency means—and what it does not mean

RFC 9110, section 9.2.2, defines an HTTP method as idempotent when multiple identical requests have the same intended server effect as one request. It identifies safe methods, PUT, and DELETE as idempotent by defined semantics. It also warns clients not to retry a non-idempotent method automatically unless they know its semantics are idempotent or can establish that the first request was not applied.

That HTTP property is not a universal duplicate-prevention guarantee. A nominally identical POST might create two invoices, send two messages, or append two records. Even a PUT can trigger secondary behavior outside its intended resource effect. Safe retry therefore depends on the contract of the system that receives the request, not on wishful interpretation of a timeout.

ActionDock adds a durable submission contract. Within a workspace, a repeated key with the same action and parsed input returns the existing job. Reusing the key for a different action or input produces an idempotency conflict instead of silently combining two intentions. The job retains its current state, whether that is awaiting_approval, running, succeeded, failed, or execution_unknown.

Use a stable, opaque value for one logical submission. Do not generate a fresh key for every transport attempt: that turns retries into new jobs. Do not reuse one key for a later business operation, even when its JSON happens to look identical.

Retry decision table

What you observe What it establishes Safe next action
The client times out before receiving ActionDock’s 202 response The submission may or may not have created a job Repeat the exact ActionDock request with the same key. If the job exists, ActionDock returns it.
awaiting_approval One job exists, but the external write has not been released Do not resubmit. Let the signed-in owner approve or reject the exact preview.
queued or running The existing job is still progressing Poll GET /v1/jobs/{id} or wait for the signed callback. Do not create another job.
succeeded ActionDock received a usable successful response and recorded it Do not retry. Use the receipt as evidence of what ActionDock observed, then verify any business outcome that matters.
failed ActionDock recorded a definite failure, but the reason still determines recovery Inspect the error and receipt. Correct the cause; create a new logical submission and key only when a new attempt is justified.
rejected The owner declined the proposed write Stop. A later attempt needs new intent and a new approval, not a replay.
execution_unknown The provider may have applied the write, but ActionDock cannot prove either outcome Block blind retry. Reconcile provider state before deciding whether a new submission is safe.

Repeating a key is not the same as rerunning the external call. For example, repeating the original submission after it reaches execution_unknown returns that same terminal job. Generating a new key creates the possibility of a second external effect, which is precisely why reconciliation must come first.

Why an ambiguous write cannot be treated as a normal failure

Consider an approved PATCH that changes a CRM account. The provider accepts the bytes, commits the change, and then the connection closes before ActionDock receives a response. From the gateway’s point of view, two realities are possible:

A blind retry is correct in one reality and harmful in the other. ActionDock therefore does not guess. A transport error on an external write, or an ambiguous provider response, can produce execution_unknown; automatic retry stays suppressed.

This is the same distributed-systems problem described in AWS’s Making retries safe with idempotent APIs. AWS explains why a timeout can force the caller to determine whether a resource already exists, and why caller-provided request identifiers make retry intent explicit. The important condition is that the receiving service must understand that identifier.

Stripe demonstrates the provider side of that contract in its idempotent requests documentation. Stripe records the first result associated with a key and returns that result for a repeated request under its documented rules. That behavior works because Stripe itself receives and interprets the key.

ActionDock’s submission key is not forwarded as a Stripe key, an AWS client token, or another provider-specific mechanism. Never infer downstream protection from the presence of Idempotency-Key on the ActionDock request. If an external API needs its own idempotency token, treat that as a separate provider integration requirement and verify the provider’s exact semantics, retention period, parameter matching, and error behavior.

Reconciliation checklist for execution_unknown

Use a read-first process. The objective is to establish external state without creating another side effect.

  1. Freeze the write. Keep the original job ID and idempotency key. Disable workflow logic that could submit a new key automatically.
  2. Inspect the approved request. Confirm the connection version, resolved destination, method, path, query, and body that the owner approved.
  3. Read the execution evidence. Review timestamps, job events, the recorded provider status and safe response fields, and the error that caused ambiguity. An ActionDock receipt says what ActionDock observed; it is not independent proof of the provider’s final business state.
  4. Identify a provider-side correlation value. Prefer a non-sensitive business identifier already present in the approved request, a provider request ID from the receipt, or a provider-native idempotency token when the integration actually used one.
  5. Query the provider without writing. Use a read-only API, provider console, or another authoritative system of record. Check for the intended object, its version, and the exact field values—not merely a similar object name.
  6. Classify the result. Record one of four findings: applied as intended, not applied, partially applied, or still indeterminate.
  7. Choose an explicit recovery. If applied, do not replay. If not applied, an operator may authorize a new submission with a new ActionDock key. If partially applied, design a separate corrective action and approve its exact payload. If still indeterminate, keep the write blocked and escalate.
  8. Preserve the evidence. Retain the original terminal job, the provider lookup result, the operator’s conclusion, and any new job ID. Do not rewrite an uncertain history into a fictional success.

The durable actions workflow shows how jobs, polling, callbacks, and evidence fit into a longer agent loop. The agent integration guide documents the current statuses and submission behavior.

A practical retry policy for AI agents

Give the agent a small deterministic policy rather than a general instruction to “retry errors”:

  1. Generate one opaque idempotency key for one logical ActionDock submission.
  2. Persist the key before sending the request.
  3. On a client-side timeout before receiving the job, resend the exact request with that same key.
  4. After receiving a job ID, poll that job or wait for its callback; do not resubmit it.
  5. Treat awaiting_approval as a human decision state, not a failure.
  6. Treat succeeded, failed, and rejected as terminal states that require no transport retry.
  7. Treat execution_unknown as a mandatory reconciliation state.
  8. Create a new key only for a genuinely new logical submission or for an explicitly authorized attempt after reconciliation.

This policy is intentionally conservative. It prevents a network retry loop from becoming a business-side duplicate loop while preserving a safe way to recover when only the response from ActionDock was lost.

Frequently asked questions

Does an ActionDock idempotency key guarantee exactly-once execution?

No. It deduplicates the ActionDock submission. It is not forwarded as provider idempotency and cannot guarantee one external effect in an arbitrary API.

Can an agent retry a job in execution_unknown with the same key?

The same key resolves to the existing terminal job; it does not prove the provider state or safely rerun the write. Reconcile the provider first. A new key before reconciliation risks a duplicate effect.

When should an agent create a new idempotency key?

Create one for a new logical submission, including a corrected request or an operator-authorized post-reconciliation attempt. Keep the existing key for transport retries of the exact original submission.