Designing APIs for AI Agents: Principles and Patterns
Most APIs are designed for human developers. Documentation explains what each field means; error messages are written to be read; authentication flows assume a browser or a terminal session. AI agents interact with APIs differently — they parse responses programmatically, handle errors in code, and make decisions about retries and payment without human intervention. An API that works cleanly for a developer with Postman can fail silently when an agent runs the same calls in production. The differences are specific.
Agents Are Not Developers
A developer reading an API response can infer intent from context — a field called filed_on is clearly a date, and a human will handle null gracefully even if the docs don't mention it. An agent working from a function schema has only the schema: field names, types, and any description text provided. Fields that are inconsistently present, arrays that can be null or empty interchangeably, and status indicators embedded in human-readable strings are all sources of failure.
Agents also cannot ask clarifying questions. When a developer encounters an ambiguous API behavior, they open the docs or post on the forum. An agent either handles the ambiguity correctly based on its training and context, or it fails. Designing for agents means designing for zero-ambiguity operation: every field has a defined type, every absence is explicit, and every error is classifiable without reading prose.
Structured, Predictable Responses
Response schemas should be stable and complete. Fields that are sometimes present and sometimes absent force agents to implement defensive checks that erode the clarity of the tool's interface. Where a value may be absent, return it as null with a documented type of string | null rather than omitting it. This makes the schema predictable: an agent can destructure a response without first checking whether a field exists.
Enumerated values should be documented exhaustively. If a status field can be active, closed, or transferred, those are the values — not an open-ended string field. Agents route on field values; undocumented values break routing logic silently.
Pagination should be cursor-based rather than offset-based. Offset pagination is fragile under concurrent modification and requires the agent to track page state. Cursor pagination is stateless from the agent's perspective: each response includes a cursor that, if present, means there is more data; if absent, iteration is complete.
Machine-Readable Errors
Error responses should include a structured code field with a stable, enumerated string identifier — not just an HTTP status code and a prose message. An agent can branch on "code": "COURT_NOT_COVERED" without parsing natural language. Prose messages are still valuable (agents use them in reasoning traces and logs) but the code field is what the agent should act on.
Error codes should be specific enough to drive correct handling. A single PAYMENT_ERROR code is less useful than separate codes for PAYMENT_EXPIRED, PAYMENT_REPLAYED, and PAYMENT_AMOUNT_MISMATCH, each of which has a different correct response: rebuild the payment, do not retry, or check the current price respectively. See the API error reference for DocketLayer's full error taxonomy.
Include a requestId in every error response. Agents log request IDs in their traces, which makes debugging production failures tractable when the agent's operator needs to reconstruct what happened.
Payment as Protocol
The x402 payment flow is designed to be handled programmatically. The 402 response carries a machine-readable payment specification — amount, recipient, nonce — and the retry mechanism is a standard HTTP header. An agent can implement the full probe-pay-retry cycle in a handful of lines: probe, receive 402, parse the payment spec, build the USDC transaction, attach the header, retry.
This is a different model than OAuth or API keys, where payment is decoupled from the request. x402 makes payment part of the protocol, which means agents do not need out-of-band payment provisioning — they transact directly. The constraint is that agents need access to a funded wallet. The benefit is that no human needs to be in the loop to authorize a specific query.
Idempotency and Retries
Agents retry on transient failures. An API that is not idempotent under retries will produce duplicate effects when an agent retries a partially-completed operation. Read endpoints are inherently idempotent; write or stateful endpoints should support an Idempotency-Key header that deduplicate concurrent or repeated identical requests.
For x402 payments specifically, payment transactions are single-use by design — once a transaction is verified, it cannot be replayed. This means a retry after a successful-but-interrupted response requires a fresh payment. Agents should treat 402 on a request with a prior payment header as a signal to rebuild the payment, not to reuse the previous transaction.
Capability Discovery
APIs designed for agents benefit from machine-readable capability endpoints. A coverage endpoint that returns available court codes, their status, and their supported query types lets an agent determine what it can query without trial and error. A pricing endpoint that returns current per-request prices lets an agent budget before querying. These endpoints reduce the surface area where an agent can fail due to conditions it could have checked in advance.
DocketLayer exposes this through its free tools: docketlayer_status, docketlayer_court_list, and docketlayer_pricing via the MCP server, and equivalent endpoints in the REST API.
OpenAPI schemas serve a similar function: a well-maintained schema gives agents (and the models powering them) a complete picture of the API surface. Schemas should include field descriptions, enum values, and example responses — not just types. The description text in an OpenAPI schema is the closest equivalent to a developer reading the docs; for agents, it is the primary channel through which intent is communicated.