Internet-Draft Agent-Friendly HTTP API Profile June 2026
Gaikwad Expires 11 December 2026 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-gaikwad-agent-friendly-http-api-profile-00
Published:
Intended Status:
Informational
Expires:
Author:
M. Gaikwad
Independent

Design Considerations and Profile for HTTP APIs Consumed by AI Agents

Abstract

AI agents are a fast-growing kind of HTTP API client. A human developer reads an API's documentation once and then writes code that calls it. An AI agent works from the machine-readable description each time it plans a step. It works within a limited amount of text it can hold at once. It retries often. It picks operations by matching their descriptions to a goal. An API built mainly for human developers can lead an agent into failures that are easy to avoid, such as repeating a write, running out of room for the task, or getting stuck on an error it cannot recover from.

This document lists the properties that make an HTTP API easy for AI agents to use, including APIs reached through tool-calling layers such as the Model Context Protocol. It gathers these properties into a profile of existing HTTP and API-description mechanisms, with a checklist at the end. It covers the API and its description. It does not define new ways to identify, authenticate, or authorize an agent. That work is happening elsewhere and is referenced here for context.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 11 December 2026.

Table of Contents

1. Introduction

Autonomous software agents built on large language models are starting to call HTTP APIs. Sometimes the agent forms the HTTP request itself. More often it goes through a tool-calling layer that presents each API operation as a callable "tool". The Model Context Protocol [MCP] is one common example of such a layer. Many of its servers are generated automatically from an existing API description such as an OpenAPI document [OPENAPI].

One property matters most. The description of the API, and the data the API returns, both become input to the agent's own reasoning. Several single points in this document are also ordinary good API practice: stable operation names, bounded pages, structured errors, idempotency. This document explains why each one matters more when the client is an agent. It adds the guidance that is specific to agents. It collects the result as a profile that a provider can apply and check against. This document does not assume that an agent is reliable or well-behaved. It treats the agent as a client whose behavior is shaped by the shape of the API.

1.1. Two Layers

There are two layers to keep separate. The API layer is the HTTP API and its machine-readable description. The tool layer is the surface that a tool-calling protocol or generator builds from that description. This document is about the API layer. A good API layer is the most reusable way to get a good tool layer. The tool layer is increasingly handled by its own protocols.

1.2. API Styles

The advice here is written for resource-oriented HTTP APIs, where each operation acts on an identified resource. Most of it also applies to query-based APIs such as GraphQL and to remote-procedure-call styles such as gRPC. A few points change. A query-based API lets the client ask for exactly the fields it needs, which handles the over-fetching concern in Section 8 on its own. In return it adds query-cost and query-depth concerns that an agent-facing deployment SHOULD limit. A reader using this document with another style should map each point to the matching idea in that style.

1.3. Scope and Non-Goals

This document is informational. It lists considerations, gives non-normative recommendations, and assembles a profile and a checklist. It does not define a protocol or a wire format. These topics are out of scope:

  • How an agent proves its identity, authenticates, or is granted authority by a user. That work is active in the IETF, including OAuth 2.0 Token Exchange [RFC8693], on-behalf-of authorization for agents [I-D.oauth-ai-agents-obo], and wider frameworks [I-D.klrc-aiagent-auth]. Section 16 explains the connection.
  • The internal design of tool-calling protocols, including how those protocols define tools, resources, and prompts.
  • Agent-side topics such as planning, reasoning traces, and model evaluation.

1.4. Requirements Language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. This document is informational. These words give guidance to API authors. They are not protocol requirements.

2. Terminology

Agent:
An autonomous software system, usually built on a large language model, that picks and calls API operations to reach a goal.
Tool:
An API operation as it is shown to an agent by a tool-calling layer. It has a name, a short description, and an input schema.
API description:
A machine-readable definition of an API, such as an OpenAPI document [OPENAPI], that a tool layer can be built from.
Context window:
The limited amount of text the agent's model can hold and read at one time. Operation descriptions and response bodies use up this space.
Affordance:
A machine-readable part of a request or response that tells the agent what it can or should do, in a form it can act on without reading prose.

3. How an Agent Uses an API

The advice below follows from a few facts about how an agent uses an API. Stating them shows where the advice applies.

