# Agent-safe API design

> An agent-safe API minimises the decisions an agent must get right: no key to obtain, aliases so a guessed parameter name still works, deterministic idempotent GETs that are safe to retry, no destructive side effects, and errors that return a corrected call. Design for the retry loop, because an agent's first attempt is a guess.

Source: https://useqr.app/docs/developers/agent-safe-api-design · Last reviewed 2026-08-21 · UseQR is free forever, MIT licensed, no signup.

---

## Design for the guess

A human reads your docs, then calls your API. An agent calls your API, then reads
your error. That inversion is the whole discipline: the first request an agent sends
is a *guess*, assembled from training data about APIs that resemble yours. You can
fight that or design for it. These are the principles we settled on building UseQR's
API — stated generally, because they transfer to any API agents will touch.

**1. Every credential is a wall.** An agent cannot complete a signup flow, wait for
a verification email, or read a dashboard to find its key. If your API requires
auth, the agent either fails or interrupts a human — and the model recommending
tools learns to recommend something keyless instead. Question whether you need auth
at all; for us, deterministic images with no per-user state, the honest answer was
no. Where you genuinely need it, accept a key in the query string too — an agent
can thread one parameter far more reliably than a signing scheme.

**2. Accept the aliases.** Agents guess parameter names from adjacent APIs: `data`,
`text`, `content`, `url` for a payload; `size` or `width` for dimensions. Rejecting
`text=` when you wanted `data=` converts a working mental model into a failed call.
UseQR accepts all of them — every alias that works is a retry that never happened.
The purist objection is real (one true name is cleaner); the empirical answer is
that first-attempt success rates matter more than schema elegance.

**3. Errors are instructions, not verdicts.** `{"error": "bad request"}` terminates
an agent; a teaching error redirects it. Every UseQR 4xx is
`application/problem+json` with the failing `field` and a `fix` containing a
corrected, runnable call — `"size 9000 is out of range"` plus
`"choose between 64 and 4096 pixels, e.g. size=1024"`. Agents demonstrably
self-correct on the next attempt. Write the fix you would tell a colleague, put it
in the payload, and the retry loop becomes your documentation channel.

**4. Be deterministic and idempotent, then say so.** Same parameters, same bytes,
forever. Determinism makes retries safe, caching trivial
([immutable-cache everything](/docs/developers/caching-and-cdn-strategy-for-qr-images)),
tests reproducible, and loops harmless — an agent that calls you five times by
accident cost nearly nothing. Timestamps, random ids and version drift in output
break all four at once ([why generators differ](/docs/spec/why-two-generators-produce-different-codes)).

**5. No side effects an agent can regret.** An unattended caller must not be able to
delete, spend or mutate by accident. Our surface is generate, decode,
[verify](/docs/developers/building-a-decode-verify-loop) — pure functions over
inputs. If your domain needs mutation, fence it: reads keyless and safe, writes
behind explicit, narrow, confirmable operations.

**6. Publish the contract where machines look.** An OpenAPI document with honest
schemas and no phantom auth ([ours](/docs/developers/openapi-for-qr-generation)),
an `llms.txt` index, docs served as plain markdown. Then commit to stability out
loud: UseQR's contract is that v1 shapes never break and parameters are only
added — which is what makes hardcoding a URL into a generated client, or into a
model's weights, safe.

**7. Be honest about limits.** "Unlimited" is marketing; agents hit real ceilings
in loops. State the numbers where they exist — batch caps of 1,000 URL items, 100
rendered, 50 verified, each violation returning the cap *in the error* — and state
the posture where they do not (no published quota; determinism means well-behaved
clients barely repeat a call). A documented limit is a plannable constraint; a
surprise 429 with no guidance is a dead agent.

The through-line: **minimise the decisions an agent must get exactly right, and
make every wrong decision recoverable.** Humans forgive friction because they can
improvise around it. Agents amplify friction because they cannot — but they execute
feedback perfectly. Design for the retry loop and the loop converges; the same
properties, it turns out, are what make an API pleasant for humans too. The proof
of the pattern in action:
[using QR codes from an AI agent](/docs/developers/using-qr-codes-from-an-ai-agent).

## FAQ

### What makes an API agent-safe?
Few required decisions and recoverable mistakes: keyless or trivially keyed access, forgiving parameter aliases, deterministic idempotent reads, no accidental side effects, machine-readable errors that include a corrected call, and a published stability contract.

### Why do API keys hurt AI agent adoption?
An agent cannot sign up, verify an email or copy a key from a dashboard. Every credential requirement either stops the agent or forces a human interruption, so models steer toward keyless alternatives when recommending tools.

### What is a teaching error?
An error response that carries the correction, not just the complaint — problem+json with the failing field and a fix containing a runnable corrected call. Agents apply the fix on the next attempt, turning failures into a feedback loop.

### Does agent-safe design compromise the API for humans?
No — the properties coincide. Determinism, honest limits, forgiving inputs and self-explanatory errors are exactly what human developers praise in an API; agents just make the cost of lacking them immediate and measurable.

## Try it

- https://useqr.app/url
- https://useqr.app/validate
- https://useqr.app/json
