---
title: "Designing APIs for AI Agents: A Practical Guide"
description: "LLM agents are the next wave of API consumers. This guide covers tool schemas, deterministic errors, retry safety, output predictability, and human-in-the-loop patterns."
canonical: https://nowah.xyz/blog/designing-apis-ai-agents-practical-guide
lastModified: "2026-08-07T08:10:35.622Z"
---

# Designing APIs for AI Agents: A Practical Guide

LLM agents are the next wave of API consumers. This guide covers tool schemas, deterministic errors, retry safety, output predictability, and human-in-the-loop patterns.

Your API's [most important](/blog/why-speed-is-most-important-feature) consumer cannot read your documentation page. It cannot browse examples, scan for code snippets, or ask a colleague for help. It is a large language model that receives a JSON schema, constructs API calls based on that schema, and interprets the responses to make decisions.

This is not a future scenario. It is happening now. AI agents are making API calls to [book flights](/blog/ai-agents-book-flights-under-two-minutes), search hotels, process payments, and manage travel itineraries. The agents that our platform serves use over a large set of tools, each defined as a JSON schema that the LLM consumes to decide what to call and how.

Building APIs that work well for AI agents requires thinking differently about several [design decisions](/blog/year-in-review-design-decisions-shipped). Not radically differently — most good API design practices serve agents well. But there are specific areas where agent-oriented design diverges from human-oriented design, and getting those areas right makes the difference between an agent that works reliably and one that hallucinates, retries endlessly, or books the wrong flight.

## Tool schema design

