Archives

MY APPROACH

The right solution, not the biggest solution.

You don't need to know whether your problem needs an API, an automation workflow, a dashboard or a custom application.

Tell me the problem. I'll help figure out a practical way to solve it.

Designing APIs for AI Agents: When Your API Becomes a Tool

PHP

We have been designing APIs for a long time.

We know how to handle authentication, validation, authorization, duplicate requests, failures, transactions, timeouts, retries, pagination, and consistent responses.

So what actually changes when an API is going to be consumed by an AI agent?

The answer is not simply:

"Make the API more reliable."

A good API should already be reliable.

The bigger change is who decides what to do with the API.

In a traditional application, a human decides what they want to do and uses an application to perform that task.

In an agentic system, the human can describe the goal and delegate the task to an agent.

The agent then decides which available capability to use, provides the required information, observes the result, and decides what to do next.

That changes the role of the API.

The API is no longer only a communication contract between software components.

It becomes a set of capabilities that an autonomous system can choose to use.


First, Separate the Three Actors

Before talking about API design, we need to separate three different actors.

They are often mixed together when people discuss "AI APIs."

1. The human developer

The developer still does what developers have always done.

They need to understand:

  • what the API does

  • what inputs it accepts

  • what it returns

  • authentication

  • authorization

  • business rules

  • errors

  • side effects

  • limitations

The developer builds the system around the API.

Nothing fundamentally changes here.


2. The human user

The human user wants something done.

For example:

"Find me a flight to Delhi next Monday."

Or:

"Cancel my order and get my refund."

The user doesn't necessarily know which API endpoint should be called.

They shouldn't have to.


3. The agent

The agent sits between the human and the system.

It receives the user's goal and uses available capabilities to accomplish it.

For example:

Human
  │
  │ "Cancel my order."
  ▼
Agent
  │
  │ decides which capability is required
  ▼
cancel_order()
  │
  ▼
API
  │
  ▼
Business Logic

This is the important change.

The developer hasn't disappeared.

The API hasn't necessarily changed completely.

A new decision-making layer has been introduced between the user and the API.


Human-Driven Application vs Agentic System

Consider a normal application.

Human
   │
   ▼
UI
   │
   ▼
Application
   │
   ▼
API
   │
   ▼
Business Logic

The UI determines much of what the user can do.

Suppose the user wants to cancel an order.

The application may show:

Order #1234

[Track Order]

[Cancel Order]

The developer has already decided:

  • where the button appears

  • when it appears

  • what it does

  • which API it calls

  • what parameters are sent

  • how the response is displayed

The human chooses the action.

Now consider an agentic system.

Human
   │
   │ "Cancel my order."
   ▼
Agent
   │
   ├── get_order()
   │
   ├── check_cancellation_policy()
   │
   └── cancel_order()
             │
             ▼
            API

There may be no button.

The agent has to determine which capability is relevant.

This is where the API design problem becomes different.


APIs Become Capabilities

When a human uses an application, an API is usually hidden behind the application.

The user sees:

Cancel Order

The developer may implement:

POST /orders/123/cancel

The human never needs to know the endpoint.

With an agent, that capability may be exposed as a tool:

cancel_order

with a description such as:

Cancel an order that has not entered shipment.
Use this when the customer explicitly wants to cancel
an existing order.

The agent may receive several tools:

search_products
get_product
create_order
get_order
cancel_order
request_refund
contact_support

It must determine which capability is appropriate.

Tool-calling systems commonly expose a function's name, description, and parameter schema to the model so that it can select and invoke the function.

This gives us an important principle:

When an API is used by an agent, the API's capabilities become part of the agent's decision space.

That is the real shift.


What Does This Change for API Developers?

It does not mean you throw away everything you already know about API design.

You still need:

  • authentication

  • authorization

  • validation

  • transactions

  • idempotency

  • retries

  • rate limiting

  • consistent errors

  • observability

  • security

These remain fundamental.

But you now have additional questions.

For example:

Can the agent understand what this operation is for?

Can it distinguish this operation from similar operations?

Does it know when it should use the operation?

Does it know when it should not use it?

Does it have enough context to call it correctly?

Can it understand the result?

Can it distinguish "nothing happened" from "the operation failed"?

Can it safely continue the task?

