Agent-First APIs Should Return Recovery Paths
By wGrow Project Team ·
An agent given a standard REST API will eventually call DELETE /users/1. Not because it’s malicious. Because it was looking for a record matching “admin user from onboarding” and 1 was its best guess at a primary key.
Standard CRUD APIs assume a human developer is reading the error response and consulting the docs. LLM agents do neither. They receive a 400 Bad Request, infer a correction from the error string, and retry with a slightly different hallucination. Given enough retries, they will corrupt something.
This is not a model alignment problem. It is an API design problem.
Agents Do Not Know Your Primary Keys
Every standard CRUD endpoint rests on an implicit contract: the caller already knows the identifier. PUT /invoices/{id} assumes you have id. That holds when the caller is a human who retrieved the record from a UI, or a developer who ran a prior GET and stored the result. It breaks immediately when the caller is a language model extracting context from a PDF, a Slack message, or a typed user prompt.
LLMs operate on natural language. They extract names, partial descriptions, approximate dates. When a UUID appears in the source text, a model can copy it — but no model reliably infers an opaque database identifier from a name, a description, or an approximate date.
We hit a version of this problem long before LLMs — while wrapping a legacy SOAP API for a Singapore statutory board. The system required exact string matches for entity names and rigid field-level schemas. A trailing space in a field name, or an unrecognised abbreviation, and the payload was rejected silently, or returned a fault code with no repair information. The integration team spent weeks building a normalisation layer just to make inputs predictable enough to pass validation.
LLMs are that same integration problem at scale, without a team of engineers hand-tuning the normalisation layer. Expecting an agent to infer an exact entity_id from natural language context is the same architectural mistake — except now it’s automated and runs at 3 AM.
Search and Select Before Execute

The fix is to decouple discovery from execution. Any state-changing operation that targets an existing entity resolved from natural-language context should be preceded by an explicit search step that maps the user’s description to a verified identifier before execution.
When building the document ingestion pipeline for WaterDoctor, we hit this directly. Water quality reports reference infrastructure by operational names: “Pump Station Alpha”, “Reservoir B outflow”. The database stores these under surrogate keys. The first implementation used a standard POST /readings endpoint and expected the agent to supply entity_id. It didn’t. It hallucinated IDs based on patterns it had absorbed from API documentation tutorials — values like entity_id: 12345 appeared in payloads because that placeholder is ubiquitous in API docs.
The corrected design exposes a /search endpoint that accepts a natural language string and returns the top three candidate matches with metadata: name, location code, last active timestamp. Three is deliberate. Returning a large result set doesn’t help an agent choose — it bloats the context window and raises the probability of a wrong selection. The agent reads the three candidates, verifies the metadata against the source document, confirms which record matches, extracts the UUID, and only then calls the write endpoint.
Search, verify, commit. It’s a decision loop agents can execute reliably. Any API that skips the search step offloads identifier resolution onto the model — and that’s not where that work belongs.
Preview Endpoints Prevent Hallucinated Commits
Once an agent has resolved an identifier, the next failure mode is a write that looks syntactically valid but is semantically wrong. The agent understood the structure but misread a value, transposed a line item, or applied a tax rate to the wrong subtotal. Standard CRUD design provides no mechanism to catch this before the database write. A confirmation screen does that job in human-facing software. Agent-facing APIs need the equivalent built into the contract.
We built this after a painful stretch with an internal invoice processing agent. The agent read vendor invoices and constructed payment drafts. Early runs committed amounts that included GST when the system expected GST-exclusive figures. The misreads were consistent enough that several drafts went through before anyone caught the pattern — and rolling back required direct database intervention each time.
The fix was a /preview endpoint. It accepts the full proposed payload, runs all calculation and validation logic, but writes nothing. It returns the calculated consequence in plain terms: the affected budget line, the deducted amount, the resulting balance. The agent cross-references that output against the source invoice and calls the commit endpoint only if the numbers align.
Preview is not a UX nicety for cautious users. It is a safety primitive. Any agent operating on financial or operational state should be required to pass through preview before the system accepts a final write. That’s a contract-level requirement, not an optional feature.
Designing Machine-Readable Recovery Paths

After the first two failure modes comes the retry loop. The agent sends a payload, receives an error, guesses at the problem, tries again. If the error message is written for a human — “Invalid date format” or “Entity not found” — the agent has almost no usable signal. It cycles through plausible corrections until it exhausts its token budget or stumbles onto a valid payload by chance.
Error responses on agent-facing endpoints need to be structured repair instructions.
Don’t return:
{"error": "Invalid date format."}
Return:
{
"error": "Date field rejected.",
"field": "report_date",
"expected_format": "YYYY-MM-DD",
"received": "2026/06/21",
"action": "retry_with_format"
}
The action field is the critical addition. It tells the agent what category of correction to apply. “retry_with_format” is a deterministic instruction — the agent reads the expected format, reformats the value, retries. When the received value is repairable — a misformatted date string, a wrong separator — the loop terminates in one additional call instead of several. When required information is absent entirely, the action should instead tell the agent to request clarification rather than attempt a guess.
The same principle applies to size limits:
{
"error": "Payload exceeds character limit.",
"field": "summary",
"current_length": 1580,
"max_length": 1000,
"action": "truncate_and_retry"
}
Fuzzy operations — entity resolution, category matching, similarity search — should expose a confidence score alongside results. An endpoint returning a low or ambiguous match score should expose that score and instruct the agent to seek clarification or surface options before proceeding. If the system uses automatic thresholds to allow unattended commits, calibrate those thresholds on task-specific data: raw similarity scores are model- and index-dependent and do not function as calibrated probabilities out of the box. The distinction between ambiguous and confirmed matches matters for any agent designed to pause for human review below a threshold.
Programmatic recovery paths convert a nondeterministic retry storm into a deterministic correction loop. The API takes responsibility for failing gracefully, instead of delegating recovery to the model’s inference.
What Changes in Practice
| 1 | { | |
| 2 | "error": "Payload exceeds limit.", | |
| 3 | "current_length": 1500, | |
| 4 | "max_length": 1000, | ← ① |
| 5 | "action": "truncate_and_retry" | ← ② |
| 6 | } |
- ① Explicit boundaries
- ② Actionable directive
None of this requires abandoning REST or introducing a new protocol. It requires accepting that the consumer of your API is a probabilistic component whose effective knowledge is bounded by what the runtime explicitly provides. Documentation it was never given, prior call state it cannot access, recovery rules that exist only in internal runbooks — none of these reach the model unless the API contract surfaces them. Where context is missing, it infers. Where inference fails, it retries.
Three practical changes follow from that.
Expose search before stateful operations that depend on entity resolution. Those endpoints should return a small, bounded result set — not a paginated list — because every unnecessary token in the agent’s context is a navigation hazard.
Mandate a preview step for any write that touches financial figures, scheduling state, or operational records. Preview should return explicit consequences, not just validation results.
Rewrite error responses as structured repair instructions. Every error should carry the field name, the received value, the expected value or format, and an action code. Treat “Invalid input” the same way you’d treat an undocumented exception: a sign the API isn’t finished.
Enterprise systems will increasingly be judged not just on uptime metrics but on how well they handle autonomous agents failing. APIs that cannot guide a failing agent toward recovery will absorb automated retries until rate limits engage or data integrity degrades. The interfaces that hold up under agentic traffic aren’t the ones with the best documentation — they’re the ones that treat failure as an expected state, not an edge case.