Designing REST APIs LLMs Can Actually Use: A Field Guide for Tool-Using Agents
APIs·By Islam Gamal··30 min read

Designing REST APIs LLMs Can Actually Use: A Field Guide for Tool-Using Agents

The API design choices that make or break tool-using LLM agents — naming, error shapes, idempotency, discoverability, JSON schema hygiene, pagination, and the eight anti-patterns that confuse every model.

Islam Gamal
Islam Gamal
AI · Data · Automation Engineer
TL;DR

LLMs can call any HTTP API — but they call some APIs correctly on the first try and fail loops of ten on others. The difference isn't the model; it's the API design. This guide covers the concrete design rules that make an API 'agent-friendly': explicit naming, structured error shapes with actionable hints, mandatory idempotency keys on writes, JSON Schema that constrains rather than describes, cursor-based pagination, and OpenAPI specs that a tool router can consume without a human translator. If your APIs will be called by agents, treat this as a compliance checklist.

Key takeaways
  • Use full, explicit names (create_customer, not POST /c).
  • Return errors with a machine-readable code, a human message, and a next-action hint.
  • Require idempotency keys on every write; agents retry constantly.
  • Use JSON Schema enums and formats to constrain — LLMs respect constraints.
  • Cursor pagination, not offset; agents lose track of page numbers.
  • Ship an OpenAPI 3.1 spec with descriptions written for humans, not just machines.
  • One resource per endpoint; polymorphic endpoints confuse tool routers.

Why LLMs fail at 'normal' APIs

Every API team has a war story: they wired up their perfectly reasonable REST API to a tool-using agent, and the agent looped, hallucinated fields, called the wrong endpoint, or gave up. Then they blamed the model.

The model isn't the problem. Most APIs were designed for human developers who read docs, remember conventions, and have taste. Agents have none of those. They see a JSON schema and a description; they act on what those literally say.

Designing 'agent-friendly' APIs means removing every place where implicit knowledge is required. It also — happily — makes the API better for humans.

Rule 1 — Explicit, complete names

Short URLs are a legacy of typing on terminals. Agents don't type. Longer, explicit names reduce ambiguity dramatically.

BadGood
POST /cPOST /customers with operation_id: create_customer
GET /o/:id/sGET /orders/{order_id}/shipments
PATCH /uPATCH /users/{user_id}

Operation IDs in your OpenAPI spec become the tool names an agent sees. Make them read like verbs an intern would use: list_pending_invoices, not list_inv_p.

Rule 2 — Errors with actionable next steps

Every error should let the agent decide what to do next: retry, ask the user, or give up. That means three fields:

{
  "error": {
    "code": "customer_email_taken",
    "message": "A customer with this email already exists.",
    "next_action": "fetch_existing_customer",
    "next_action_params": { "email": "ada@example.com" },
    "retryable": false,
    "docs_url": "https://api.example.com/docs/errors/customer_email_taken"
  }
}
Pro tip: Agents that see retryable: true retry with backoff. Agents that see next_action chain calls without human help. This one field pair cuts agent latency by 30–60% on error paths.

Rule 3 — Idempotency keys are mandatory, not optional

Agents retry. Networks fail. The user says 'try again'. Without an idempotency key, you get duplicate charges, duplicate emails, duplicate tickets.

Accept an Idempotency-Key header on every non-GET endpoint. Cache the response for 24h keyed by (endpoint, key, request-body-hash). Return the same response on retry.

Same pattern for webhooks going the other way — see webhooks that don't lie.

Rule 4 — JSON Schema that constrains

LLMs respect JSON Schema. Use it aggressively to prevent bad calls:

  • Use enum for finite value sets — do not accept free-text where enums exist.
  • Use format: 'email', format: 'date-time', pattern for regex constraints.
  • Mark fields required when they truly are; agents skip optional fields aggressively.
  • Add description on every field, in prose — this is what the model reads to know what the field means.
  • Use oneOf for tagged unions with a discriminator; avoid anyOf which is ambiguous.

Rule 5 — Cursor pagination, not offset

Agents lose track of page numbers across turns. Cursors are self-describing:

{
  "items": [...],
  "next_cursor": "eyJpZCI6MTIzNCwidHMiOiIyMDI2LTA3LTA4In0",
  "has_more": true
}

The agent just passes cursor back in the next call. No off-by-one, no state to remember, no double-fetching.

Rule 6 — One resource, one endpoint

Polymorphic endpoints — POST /entities that accepts 12 different type values — confuse tool routers. Split into create_customer, create_invoice, create_ticket. Yes, it's more endpoints. Yes, it's better.

Rule 7 — OpenAPI 3.1, written for agents

Your OpenAPI spec is the contract every tool-using framework reads. Treat descriptions as first-class UX:

paths:
  /customers:
    post:
      operationId: create_customer
      summary: Create a new customer record.
      description: |
        Creates a customer. Returns 409 if a customer with the same email
        already exists — in that case, call get_customer_by_email instead
        of retrying.
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/CustomerCreate" }

Tools like Chat GPT plugins, Anthropic tool use, and LangGraph ingest this spec verbatim. Bad descriptions == bad agent behavior.

Rule 8 — Rate limits with a hint, not a hammer

Return 429 with headers the agent can act on:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1720431600
Retry-After: 12

Agents will honor Retry-After automatically. Without it, they hammer you.

Eight anti-patterns to fix today

Anti-patternFix
Free-text status fieldEnum with 3–8 values
Booleans that should be enums (paid: true/false → status)Enum: unpaid/paid/refunded/void
Timestamps as unix intsISO 8601 with timezone
Errors as HTML pagesStructured JSON always
POST for readsUse GET; caching + LLM heuristics rely on verb
Field names in multiple cases (userId, user_name)Pick snake_case, apply everywhere
Silent truncation of long inputs413 with max length
Deprecated endpoints still 200 OK410 Gone + successor endpoint hint

Testing your API with an actual agent

Before shipping API changes, run a smoke test with a real tool-using agent:

  1. Feed the OpenAPI spec into your agent framework.
  2. Give the agent a natural-language task ("create a customer named Ada with email x, then create an invoice for $100").
  3. Log every call, every retry, every error.
  4. Any confusion the agent shows is a doc bug or design bug — fix it, not the prompt.

Deeper eval methodology in evaluating LLMs.

The compounding win

APIs designed this way don't just work better for agents — they're easier for humans too. Better error messages, cleaner names, stricter schemas, and cursor pagination are best practices from long before LLMs existed. The pressure of tool-using agents just makes the tax on bad APIs finally visible.

#APIs#REST#LLM#Agents#Tool Use#OpenAPI

Building something similar?

I help teams ship production-grade AI agents, n8n workflows, and data platforms. Let's talk about what you're building.

Work with me
Islam Gamal
Written by

Islam Gamal

AI, Data & Automation Engineer. I design and ship production AI agents, n8n workflows, and cloud data platforms — with a focus on reliability, cost, and measurable business impact. Founder of Tashghil and Tek bil Arabi.

More from Islam Gamal

Browse every article by Islam Gamal on the author page.