Can it recognize when it needs the human?

These are the areas where agent-oriented API design becomes different.


1. Design the API Around Capabilities

One of the first questions should be:

What meaningful things can an agent do with this system?

Consider an e-commerce application.

You could expose generic operations:

get()
create()
update()
delete()

Technically, that may be enough.

But these operations don't necessarily describe the business capabilities.

An agent may need:

search_products
get_order
cancel_order
track_order
request_refund

These names communicate intent much better.

Compare:

update_order()

with:

cancel_order()

The second one tells both the developer and the agent what the operation actually means.

It also gives your backend an opportunity to enforce the business rules around cancellation.

The agent doesn't need to know how cancellation works internally.


2. Make Tool Names Meaningful

When a human developer reads:

update_order

they can open the documentation and investigate.

An agent has to make a decision based partly on the information exposed to it.

Suppose it has:

update_order
cancel_order
refund_order

A good description should make the difference clear.

For example:

cancel_order

Cancels an existing order when it has not entered shipment.
Use only when the customer wants to cancel the order.
A refund may be initiated automatically for paid orders.

And:

refund_order

Requests a refund for an eligible paid order.
Use when the customer wants money returned for an
order that is eligible for refund.

Now the capabilities are easier to distinguish.

This matters because tool descriptions are not just documentation anymore.

They can influence tool selection.

MCP's tool model explicitly includes a human-readable description intended to help clients improve the model's understanding of what the tool does and when to use it.


3. Make the Boundary of Each Capability Clear

A tool should have a clear responsibility.

Avoid creating a tool such as:

manage_order()

with parameters like:

{
    "action": "cancel",
    "operation": "something",
    "mode": "..."
}

Now the agent has to understand a mini-language inside the tool.

Prefer:

cancel_order()
update_shipping_address()
request_refund()

Each operation has a clear purpose.

This is easier for:

  • the developer

  • the agent

  • authorization

  • auditing

  • testing

  • monitoring


4. Tell the Agent What the Tool Needs

Imagine:

cancel_order(order_id)

The developer understands that order_id is required.

But what if the user says:

"Cancel my order."

Which order?

If the agent has already retrieved the user's active order, it may know.

If not, it needs another capability:

get_customer_orders()

This leads to an important concept:

A tool should clearly define its prerequisites.

For example:

cancel_order

Requires:
- a valid order ID
- the order must belong to the current customer
- the order must not have entered shipment

Some prerequisites can be enforced by the API itself.

Others need to be discoverable so that the agent knows what information it needs before acting.


5. Context Becomes Important

Humans naturally carry context.

Suppose a user says:

"Book it for tomorrow."

A human understands "it" from the conversation.

An agent needs enough context to resolve:

it = what?
tomorrow = which date?
book = which operation?

The API cannot solve every conversational ambiguity.

But API design can make context explicit.

Instead of expecting an agent to construct hidden state, expose useful identifiers and relationships:

{
    "customer_id": "cus_123",
    "order_id": "ord_456",
    "status": "pending"
}

The agent can then use those identifiers in subsequent operations.

A good API gives the agent enough information to continue a workflow without forcing it to rediscover basic context repeatedly.


6. State Matters More Than It First Appears

Humans are good at understanding state.

If you see:

Order #1001
Shipped

you immediately understand that cancelling it may not be possible.

An agent needs the state to be explicit.

For example:

{
    "id": "1001",
    "status": "shipped",
    "cancellation": {
        "allowed": false
    }
}

Now the agent does not have to infer that:

shipped → cancellation probably not allowed

The API has already communicated the relevant business state.

This is particularly important when the system has workflows such as:

draft
  ↓
confirmed
  ↓
processing
  ↓
shipped
  ↓
delivered

If an agent is going to act on these resources, the states and allowed transitions need to be clear.


7. Don't Make the Agent Guess Business Rules

Consider:

PATCH /orders/123

with:

{
    "status": "cancelled"
}

The agent might think:

"The user asked me to cancel it, so I should change the status."

But the actual business rules might be:

pending      → can cancel
confirmed    → can cancel
processing   → cannot cancel
shipped      → cannot cancel
delivered    → cannot cancel

The API should enforce this.

Even better, expose:

POST /orders/123/cancel