These facts apply most directly when operation descriptions, schemas, error messages, and response bodies reach a language model or a model-guided planner. When something in between filters, checks, or shortens the data before the model sees it, the space and selection effects shrink but do not disappear. The retry and side-effect effects usually remain.

4. Prefer Signals the Agent Can Act On

This is the main idea of the document. An agent-facing API SHOULD give the agent machine-readable signals it can act on. It SHOULD avoid relying on prose that the agent has to read and interpret. A sentence such as "call this carefully" or "try again later" has to be understood by the model, and the model follows such sentences unevenly. The same intent stated as a field or a flag can be acted on directly. This swap shows up throughout the profile:

5. The API Description Is the Contract

When an API is reached through a generated tool layer, its machine-readable description is the single source the tools are built from. Anything missing from the description is missing from the tool. So treat the description as a main deliverable. Do not treat it as documentation written after the code.

6. Be Consistent and Predictable

An agent learns patterns and reuses them. Anything inconsistent across the API makes it guess wrong. Keep naming, identifier formats, pagination, error shape, and authentication the same across the whole API. For example, a status value that is pending on one operation, IN_PROGRESS on another, and done on a third will cause errors. When an operation only works in certain states of a resource, document the states and the moves between them. Then the agent can work out which operations are valid without guessing. Keep enumerated values stable. The agent may have seen and remembered them in an earlier call.

7. The Set of Operations You Expose

A complete resource-oriented API does not become a good tool surface on its own. Turning every endpoint into its own tool gives the agent a surface that is large, low-level, and hard to work through.

8. Keep Responses Small

A response uses up the agent's space budget on the turn it arrives, and on every later turn it stays in view. Asking for too much costs more each turn. A response that is too large is also a denial-of-service and cost problem (see Section 17).

9. Make Errors Recoverable

An error response is not the end of the story. It is the input to the agent's next decision. An error that is unstructured or unclear leads the agent to retry something that cannot work, or to give up on something a retry would have fixed.

Use a structured, machine-readable error format such as Problem Details for HTTP APIs [RFC9457], which is a standard JSON shape for errors. Include a stable error code that is separate from the HTTP status code.

Problem Details lets you add your own fields. For an agent-facing API, say plainly whether a failed call can be retried, using a field. Do not leave the agent to read this off the status code. Report every validation problem at once, with the field name for each one. A small, consistent set of fields across the API does the job: a boolean retryable, an optional retry-delay hint, and a list of field errors. With these the agent can decide to retry, to change the request, or to stop, without guessing. The field names here are only examples. This document does not register them. That would be the job of a later specification (see Section 19). Here is a retryable rate-limit error:

HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/problem+json

{
  "type": "https://api.example.com/problems/rate-limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "detail": "Request rate exceeded for this credential.",
  "code": "RATE_LIMITED",
  "retryable": true,
  "retry_after": 30
}
Figure 1: Error response with an explicit retry indication

A validation error sets retryable to false and lists the fields that were wrong. That tells the agent to change the request before it sends it again:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "https://api.example.com/problems/validation",
  "title": "Invalid request",
  "status": 422,
  "code": "VALIDATION_FAILED",
  "retryable": false,
  "field_errors": [
    { "field": "assignee_email", "code": "INVALID_FORMAT",
      "detail": "Not a valid email address." },
    { "field": "priority", "code": "NOT_IN_ENUM",
      "detail": "Must be one of: low, medium, high." }
  ]
}
Figure 2: Validation error that should not be retried unchanged

10. Make Writes Safe to Repeat, Preview, and Undo

Agents retry after timeouts, after unclear results, and as their plan changes. So safe writing for agents covers more than one idea. It covers repeating a write safely, previewing it, confirming it, cancelling it, and undoing it. As a rule, prefer writes that can be previewed, cancelled, and reversed over writes that take effect at once and cannot be undone.

11. Signal When to Slow Down

Agent traffic can come in bursts. It often lacks the natural pacing of a person at a keyboard. Signal clearly when the client should slow down, so a well-behaved agent can hold back on its own.

12. Long-Running Operations

An operation that takes more than a few seconds does not fit a single blocking request. The connection may not stay open. An agent that waits for it cannot do anything else in the meantime.

13. Changing the API Over Time

The agent's behavior comes from the API description. So a change to the description is a change to the agent's tools. Manage change carefully.

14. Making the API Easy to Discover

