Why successful API calls are no longer enough when AI agents can take real-world actions
For most backend systems, 200 OK is comforting.
It means the request reached the server, passed validation, and completed successfully.
For an AI agent, however, 200 OK can hide one of the most dangerous failure modes in modern software:
The API did exactly what the agent asked — but the agent asked for the wrong thing.
Imagine an AI-powered banking assistant.
A customer says:
“Refund the duplicate payment from yesterday.”
The agent retrieves several transactions, identifies what it believes is the duplicate, and calls:
POST /refunds
The request is authenticated.
The agent is authorised.
The transaction ID exists.
The refund API processes the request successfully.
HTTP/1.1 200 OK
Every technical dashboard is green.
But the agent selected the wrong transaction.
The API succeeded.
The business outcome failed.
As AI systems evolve from chatbots that recommend actions into agents that execute them, backend engineers need to rethink what “success” actually means.
The Problem: We Treat Success as a Single Layer
Traditional systems usually measure success at several technical levels.
At the network layer:
Did the request reach the service?
At the API layer:
Did the service return a successful response?
At the database layer:
Did the transaction commit?
That works reasonably well when deterministic application code has already decided what operation should happen.
For example:
refundService.refund(transactionId);
The developer has chosen:
- which service to call,
- which transaction to target,
- when the call should happen,
- what should happen after it succeeds.
Agentic systems change this relationship.
An AI agent may be given tools such as:
findCustomer()
lookupTransaction()
issueRefund()
cancelOrder()
sendEmail()
disableAccount()
restartService()
The model then determines:
Which tool should I call?
Which parameters should I use?
Should I retry?
What should I do next?
We have introduced probabilistic reasoning before deterministic side effects.
That means we need another definition of success.
Three Levels of Success
I find it useful to separate agent success into three layers.
1. Transport Success
Did the technical request complete?
HTTP/1.1 200 OK
2. Execution Success
Did the backend perform the requested operation?
Refund created successfully.
3. Intent Success
Did the system perform the right action, on the right resource, for the right user, under the right conditions, exactly as intended?
For a refund that might mean:
Correct customer
Correct transaction
Correct amount
Correct reason
Correct approval
Exactly once
The first two are familiar engineering problems.
The third becomes much more important once AI starts selecting and sequencing actions dynamically.
Failure Mode 1: The API Correctly Executes the Wrong Decision
Consider this user request:
“Refund the most recent duplicate charge.”
The agent receives:
[
{
"id": "TX-18419",
"amount": 2500,
"merchant": "ABC Store"
},
{
"id": "TX-18491",
"amount": 2500,
"merchant": "ABC Store"
}
]
The agent incorrectly chooses:
TX-18491
and sends:
{
"transactionId": "TX-18491",
"amount": 2500
}
The backend validates the request.
The account has sufficient authority.
The transaction exists.
The refund executes.
Technically, there is no error.
But the customer wanted another transaction refunded.
This is an important distinction:
API correctness does not guarantee semantic correctness.
The service knows how to refund a transaction.
It does not necessarily know whether the AI chose the correct transaction.
Failure Mode 2: The Agent Retries Something That Already Worked
Now imagine the refund really is correct.
The agent calls the service.
Agent → Refund API
The refund succeeds.
But the response is lost.
The agent sees:
Timeout
It reasons:
“The refund probably failed. I should retry.”
The second call also succeeds.
Without protection, one user intent may produce multiple real-world side effects.
This problem is familiar to payment engineers and distributed-systems developers.
The difference is that with autonomous agents, retries may not come from a predefined retry library.
The model itself can decide:
“Let me try that again.”
That makes idempotency even more important.
Give Every Important Action an Intent ID
We already use identifiers such as:
request_id
trace_id
span_id
Those identify technical execution.
Agents also need something representing the business objective.
For example:
intent_id = REFUND_DUPLICATE_CHARGE_8472
One intent may generate many technical requests:
REFUND_DUPLICATE_CHARGE_8472
|
+-- lookup transaction
|
+-- validate eligibility
|
+-- create refund
|
+-- update CRM
|
+-- notify customer
Suppose the refund API times out.
Instead of asking:
Should I POST /refunds again?
the system can ask:
Has REFUND_DUPLICATE_CHARGE_8472
already produced a successful refund?
That is a much safer abstraction.
A Simple Intent Model
Conceptually:
public record AgentIntent(
UUID intentId,
String userId,
String action,
String resourceId,
IntentStatus status,
String resultId
) {}
With:
public enum IntentStatus {
PENDING,
EXECUTING,
COMPLETED,
REQUIRES_REVIEW,
FAILED
}
Before executing a mutation:
AgentIntent intent = intentRepository.findById(intentId)
.orElseThrow();
if (intent.status() == IntentStatus.COMPLETED) {
return previousResult(intent.resultId());
}
The exact implementation will vary.
The principle is what matters:
A retry should refer to the same business intent instead of silently becoming a new action.
Failure Mode 3: Every Tool Succeeds, but the Workflow Is Wrong
Imagine an account-closing agent.
It successfully executes:
✓ Cancel subscription
✓ Revoke API credentials
✓ Delete files
✓ Generate final invoice
✓ Close account
Every API returns success.
But company policy requires:
Export compliance archive
BEFORE
Delete files
The agent skipped the archive.
Five green tool calls.
One invalid business process.
This is why agent observability cannot stop at:
Tool call succeeded
We need to ask:
Was the workflow itself valid?
Put a Deterministic Gate Between Reasoning and Mutation
For read-only operations, directly exposing tools may be reasonable.
For high-impact actions, I prefer an architecture like:
User Goal
↓
AI Agent
↓
Intent + Policy Gate
↓
Tool Gateway
↓
Business API
↓
Outcome Verification
Before issuing a refund, deterministic code can verify:
transaction belongs to authenticated user
AND transaction is refundable
AND amount <= remaining refundable amount
AND approval threshold is satisfied
AND intent has not already completed
The model proposes.
The system verifies.
The API executes.
The system verifies again.
That separation is important.
Authorised Does Not Mean Appropriate
Security controls still matter enormously.
But authorisation alone does not solve every agent problem.
Suppose an agent legitimately has permission to call:
restartProductionService()
The credentials are valid.
The operator has the correct role.
But should the service restart now?
Perhaps:
a deployment is currently running
or:
an incident is already active
or:
traffic is at its daily peak
or:
another restart happened 30 seconds ago
Authentication answers:
Who are you?
Authorisation answers:
Are you allowed to perform this operation?
Agentic systems also need:
Is this action appropriate in the current context?
That requires policy, state, and sometimes human judgement.
Define Preconditions and Postconditions
Many tools are described approximately like this:
name: issue_refund
description: Refund a customer transaction
That tells the model what the tool does.
It does not define the conditions that make using it safe.
A stronger contract might be:
tool: issue_refund
preconditions:
- transaction belongs to authenticated customer
- transaction is refundable
- amount <= remaining refundable balance
execution:
idempotency_required: true
postconditions:
- refund record exists
- refund references expected transaction
- refund amount matches approved amount
- ledger state reconciles
approval:
required_above: 5000
Now success is not simply:
function returned successfully
It becomes:
preconditions satisfied
+
action executed
+
postconditions verified
Don’t Let the Agent Grade Its Own Homework
A tempting pattern is:
Agent performs action
↓
Agent asks itself:
"Did that work?"
↓
Agent continues
For low-risk workflows, this may be sufficient.
For important actions, it is fragile.
If the model misunderstood the original request, asking the same model whether its interpretation was correct may reproduce the same mistake.
High-impact actions should be verified against external evidence:
database state
payment receipt
ledger state
policy engine
independent validator
sensor state
human approval
The model can reason about these signals.
It should not invent them.
Observability Needs to Move Above HTTP
Imagine this dashboard:
refund-api availability: 99.99%
tool-call success rate: 98.9%
average API latency: 310 ms
Everything appears healthy.
But you are not measuring:
wrong-target actions
duplicate mutations
policy violations
unverified outcomes
human reversals
Agentic systems need higher-level metrics.
For example:
verified_outcome_rate
duplicate_action_rate
postcondition_failure_rate
human_override_rate
ambiguous_outcome_rate
intent_reconciliation_rate
A meaningful future SLO might look like:
99.95% of high-impact agent intents complete with a verified business outcome and no duplicate side effect.
That tells us far more than API availability.
A Safer End-to-End Example
Suppose a user tells an AI commerce agent:
“Cancel my duplicate order and refund it.”
Instead of immediately executing actions, the workflow could be:
1. Create intent
CANCEL_DUPLICATE_ORDER_9821
2. Retrieve candidate orders
3. Deterministically verify:
- same customer
- duplicate item
- matching amount
- cancellable state
4. Generate action preview:
Cancel Order A1842
Refund £74.99
5. Request human confirmation if required
6. Cancel order using intent ID
7. Issue refund using same intent context
8. Verify:
order == CANCELLED
refund == CONFIRMED
refund amount == £74.99
9. Mark intent COMPLETED
10. Tell user:
"Done"
Step 10 is the important part.
The agent does not say “done” because it received 200 OK.
It says “done” because the system verified the intended business outcome.
Six Controls I’d Use for High-Impact Agent Actions
For any agent capable of moving money, modifying production systems, changing permissions, deleting information, or performing irreversible actions:
1. Explicit intent
Persist the actual business objective.
2. Least-privilege tools
Expose only capabilities required for the task.
3. Deterministic preconditions
Keep critical business rules outside the model.
4. Idempotent mutations
Design retries so repeating a request does not repeat the side effect.
5. Independent postcondition verification
Verify the resulting state using trusted systems.
6. Outcome-level auditability
Connect:
user intent
→ agent decision
→ policy result
→ tool call
→ API response
→ verified business state
That gives us:
Intent
↓
Policy
↓
Action
↓
Receipt
↓
Verification
↓
Outcome
instead of:
Prompt
↓
Tool
↓
200 OK
↓
"Done!"
Agent-Facing APIs May Need Richer Contracts
Traditional APIs mainly answer:
What operation can I call?
What arguments are required?
What response will I receive?
AI-agent-facing capabilities may need to expose more:
What risk level does this action carry?
Is the operation reversible?
Does it require approval?
Can it be retried safely?
What preconditions must hold?
What proves successful completion?
That turns the API from a simple interface into something closer to a capability contract.
The AI supplies flexible reasoning.
The surrounding system supplies deterministic guarantees.
Final Thought
We are investing enormous effort in making AI agents smarter.
Better models.
More context.
More tools.
Longer workflows.
Greater autonomy.
But once an agent can modify the real world, the hardest production question may not be:
Can the model determine what to do?
It may be:
How do we prove that what it just did was actually what the user intended?
The most dangerous failure may never generate an exception.
It may not trigger PagerDuty.
It may not appear in the error logs.
Every service may remain healthy.
All you may see is:
HTTP/1.1 200 OK
The API succeeded.
The AI agent completed its task.
And the business still lost.
That is why production Agentic AI needs more than successful tool calls.
It needs verified outcomes.
References and Further Reading
- OWASP — LLM06: Excessive Agency: guidance on risks caused by excessive functionality, permissions, and autonomy in LLM applications.
- OWASP — Agentic AI Security: emerging guidance for autonomous AI applications and tool-enabled agents.
- NIST — AI Agent Identity and Authorization: work examining how established identity and authorisation practices apply to software and AI agents.
- AWS Well-Architected Framework — Idempotent Mutating Operations: guidance for making retries safe in distributed systems.
- Stripe API Documentation — Idempotent Requests: a practical example of retry-safe financial API mutations.

Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.