The server knows how cancellation works.

This gives us another important principle:

The agent should decide what the user wants. The application should decide whether and how that action is legally and technically performed.

Never move critical business rules into the prompt.


8. Make Side Effects Understandable

An API operation may do more than its name suggests.

For example:

cancel_order()

may also:

cancel shipment
refund payment
release inventory
send email
send SMS
create audit record

A human developer can discover these side effects from documentation.

An agent needs them to be clearly communicated too.

The tool description could say:

Cancels the order and, when applicable, initiates a refund.
The operation may also cancel an associated shipment.

Why does this matter?

Because the agent may be deciding between:

cancel_order()

and:

request_refund()

The difference in side effects matters to that decision.


9. Separate Read Operations From Actions

This is a useful pattern for agentic systems.

Consider:

get_order()
cancel_order()

The first observes.

The second changes the system.

That distinction is important.

An agent may safely call:

get_order()

while it may need confirmation before:

cancel_order()

This gives you a natural way to classify capabilities:

READ

get_order
get_customer
search_products
check_inventory

versus:

WRITE / ACTION

create_order
cancel_order
request_refund
change_address

The API can then apply stronger authorization, confirmation, or approval requirements to actions.


10. Some Actions Need Human Approval

Delegation does not necessarily mean:

"Let the agent do everything."

Often the human wants to delegate routine work while retaining control over important decisions.

For example:

Find a suitable laptop under ₹80,000

could be delegated completely.

But:

Purchase the laptop for ₹80,000

may require confirmation.

The API/tool boundary should support this distinction.

For example:

search_products()

can be performed automatically.

But:

place_order()

could require an approval step.

A useful workflow might be:

Human
  │
  │ "Find me a laptop."
  ▼
Agent
  │
  ├── search_products()
  ├── compare_products()
  └── present recommendation
              │
              ▼
          Human approval
              │
              ▼
        place_order()

This is an important part of agentic API design:

The API should make it possible to control which actions can happen autonomously and which require human involvement.


11. Tools Should Be Composable

An agent often completes a task using several capabilities.

Suppose the user says:

"Find my pending order and cancel it."

The workflow might be:

get_my_orders()
       ↓
find pending order
       ↓
cancel_order()

Or:

search_products()
       ↓
get_product()
       ↓
check_inventory()
       ↓
create_order()

Each tool should therefore have a clear boundary and predictable output.

The agent can then compose them into a workflow.

This is very different from exposing one giant function:

do_everything()

Good tool design is often about finding the right level of granularity.

Not too small:

get_order_database_row()

Not too large:

handle_customer_request()

Instead:

get_order()
cancel_order()
request_refund()

Each represents a meaningful business capability.


12. Return Results That Help the Next Decision

Consider this response:

{
    "success": true
}

A human developer may understand what happened from the HTTP status and documentation.

An agent needs enough information to decide what happens next.

For example:

{
    "order": {
        "id": "ord_1001",
        "status": "cancelled"
    },
    "refund": {
        "status": "initiated",
        "amount": 1499,
        "currency": "INR"
    }
}

Now the agent knows:

Order = cancelled
Refund = initiated
Amount = ₹1499

It can tell the user:

"Your order was cancelled and a refund of ₹1,499 has been initiated."

The response is not merely reporting technical success.

It communicates the new business state.


13. Errors Should Tell the Agent What Happened

We already design APIs to handle errors.

But with agents, the meaning of the error becomes especially important.

Consider:

{
    "error": "Unable to cancel order"
}

The agent doesn't know what to do next.

Compare:

{
    "error": {
        "code": "ORDER_ALREADY_SHIPPED",
        "message": "The order cannot be cancelled because it has already shipped.",
        "current_status": "shipped",
        "retryable": false
    }
}

Now the agent can stop trying.

It can tell the user:

"I couldn't cancel the order because it has already shipped."

The important point isn't that the error is verbose.

It is that the error gives the agent a usable state and reason.


14. Distinguish Failure From "Action Not Allowed"

These are different situations.

Technical failure

PAYMENT_PROVIDER_TIMEOUT

The operation may be retried or checked again.

Business restriction

ORDER_ALREADY_SHIPPED

Retrying will not help.

Missing information

SHIPPING_ADDRESS_REQUIRED