An agent does best with one machine-readable, low-noise place to learn what the API can do. A complete API description [OPENAPI] is the main artifact for this. Some providers also publish a short, plain-text index of their documentation aimed at models. The llms.txt convention [LLMSTXT] is one community example, and it is not a standard. Generate any such file from the same source as the human documentation, so the two do not drift apart. Keep it focused on parameters, the meaning of errors, and authentication.

15. Observability

After an agent runs, an operator often needs to work out what it did. To let the agent's steps line up with the API's own logs, accept and pass along a standard correlation identifier. The W3C Trace Context traceparent header field [W3C-TRACE-CONTEXT] is one such identifier, and a generic correlation header is another. Record it in the API's logs next to the identity that acted. This helps with debugging, with working out cost, and with the audit trail in Section 17.

16. How This Relates to Identity and Authorization

This document does not say how an agent authenticates to an API, or how a user grants it authority. A single static credential that covers the whole API is a poor fit for an agent. If it leaks, it reaches everything. The direction the field is taking is to issue narrow, short-lived credentials that can be revoked, and to record delegation openly. The user the agent acts for is recorded separately from the agent. That keeps actions traceable.

Authors building for agents should follow the relevant work, including OAuth 2.0 Token Exchange [RFC8693], protected resource metadata [RFC9728], resource indicators [RFC8707], dynamic client registration [RFC7591], on-behalf-of authorization for agents [I-D.oauth-ai-agents-obo], and the wider analysis in [I-D.klrc-aiagent-auth].

17. Security Considerations

Building an API for agents changes its security picture. The changes connect to the points above.

Injected instructions in text. The agent treats the text it receives as input to its reasoning. So both operation descriptions and response bodies can carry instructions that an attacker planted. This is called indirect prompt injection. Keep trusted control fields apart from untrusted content. Mark natural-language content that came from users or third parties as data, not as instruction. One way is to put it in its own named field and keep a note of where it came from. Do not put externally supplied text into operation descriptions or API documentation unless it is clearly marked as untrusted. Enforce access decisions at the API. Do not rely on instructions in the agent's prompt, because injected text can override them.

Running out of room and money. An API can return a payload far larger than expected, and so can a downstream system that has been compromised. A huge payload can fill the agent's space budget and make the task fail. Where use is billed, it can also run up a large, unexpected cost. People often treat the limits on response size and the cursor-based pagination in Section 8 as performance tuning. For an agent they are also a security control. Enforce them on the server. Do not count on the client to ask for less.

Unsafe retries. The idempotency, preview, and undo guidance in Section 10 is also a security matter. Agents retry more than clients driven by a person, and an unsafe retry can repeat an effect that changes state. Apply least privilege to operations that have real side effects. Keep an audit log that records who acted and under what delegation. Consider requiring a confirmation step for high-risk actions.

Wider reach when access is broad. The discovery artifacts in Section 14 make the API easier for any automated client to read, including a hostile one. They do not replace authorization or rate limiting. Authorization is out of scope here. Still, broad access together with easy discovery widens how much a tricked or compromised agent can reach. Scope access narrowly to the task. That limits the damage an injected instruction can do.

18. Agent-Friendly Profile Summary

An HTTP API meant for agents can be called agent-friendly, in the sense of this document, when:

19. IANA Considerations

This document has no IANA actions. It does not define any protocol element, header field, media type, or registry entry. The field names used in the error examples in Section 9 are only examples. If such Problem Details fields are ever standardized, registering them would be the job of that later specification.

20. References

20.1. Normative References

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC9110]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, , <https://www.rfc-editor.org/info/rfc9110>.
[RFC9457]
Nottingham, M., Wilde, E., and S. Dalal, "Problem Details for HTTP APIs", RFC 9457, , <https://www.rfc-editor.org/info/rfc9457>.

20.2. Informative References

