Series II: From infrastructure to agentic projects in production. Episode 16 of 20.
The fictional B2B portal can be monitored and recovered. What should an agent do after submitting a request without receiving a response? An SME should define a verifiable action contract before giving the agent write access. Retrying must be designed into the service, not left to the model's intuition.
A broken connection does not prove failure
An API, application programming interface, lets a program request data or perform operations in another system. In our hypothetical scenario, the agent integrated into the portal creates a request associated with a document, on an authorized user's behalf. The server saves it, but the connection breaks before the response reaches the agent.
A timeout means the waiting period has expired. A retry repeats an attempt. If the agent immediately sends a new creation request, it may produce two records for the same intent. Not seeing the result does not mean the first operation had no effect.
This ambiguity also appears in Birrell and Nelson's paper on remote procedure calls, published in 1984: a communication error can leave the client uncertain about execution. This is a conceptual reference, not an evaluation of today's agents.
The contract describes one action
We propose a “create request” action, separate from reading, modifying, and approving. Its contract must be understandable to a developer, enforceable by the server, and usable by the agent without guessing rules.
Element | Proposal for the portal |
|---|---|
Inputs | Title, existing documents, and intent identifier |
Identity | User and organization verified by the server |
Preconditions | Documents belong to the organization and are accessible to the user |
Result | Stable request identifier and operation state |
Repetition | The same intent and data create no additional request |
Verification | A read operation exposes state under the same access controls |
We define required fields, length limits, accepted values, and errors. OpenAPI is a standardized format for describing APIs that use HTTP, the web services protocol. Specification 3.2.1 was published on 10 September 2026. We choose the version compatible with the project's tools; a description does not implement validation or security by itself.
The key tracks intent, not the agent's wording
Idempotency means repeating the same operation has the same intended effect as executing it once. It does not require identical logs or responses. RFC 9110 cautions against automatically retrying non-idempotent requests without evidence that repetition is safe. The HTTP POST method, often used for creation, does not provide that guarantee by default.
For the portal, we propose an idempotency key generated before the first attempt and retained for the same intent. After an interruption, the client reuses the key and original data. It does not generate a new key merely because the agent rephrased its explanation. A separate request genuinely wanted by the user receives another key, even if the document and title match.
The server associates the key with the caller, organization, and action and compares relevant data. The same key with different data is rejected as a mismatch. The key is not an authentication secret and must not contain personal data.
In the example, after losing the response, the agent checks the known operation or retries according to the contract. It receives the identifier of the request already created and presents it to the user. If verification is unavailable and retry protection cannot be confirmed, it reports an unknown outcome and requests human verification, without inventing success or failure.
Concurrency and the protection window are explicit
Two attempts may arrive simultaneously. Simply checking “does the key exist?” and then creating the record can let both proceed. We propose a database uniqueness constraint and a transaction, a group of changes committed together or not at all, to record the key, create the request, and save the result.
For an operation still running, the response indicates its state and how to check it without starting another creation. The final result remains linked to the same request. We separate the intent identifier from each attempt's identifier, useful in execution logs.
The contract specifies how long the server retains keys. After expiry, repetition may be treated as a new operation; the client checks the previous result or seeks intervention rather than blindly resubmitting. Stripe API v1 documents saving results after execution begins, including some error responses, and permitting key removal after at least 24 hours. This is that API's policy, not a universal rule for the portal.
External effects need their own protection
A database transaction does not automatically include an email sent by an external provider. We propose durably recording the notification to be sent together with the request, followed by separate, verifiable processing. The service processing notifications must recognize repetitions, while the external integration must prevent duplicates or reconcile outcomes with the actual state.
We do not promise “exactly once” execution across all systems. The defensible boundary is the tested behavior: one request created for the same intent, within the contract's conditions and time window. Notifications and other effects are tracked separately.
We also connect this register to recovery from the previous episode. Restoring an older database can remove evidence of an operation already executed elsewhere. After such an incident, we reconcile states before automatically restarting jobs; a key recorded in a lost copy no longer protects a retry.
Errors should indicate the next step
Responses provide a stable error category, fields needing correction, and the operation identifier, without credentials or sensitive internal details. Invalid data requires correction; missing permissions require stopping or clarification, not continuous retries. An operation accepted for processing is not presented as finished.
For transient errors anticipated by the contract, we use bounded attempts and progressively longer pauses with a small random variation, called jitter, to avoid synchronized retries. We respect Retry-After when supplied and applicable. We also establish when the agent must stop retrying and report uncertainty.
The server limits call frequency and concurrent operations for each client. These limits protect capacity and budget but do not replace duplicate detection.
Authorization stays on the server
The server checks access to each document and request, including when reading a stored result. An organization identifier supplied by an agent does not prove membership. If we use OAuth, an access-delegation mechanism, we restrict tokens to necessary resources and actions, following RFC 9700's guidance.
A dry run is an explicitly designed simulation showing validations and proposed effects without performing the change. It is not built into every API and does not automatically reserve the checked state. For high-impact operations, human confirmation must be bound to the exact data, with conditions rechecked before execution.
Acceptance tests before agent access
We test a response lost after saving, concurrent attempts, one key with changed data, access from another organization, and an expired key. We check request counts and external-effect states, not just success messages. The contract and these tests are the episode's usable outcome.
The development agent can implement the contract; the portal's integrated agent consumes it under a distinct identity. An adapter using MCP (Model Context Protocol) connects tools but does not replace service controls. The next episode checks whether agents can also use the website interface correctly, not just its API.
Sources
Sources checked on 17 October 2026:
- RFC 9110, HTTP Semantics, June 2022, Section 9.2.2, for idempotency and retries.
- Stripe, Idempotent requests, for API v1 policy, keys, results, and expiry; the page distinguishes API v2 behavior.
- AWS Builders' Library, Making retries safe with idempotent APIs, for intent identification and concurrency, and Transactional outbox pattern, for durable notifications and idempotent consumers.
- PostgreSQL 18, Transactions and Unique Constraints, for atomic commits and database uniqueness.
- OpenAPI Specification 3.2.1, 10 September 2026, for describing the contract.
- RFC 9700, January 2025, Section 2.3 and OWASP API1:2023, Broken Object Level Authorization, for access restrictions and object-level checks.
- Birrell and Nelson, Implementing Remote Procedure Calls, ACM Transactions on Computer Systems, February 1984, particularly Section 3.1; paper text.
Want APIs that agents can use with controlled effects? Talk to i8 about integration, verifiable contracts, and safe retries.