The agent should ask the user for information.

Permission problem

REFUND_REQUIRES_APPROVAL

The agent should follow the approval workflow.

These aren't merely different error messages.

They imply different next decisions.

That is why stable error codes and structured error information are valuable in agentic systems.


15. Give the Agent a Way to Know When the Task Is Complete

This is easy to overlook.

A human knows when they have finished a task.

An agent may need explicit signals.

Suppose the user says:

"Book me a hotel."

The workflow could involve:

search hotels
     ↓
check availability
     ↓
select hotel
     ↓
create booking
     ↓
payment
     ↓
booking confirmation

Returning:

{
    "success": true
}

after create_booking() may not mean the overall task is complete.

A better response might contain:

{
    "booking": {
        "id": "BK123",
        "status": "confirmed",
        "confirmation_number": "ABC789"
    }
}

Now the agent has evidence that the business operation completed.

This leads to a useful question for every action:

What observable result tells the caller that this operation actually succeeded?


16. Don't Hide Important State Inside Human-Friendly Text

This response is difficult for machines:

"Your order was successfully cancelled and the refund
should reach you in 5-7 working days."

It is nice for a human.

But the important information is mixed into prose.

Prefer:

{
    "order_status": "cancelled",
    "refund_status": "initiated",
    "refund_amount": 1499,
    "refund_currency": "INR",
    "estimated_refund_days": 7
}

The agent can then turn that structured information into natural language for the user.

This is an important separation:

API
  ↓
structured business information
  ↓
Agent
  ↓
human-friendly explanation

The API should provide facts.

The agent can decide how to communicate those facts to the user.


17. The API Should Still Be the Final Authority

This is perhaps the most important safety principle.

Suppose your system says:

Refunds above ₹10,000 require approval.

Do not rely on the agent to remember that rule.

The API must enforce it.

The agent might decide:

request_refund(15000)

The server should respond:

{
    "error": {
        "code": "REFUND_APPROVAL_REQUIRED",
        "message": "Refunds above ₹10,000 require human approval.",
        "required_approval": true
    }
}

The agent can then initiate the approval workflow.

This architecture is safer:

Agent decides
      ↓
API validates
      ↓
Business rules
      ↓
Authorization
      ↓
Execute

Not:

Agent decides
      ↓
Trust the agent
      ↓
Execute

The agent is a decision-maker, not the authority over your business rules.


18. Think About the Agent's Decision Surface

This is perhaps the simplest way to think about the whole topic.

Imagine giving a human employee access to your company's internal systems.

You would ask:

What actions are we allowing this person to perform?

For an agent, ask the same question.

If you expose:

delete_customer
issue_refund
change_account_owner
transfer_money
send_email

you have created a large decision surface.

The agent can potentially choose among those capabilities.

Therefore:

Every tool you expose is an available action.

Don't expose a capability simply because you have an endpoint for it.

Expose capabilities because the agent genuinely needs them.

This is one reason tool design should be intentional rather than simply turning every REST endpoint into a tool.


19. Your Existing API May Already Be Good Enough

This is an important point.

You don't necessarily need:

/api/v2/ai/orders
/api/v2/ai/products
/api/v2/ai/customers

just because an agent is going to consume the API.

If your existing API already provides:

  • clear operations

  • strong validation

  • predictable responses

  • structured errors

  • authorization

  • idempotency

  • stable resource identifiers

  • clear business states

  • well-defined side effects

then it may already be an excellent foundation.

The agent layer can expose those capabilities as tools.

For example:

Existing API

POST /orders/{id}/cancel

can become:

Tool

cancel_order(order_id)

The important work may be in the tool definition and orchestration layer, rather than rewriting the entire backend.

MCP, for example, explicitly models tools with names, descriptions, and input schemas, and tool implementations can validate arguments against those schemas before execution.


20. Think in Two Contracts

When designing for an agentic system, there are effectively two contracts.

Contract 1: Developer contract

The traditional API contract:

HTTP method
URL
authentication
request
response
status codes
errors
business rules

The human developer uses this to build the system.


Contract 2: Agent capability contract

The agent-facing contract:

What can I do?
When should I use this capability?
What information do I need?
What will happen?
What will change?
What can go wrong?
What does success look like?
What should I do after the result?