[I-D.httpapi-idem]
IETF HTTP API Working Group, "The Idempotency-Key HTTP Header Field", Work in Progress, Internet-Draft, draft-ietf-httpapi-idempotency-key-header, , <https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/>.
[I-D.klrc-aiagent-auth]
Kasselman, P., Lombardo, J., Rosomakho, Y., and B. Campbell, "AI Agent Authentication and Authorization", Work in Progress, Internet-Draft, draft-klrc-aiagent-auth, , <https://datatracker.ietf.org/doc/draft-klrc-aiagent-auth/>.
[I-D.oauth-ai-agents-obo]
IETF, "OAuth 2.0 Extension: On-Behalf-Of User Authorization for AI Agents", Work in Progress, Internet-Draft, draft-oauth-ai-agents-on-behalf-of-user, , <https://datatracker.ietf.org/doc/draft-oauth-ai-agents-on-behalf-of-user/>.
[LLMSTXT]
Howard, J., "The /llms.txt file", , <https://llmstxt.org/>.
[MCP]
Model Context Protocol, "Model Context Protocol Specification", , <https://modelcontextprotocol.io/specification>.
[OPENAPI]
OpenAPI Initiative, "OpenAPI Specification", , <https://spec.openapis.org/oas/latest.html>.
[RFC7591]
Richer, J., Ed., "OAuth 2.0 Dynamic Client Registration Protocol", RFC 7591, , <https://www.rfc-editor.org/info/rfc7591>.
[RFC8693]
Jones, M., Nadalin, A., Campbell, B., Ed., Bradley, J., and C. Mortimore, "OAuth 2.0 Token Exchange", RFC 8693, , <https://www.rfc-editor.org/info/rfc8693>.
[RFC8707]
Campbell, B., Bradley, J., and H. Tschofenig, "Resource Indicators for OAuth 2.0", RFC 8707, , <https://www.rfc-editor.org/info/rfc8707>.
[RFC9728]
Jones, M., Hunt, P., and A. Parecki, "OAuth 2.0 Protected Resource Metadata", RFC 9728, , <https://www.rfc-editor.org/info/rfc9728>.
[W3C-TRACE-CONTEXT]
W3C, "Trace Context", W3C Recommendation, , <https://www.w3.org/TR/trace-context/>.

Appendix A. Example: MCP Tools for a Project Management System

This appendix applies the profile to a Model Context Protocol [MCP] server for a project management system. The system has projects, tasks, and assignees. Each tool uses a strict JSON Schema, so the model can find and call it without inventing parameters. Every input schema sets additionalProperties to false, uses a fixed value set for closed choices, marks the required fields, and bounds the size of any collection.

An agent is often told a project by name, not by identifier. A lookup tool turns the name into an identifier the other tools need. This follows the rule in Section 7 not to demand an identifier the agent cannot get:

{
  "name": "find_projects",
  "description": "Find projects by name.",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["name_contains"],
    "properties": {
      "name_contains": { "type": "string" },
      "limit": {
        "type": "integer",
        "minimum": 1, "maximum": 20, "default": 10
      }
    }
  }
}

A creation tool keeps a strict input schema. Its description, kept short in the example, should also say that the operation notifies the assignee, point the agent to find_projects when it has only a name, and explain that reusing the idempotency_key returns the original task instead of making a duplicate:

{
  "name": "create_task",
  "description": "Create a task in a project.",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["project_id", "title"],
    "properties": {
      "project_id": { "type": "string" },
      "title": { "type": "string", "maxLength": 200 },
      "assignee_email": { "type": "string", "format": "email" },
      "priority": {
        "type": "string",
        "enum": ["low", "medium", "high"],
        "default": "medium"
      },
      "idempotency_key": { "type": "string" }
    }
  }
}

A search tool bounds its result size and returns an opaque cursor, so the agent never computes an offset. The status filter lets it narrow the results before it fetches them:

{
  "name": "find_tasks",
  "description": "Search tasks in a project (bounded page).",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["project_id"],
    "properties": {
      "project_id": { "type": "string" },
      "status": {
        "type": "string",
        "enum": ["open", "in_progress", "done"]
      },
      "limit": {
        "type": "integer",
        "minimum": 1, "maximum": 50, "default": 20
      },
      "cursor": { "type": "string" }
    }
  }
}

A result is bounded. It carries human-readable labels and a next action, and it gives back a cursor for the following page:

{
  "tasks": [
    {
      "task_id": "t_8a1",
      "title": "Draft launch checklist",
      "status": "in_progress",
      "assignee": { "id": "u_42", "name": "Priya Rao" },
      "next_actions": { "complete": "update_task_status" }
    }
  ],
  "next_cursor": "eyJvIjoyMH0"
}

To read the next page, the agent calls the same tool again and passes the cursor straight back. It does no arithmetic:

