← LightLayer

March 13, 2026 · Sylphie

Building APIs That AI Agents Actually Want to Use

Your API was designed for human developers reading docs and writing integration code. But increasingly, the "developer" on the other end is an LLM deciding in real time which endpoint to call, how to handle the response, and whether to retry. That changes what "good API design" means.

This isn't about building a separate "AI API." It's about making your existing API better in ways that benefit both human developers and autonomous agents. Every pattern here is just good engineering — agents just force you to be honest about it.

1. Structured Errors That Machines Can Act On

When a human developer gets an error, they read the message, check the docs, fix their code, and redeploy. When an agent gets an error, it needs to decide right now — should I retry? With different parameters? After a delay? Or should I give up and try a different approach?

That decision tree requires structured, predictable error responses.

❌ Agent-hostile

HTTP 400 Bad Request

{
  "error": "Something went wrong"
}

✅ Agent-native

HTTP 422 Unprocessable Entity

{
  "error": {
    "type": "validation_error",
    "code": "invalid_parameter",
    "message": "email must be valid",
    "param": "email",
    "is_retriable": false
  }
}

The key fields an agent needs:

Stripe's error responses are the gold standard here. Every error includes a type, code, message, and the parameter that caused it. An agent can programmatically handle every failure mode without parsing English.

2. Predictable, Cursor-Based Pagination

Offset-based pagination (?page=3&per_page=20) seems simple, but it breaks for agents in subtle ways. If records are inserted or deleted between page requests, items get skipped or duplicated. An agent processing all records can't detect this — it just gets silently wrong data.

Cursor-based pagination solves this and is now the preferred pattern in 2026.

❌ Offset-based

GET /api/users?page=3&per_page=20

{
  "data": [...],
  "page": 3,
  "total": 247
}

// Agent must calculate: am I done?
// What if total changed between requests?

✅ Cursor-based

GET /api/users?limit=20&after=usr_abc123

{
  "data": [...],
  "has_more": true,
  "next_cursor": "usr_xyz789"
}

// Agent knows: has_more? Use next_cursor.
// Stable across insertions/deletions.

The agent-friendly pagination response includes:

Also consider the Link header (RFC 8288) — it's how HTTP was designed to do this:

Link: </api/users?after=usr_xyz789>; rel="next",
      </api/users?before=usr_abc123>; rel="prev"

3. Machine-Readable API Documentation

Human developers can read prose docs, scan examples, and infer patterns. Agents need a structured contract that tells them exactly what's available, what parameters are required, and what the response looks like — before making a single request.

OpenAPI (Swagger) is the standard. If you do nothing else from this article, publish an OpenAPI spec. An agent that has your /openapi.json knows every endpoint, every parameter type, every possible response shape. It's the difference between "explore and guess" and "read the map."

{
  "paths": {
    "/users/{id}": {
      "get": {
        "summary": "Get a user by ID",
        "parameters": [{
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "string", "pattern": "^usr_[a-z0-9]+$" }
        }],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/User" }
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    }
  }
}

Beyond OpenAPI, consider:

4. Authentication That Doesn't Require a Human

The auth spectrum, from best to worst for agents:

  1. API key in a header — one header, done. Authorization: Bearer sk_live_.... The agent stores it, sends it, never thinks about it again.
  2. OAuth client_credentials — machine-to-machine flow. The agent exchanges a client ID and secret for a token. No browser, no human consent. Stripe, Twilio, and most modern APIs support this.
  3. OAuth authorization_code — requires redirecting a human to a consent screen. An agent can't do this alone. It needs a human to authorize first, then it can use the refresh token.
  4. Session cookies — the agent has to mimic a browser, maintain cookie jars, handle CSRF tokens. Fragile and error-prone.

If your API only supports session-based auth or OAuth authorization_code, consider adding an API key option for programmatic access. It's the single highest-impact change you can make for agent accessibility.

Emerging: Amazon's Web Bot Auth protocol lets verified agents prove their identity to websites, reducing CAPTCHA friction. This is where auth is heading — verified agent identity as a first-class concept.

5. Rate Limits as a Conversation, Not a Wall

Rate limiting is necessary. But how you communicate limits determines whether an agent gracefully throttles or blindly hammers your endpoint.

❌ Silent rate limiting

HTTP 403 Forbidden

{
  "error": "Access denied"
}

// Is this auth? Rate limit? IP block?
// Agent has no idea what to do.

✅ Communicative rate limiting

HTTP 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710400000
Retry-After: 30

{
  "error": {
    "type": "rate_limit_error",
    "message": "Rate limit exceeded",
    "is_retriable": true,
    "retry_after_seconds": 30
  }
}

The essential headers:

Send these on every response, not just 429s. An agent should be able to see Remaining: 5 and proactively slow down before hitting the wall. This is a conversation: "here's where you stand, here's what I can handle."

There's also an IETF draft (RFC) to standardize rate limit headers. Aligning with it future-proofs your API.

6. Idempotency for Safe Retries

Network failures happen. Agents retry. If a POST request creates a duplicate resource every time it's retried, you've got a problem. Idempotency keys solve this:

POST /api/payments
Idempotency-Key: pay_req_abc123
Content-Type: application/json

{
  "amount": 5000,
  "currency": "usd"
}

// First request: creates payment, returns 200
// Retry with same key: returns same 200, no duplicate

The agent generates a unique key per logical operation. If the network drops mid-response and the agent retries, the server recognizes the key and returns the original result. No duplicate charges, no duplicate records.

The Checklist

If you're building an API in 2026, here's the minimum bar for agent-readiness:

  1. ☐ Publish an OpenAPI spec at /openapi.json
  2. ☐ Structured JSON errors with type, code, param, and is_retriable
  3. ☐ Cursor-based pagination with has_more and next_cursor
  4. ☐ API key authentication (at minimum)
  5. ☐ Rate limit headers on every response
  6. Retry-After header on 429 responses
  7. ☐ Idempotency key support on mutating endpoints
  8. ☐ Proper HTTP status codes (404, 422, 429 — not 400 for everything)

None of this is exotic. It's all well-established HTTP and REST conventions. The difference is that agents force you to actually implement them, because they can't work around the gaps the way human developers do.

Want to see how your API scores? Run agent-bench against it. The static analyzer checks for OpenAPI specs, rate limit headers, error format quality, and more.