These contracts can be backed by the same underlying API.

But the second contract needs to make capability and decision boundaries clear.

That's the major addition.


A Simple Example

Imagine a courier system.

A traditional application might expose:

GET  /shipments/{id}
POST /shipments
PATCH /shipments/{id}

A human developer can build a UI around these APIs.

Now suppose you want an agent to handle:

"Where is my package?"

The agent might have:

track_shipment(shipment_id)

The user asks:

"Where is my package?"

The agent:

1. identifies the shipment
2. calls track_shipment()
3. receives structured tracking information
4. explains the current status

Now the user asks:

"Can you change the delivery address?"

The agent needs another capability:

change_delivery_address()

But that capability may have restrictions.

For example:

Before shipment:
    allowed

After shipment:
    requires manual review

The agent doesn't need to invent these rules.

The API enforces them.

The tool description makes the capability understandable.

The response tells the agent what happened.

This is the model we want.


A Practical Checklist for Agent-Ready APIs

Before exposing an API as a tool, ask:

Capability

  • Does this operation represent a meaningful business capability?

  • Is its name clear?

  • Is its responsibility narrow enough?

  • Is it obvious when it should be used?

Context

  • What information must the agent already have?

  • Can the agent obtain that information through another capability?

  • Are identifiers stable and easy to pass between operations?

Inputs

  • Are required parameters explicit?

  • Are allowed values constrained?

  • Are ambiguous values avoided?

  • Can invalid arguments be rejected before execution?

Modern tool protocols and SDKs increasingly use schemas for exactly this purpose: tool inputs can be described and validated before the underlying operation runs.

State

  • Can the agent understand the current state?

  • Are valid state transitions enforced?

  • Can it distinguish "already done" from "failed"?

Side effects

  • What will this operation change?

  • Does it trigger other actions?

  • Does it affect money, permissions, messages, or external systems?

Human control

  • Which actions can happen automatically?

  • Which require confirmation?

  • Which require approval?

Output

  • Does the response clearly describe the resulting business state?

  • Can the agent determine what happened without parsing prose?

  • Is there enough information to continue the task?

Failure

  • Is there a stable error code?

  • Does the error explain what happened?

  • Can the agent determine whether to retry, correct, ask the user, or stop?

Security

  • Is authorization enforced by the server?

  • Are permissions scoped to the user and agent?

  • Can the agent access only the capabilities it actually needs?

Observability

  • Can you identify which user initiated the task?

  • Can you identify which agent performed the action?

  • Can you reconstruct the sequence of tool calls?

  • Can you audit important actions?


The Mental Model to Remember

You don't need to learn a completely new philosophy of API development because AI agents exist.

Instead, add one question to your existing API design process:

What happens if the caller is not a human developer-controlled application, but an autonomous system deciding which capability to invoke on behalf of a human?

That question exposes several things that traditional APIs can leave implicit.

You start thinking about:

Capability
    ↓
When should it be used?
    ↓
What does it need?
    ↓
What will it change?
    ↓
What can go wrong?
    ↓
What does success look like?
    ↓
What can happen next?
    ↓
When should the human take over?

And that is the real difference.

The human developer is still there.

The API is still there.

The business logic is still there.

But now there is an additional layer:

                    Human
                      │
                      │ goal
                      ▼
                    Agent
                      │
             chooses a capability
                      │
                      ▼
               Tool / Function
                      │
                      ▼
                     API
                      │
                      ▼
               Business Logic
                      │
                      ▼
                  Data / Services

The API therefore needs to be more than technically callable.

Its capabilities, boundaries, context, state, side effects, and outcomes need to be understandable to the system making the decision to call it.

That is what makes an API ready for an agentic system.

And perhaps the simplest way to remember it is this:

A human uses an application to decide what the system should do. An agent uses tools to decide what the system should do on the human's behalf.

The better we define those tools and the boundaries around them, the more safely and reliably we can delegate work to agents.

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment

RDA
Rashid Anwar
Independent Developer

I’m Rashid, an independent developer focused on practical software solutions for businesses.

HAVE A PROJECT IN MIND?

Let's talk about the problem you're trying to solve.

Share what you need. We can discuss the requirements and a practical next step.

Start a Conversation