{
  "name": "find_tasks",
  "arguments": {
    "project_id": "p1",
    "status": "open",
    "cursor": "eyJvIjoyMH0"
  }
}

A batch tool creates several tasks in one call. It bounds the array size, and its result reports one outcome per item, so the agent can see which tasks were created and which were rejected:

{
  "name": "create_tasks_batch",
  "description": "Create several tasks in one project.",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["project_id", "tasks"],
    "properties": {
      "project_id": { "type": "string" },
      "idempotency_key": { "type": "string" },
      "tasks": {
        "type": "array",
        "maxItems": 50,
        "items": {
          "type": "object",
          "additionalProperties": false,
          "required": ["title"],
          "properties": {
            "title": { "type": "string", "maxLength": 200 },
            "priority": {
              "type": "string",
              "enum": ["low", "medium", "high"]
            }
          }
        }
      }
    }
  }
}

The batch result shows the per-item outcomes. One task was created and one was rejected, and the agent can tell exactly which is which:

{
  "results": [
    { "index": 0, "status": "created", "task_id": "t_901" },
    { "index": 1, "status": "rejected", "code": "TITLE_TOO_LONG" }
  ],
  "created_count": 1,
  "rejected_count": 1
}

A state-changing tool uses a fixed value set for the closed list of states and accepts an idempotency key. Its description should note the side effect of notifying the assignee:

{
  "name": "update_task_status",
  "description": "Move a task to a new workflow state.",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["task_id", "status"],
    "properties": {
      "task_id": { "type": "string" },
      "status": {
        "type": "string",
        "enum": ["open", "in_progress", "done", "cancelled"]
      },
      "idempotency_key": { "type": "string" }
    }
  }
}

Each choice maps back to the profile. The intent-revealing names and the use-when guidance reduce wrong-operation mistakes (Section 5). The fixed value sets and additionalProperties: false stop the agent from inventing values and parameters. The bounded limit and the opaque cursor follow Section 8. The idempotency key and the stated side effects follow Section 10. The batch result follows the partial-failure rule in Section 7.

Appendix B. Example: A Weak and a Strong Operation Description

An operation described only well enough for someone who already knows the system leaves the agent to guess its scope and its side effects:

# Too little for an agent
operationId: updateUser
summary: Updates a user

The same operation, described for an agent, names its exact purpose, says when not to use it, and states the side effect:

# Enough for an agent
operationId: updateUserEmailAddress
summary: Change a user's email address
description: >
  Use this only to change an existing user's email address. Do not
  use it for other profile fields. Use updateUserProfile for those.
  Side effect: sends a verification email. The new address stays
  unverified until the user confirms it.

Appendix C. Example: A Small Response with Field Selection

The request selects three fields and a bounded page, so the response stays small. The response gives back a ready-to-use link for the next page, so the agent does no offset arithmetic:

GET /projects/p1/tasks?status=open&fields=id,title,status&limit=20
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json

{
  "items": [
    {
      "id": "t_8a1",
      "title": "Draft launch checklist",
      "status": "open"
    }
  ],
  "next_page": "/projects/p1/tasks?status=open&cursor=eyJvIjoyMH0",
  "next_cursor": "eyJvIjoyMH0"
}

Appendix D. Example: Previewing a Destructive Write

A dry-run request reports what an operation would do, without doing it. The agent can check the predicted effects and decide whether to go ahead:

POST /projects/p1/archive
X-Dry-Run: true
Content-Type: application/json

{ "reason": "Project completed" }

HTTP/1.1 200 OK
Content-Type: application/json

{
  "dry_run": true,
  "would_change": {
    "project_status": { "from": "active", "to": "archived" },
    "tasks_closed": 14,
    "members_notified": 6
  },
  "reversible": true
}

Sending the same request without the X-Dry-Run header performs the operation. The predicted-effects shape is the same, so the agent can use it to decide whether to go ahead or to ask for confirmation first.

Acknowledgments

This document gathers considerations discussed across the API design and AI agent engineering communities. The author thanks the authors of the referenced specifications and drafts, whose work covers the identity and authorization topics this document leaves to them, and the reviewers whose feedback shaped the profile structure, the worked examples, and the treatment of context exhaustion and observability.

Author's Address

Madhava Gaikwad
Independent
Bengaluru
India