![Illustration for this section](https://pics.nowah.xyz/website-media/developer-experience-026-img-1-tool-schema.webp)

When an AI agent decides to call your API, it is working from a JSON schema definition that describes the endpoint, its parameters, and the expected response. The quality of this schema directly determines the accuracy of the agent's API calls.

A vague schema produces vague results. If the parameter description says "location" without specifying the format, the agent might send "New York", "JFK", "40.6413,-73.7781", or "New York, NY, USA." Each is a reasonable interpretation of "location." Only one format is what your API expects.

A precise schema eliminates ambiguity:

```
{
 "name": "a flight-search capability",
 "description": "Search for available flights between two airports on a specific date. Returns ranked flight offers with pricing.",
 "parameters": {
 "type": "object",
 "required": ["origin", "destination", "departureDate", "passengers"],
 "properties": {
 "origin": {
 "type": "string",
 "description": "IATA airport code for departure (e.g., 'JFK', 'LAX', 'LHR')",
 "pattern": "^[A-Z]{3}$"
 },
 "destination": {
 "type": "string",
 "description": "IATA airport code for arrival (e.g., 'CDG', 'NRT', 'SYD')",
 "pattern": "^[A-Z]{3}$"
 },
 "departureDate": {
 "type": "string",
 "description": "Departure date in ISO 8601 format (YYYY-MM-DD)",
 "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
 },
 "passengers": {
 "type": "object",
 "required": ["adults"],
 "properties": {
 "adults": {
 "type": "integer",
 "minimum": 1,
 "maximum": 9,
 "description": "Number of adult passengers (age 12+)"
 }
 }
 },
 "cabinClass": {
 "type": "string",
 "enum": ["economy", "premium_economy", "business", "first"],
 "description": "Preferred cabin class. Defaults to economy if not specified."
 }
 }
 }
}
```

Every field has a specific type, format constraints, examples, and a description that explains what the field means in concrete terms. Enum constraints restrict free-text fields to valid values — the agent cannot hallucinate a cabin class that does not exist.

In our testing, adding enum constraints to fields that previously accepted free text reduced hallucinated values by over 80%. Tool descriptions averaging two to three sentences produce higher accuracy than either one-line descriptions (too vague) or paragraph-length descriptions (too much for the model to parse efficiently).

## Deterministic error codes

When an agent encounters an error, the [error message](/blog/anatomy-of-perfect-error-message) is its only source of information. It cannot screenshot the response and ask a teammate for help. It cannot search Stack Overflow. It needs to decide what to do next based entirely on what the error tells it.

This means errors must be deterministic and actionable. Each error code should map to exactly one behavior:

- \`OFFER\_EXPIRED\` means search again\.
- \`RATE\_LIMIT\_EXCEEDED\` means wait and retry\.
- \`VALIDATION\_MISSING\_FIELD\` means fix the request parameters\.
- \`PROVIDER\_UNAVAILABLE\` means retry after a delay\.
- \`AUTH\_TOKEN\_EXPIRED\` means re\-authenticate\.
- \`BOOKING\_ALREADY\_CONFIRMED\` means no action needed\.

An agent can build a decision tree from these codes. Each code leads to one recovery action. There is no ambiguity, no interpretation required.

We tested [what happens](/blog/what-happens-after-you-book) when agents encounter vague errors. Agents without structured error codes show three to five times higher retry rates on unrecoverable failures. They keep retrying because the error does not tell them that retrying will not help. Structured codes with recovery suggestions cut wasteful retries dramatically.

## Idempotency everywhere

![Supporting diagram](https://pics.nowah.xyz/website-media/developer-experience-026-img-2-human-in-loop.webp)

Agents retry by default. Most agent frameworks include automatic retry logic. This is a feature, not a bug — it makes agents resilient to transient failures.

But it means every state-changing endpoint must handle repeated requests safely. If an agent retries a booking request and the endpoint is not idempotent, you get a double booking.

We covered idempotency in depth in a previous article, but the agent-specific angle is worth emphasizing: you cannot rely on the agent to manage idempotency keys. The API must generate and manage them. The agent sends a booking request, the API generates an idempotency key from the request parameters and the session context, and duplicates are caught automatically.

## Output predictability

AI agents parse API responses to extract data and make decisions. Inconsistent response shapes break this parsing.

Every endpoint should return the same structure every time\. If a successful response wraps in \`\{ "success": true, "data": \{ \.\.\. \} \}\`, that structure should be identical across every endpoint\. The agent writes one parsing function, and it works everywhere\.

Fields should have predictable types. A price that is sometimes a number and sometimes a string will confuse an agent. A date that is sometimes ISO 8601 and sometimes "March 15th" will produce parsing errors.

Null handling should be explicit. If a field can be absent, document it in the schema. If a field can be null, use null rather than omitting it. Agents handle explicitly null fields more reliably than missing fields.

## Human-in-the-loop patterns

AI agents that book flights and process payments need guardrails. An agent that can autonomously spend $12,000 on a first-class ticket without human approval is a liability.

Our booking flow requires confirmation tokens for any financial transaction. The process:

1. Agent searches for flights and presents options to the user.
2. User selects an option.
3. API generates a time-limited, single-use confirmation token.
4. User reviews the booking details and approves.
5. Agent submits the booking with the confirmation token.

The agent cannot skip steps 2-4. The confirmation token can only be generated through a user-facing interaction, not through an API call that the agent could make autonomously. This ensures a human is in the loop for every financial commitment.

Spending limits add a second layer. Each API key has a configurable maximum booking value per session. If an agent tries to book something above the limit, the API rejects the request and requires human escalation.

## Agent-friendly sandbox

Agents need to be tested, and testing against production data is risky. Our sandbox provides deterministic test data and reproducible scenarios specifically designed for agent evaluation.

The sandbox returns the same results for the same queries, making agent behavior reproducible across test runs\. Error scenarios are triggerable with specific test parameters \(a magic airport code that always returns OFFER\_EXPIRED, a test card number that always fails payment\)\.

This determinism is essential for agent evaluation. If the test data changes between runs, you cannot tell whether a behavior change is due to your code update or due to different test data. Deterministic sandbox data isolates the variables.

No travel API provider currently scores above 4 out of 5 on industry AI agent readiness assessments. The gap between current API design practices and what agents actually need is significant. The providers who close that gap first will capture a disproportionate share of agent-[driven traffic](/blog/rate-limiting-ai-driven-traffic). We are building for that future.

---

Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. [Plan your next trip](https://app.nowah.xyz).
