On this page
- The agent ordered 400 units. The ERP booked 400 cases.
- What is a governed API client?
- Why do free-form tool calls fail against enterprise APIs?
- What an API client should declare
- Where do silent errors come from in API mappings?
- Who holds the API credentials?
- Is a 200 or 202 response a confirmed result?
- Treat API responses as data, never instructions
- When the contract changes, compare versions
- Common anti-patterns
- Ten rules for governed API integration
- The result: agents that change systems the way you intended
- Frequently asked questions
- How Frozion connects agents to your APIs
- Sources
AI agents should call enterprise APIs through governed API clients, not free-form tool calls. Each client declares an explicit contract and field mapping, rejects missing values instead of applying silent defaults, keeps credentials in the runtime where the agent never sees them, and carries every write through to a result the system of record confirms.
The agent ordered 400 units. The ERP booked 400 cases.
A procurement agent handles a request to restock safety gloves. It finds the approved supplier, checks the budget and calls a "create purchase order" tool. The tool is a thin wrapper around the ERP's API: the agent fills in a JSON object, and the wrapper forwards it.
The agent sends a quantity of 400. It doesn't send a unit of measure, because the tool description never mentioned one. The ERP fills the gap with the item's default unit: cases of 12. The order is for 4,800 gloves.
The ERP replies 202 Accepted. The agent reports "Purchase order created" and closes the task. In fact the order is queued for credit review, because the total now exceeds the supplier's limit. It's never released. The gloves that were actually needed don't arrive, and nobody knows why for two weeks.
Nothing threw an error. The agent formed a valid request. The wrapper forwarded it faithfully. The ERP applied its documented default and its documented credit rule. The failure lived in the space between them: an implicit mapping, a silent default and an unconfirmed write.
What is a governed API client?
A governed API client is a versioned connection to one API operation with an explicit contract: typed inputs and outputs, a declared field mapping, defined error meanings, required authority and a rule for confirming success. The agent proposes values; the client validates, maps and executes them.
The difference from a free-form tool call is where the knowledge lives. In a free-form call, the model has to infer from a description which fields matter, what units apply and what a response means. In a governed client, those facts are written down once, reviewed, versioned and enforced on every call.
Why do free-form tool calls fail against enterprise APIs?
Because enterprise APIs are full of implicit meaning (units, defaults, partial updates, async processing) that a model can't reliably infer from a tool description, and a forwarding wrapper doesn't check. The request succeeds technically and fails in business terms.
Enterprise APIs are built for integrations written by developers who read the documentation and test edge cases. Agents read a short description and fill in what seems reasonable. Common gaps:
- Optional fields with consequential defaults: unit, currency, timezone, tax code, warehouse.
- Partial-update semantics: a null or empty value can clear a field instead of leaving it alone.
- Asynchronous processing:
202 Acceptedmeans the request was queued, not completed. - Overloaded fields: a "status" or "type" field that changes downstream behavior.
- Writable properties the caller shouldn't touch: OWASP's API Security Top 10 lists broken property-level authorization, including mass assignment, where a client sets fields it was never meant to.
A wrapper that forwards whatever JSON the model produces exposes the agent to every one of these. OWASP's agentic list names tool misuse among the top risks for exactly this reason: the tool works as built, and the agent uses it in ways nobody intended.
What an API client should declare
An OpenAPI document describes an API's shape, and JSON Schema validates payloads. Both are essential inputs. Neither says how your business meaning maps to the API, or what to do when the response is ambiguous. A governed client adds that:
| Declaration | What it covers | Why it matters |
|---|---|---|
| Operation | Which endpoint and method, for which business action | One client, one purpose; no general-purpose passthrough |
| Input contract | Typed fields, units, required values, allowed ranges | Rejects incomplete or out-of-range proposals before the call |
| Field mapping | How each business field becomes an API field, and which API fields are never set | Removes guesswork; blocks mass assignment |
| Defaults | Which defaults are allowed, written explicitly | No value is ever supplied by the target's hidden default |
| Authority | Which roles, conditions and purposes may invoke it | The agent acts within the person's authority, not the integration's |
| Effect class | Read, create, update, irreversible | Sets retry, approval and confirmation behavior |
| Response meaning | What each status and body means in business terms | "Accepted" and "completed" are kept distinct |
| Errors | Typed error outcomes, ideally RFC 9457 problem details | The workflow can branch on cause, not on a string |
| Confirmation | How success is proven: read-back, status query, callback | A write isn't done until the system of record says so |
Where do silent errors come from in API mappings?
From the values nobody sent: target-side defaults, nulls that clear fields, unmapped enums and unit or timezone assumptions, all of which the API accepts without complaint. Silent errors are dangerous precisely because every layer reports success.
| Mapping gap | What happens | Governed alternative |
|---|---|---|
| Missing unit of measure | Target applies the item default (cases, not units) | Unit is required in the contract, or set by an explicit, reviewed default |
| Missing currency | Target uses the account or tenant currency | Currency always mapped from the business record |
| Naive date or time | Interpreted in the server's timezone; deadlines shift a day | Dates mapped with explicit timezone and meaning |
| Null versus absent | A null in an update clears the existing value | Mapping distinguishes "leave unchanged" from "clear" |
| Unmapped enum value | Falls back to "other" or a generic type | Unknown values are rejected, not coerced |
| Truncated text | Long values cut silently at the field limit | Length checked before the call; reject or route for review |
| Amount in wrong minor units | 12.50 sent where the API expects 1250 | Amounts typed with currency and minor-unit rules |

Who holds the API credentials?
The runtime does, never the agent: credentials are attached at call time, scoped to the operation, and the call runs within the authority of the person the agent acts for. A key the agent can see is a key it can leak, misuse or carry into the wrong task.
Putting an API key in a prompt, a tool config the model reads, or an environment the agent can query creates three problems. The key can leak through output, logs or prompt injection. The agent can use it for calls nobody approved. And the key usually carries the integration's broad service authority, not the narrower authority of the person who asked for the work.
A governed client fixes all three. Credentials are stored once, outside any agent's reach. The runtime attaches them when a validated call executes. Before that, it checks that the person the agent acts for may perform this operation on this record for this purpose. OWASP's API list puts broken authentication and broken function-level authorization near the top; the agentic list adds identity and privilege abuse. The answer to all of them is the same: authority is decided by the runtime, per call, not carried around by the agent. More on delegated authority in AI agent identity.
Is a 200 or 202 response a confirmed result?
Not necessarily. A 202 means the request was accepted for processing, not completed, and even a 200 may describe a record that's pending review, partially applied or later rejected. Carry each write through to a result the system of record confirms.
RFC 9110 is explicit that 202 Accepted means processing hasn't finished and may still fail. Many enterprise APIs also return success for records that land in a draft, held or pending state. In the opening scenario, "accepted" turned into "held for credit review" and stayed there.
For each write, the client declares what confirmation looks like:
- Read back the created or updated record and compare it to what was authorized.
- Poll status for asynchronous operations until a terminal state, with a deadline.
- Match a callback or event to the original operation.
- Treat a timeout as unresolved, not failed: query the target before any retry.
Only then does the workflow mark the action complete. If the confirmed record differs from what was authorized (a different unit, amount or status), that's a typed outcome with its own route: correct, escalate or reverse as a new governed action. Timeouts and retries are covered in depth in retries and idempotency.

Treat API responses as data, never instructions
Responses flow back into the agent's context, and that's a second attack surface. OWASP's API list includes unsafe consumption of APIs: trusting third-party responses without validation. For agents the risk is sharper, because a free-text field in a response can carry instructions the model may follow.
Validate responses against the declared output contract. Pass the agent typed fields it needs, not whole raw payloads. Map errors to typed outcomes (RFC 9457 problem details make that easier when the API supports them) so the workflow branches on cause instead of the model interpreting an error string.
When the contract changes, compare versions
APIs change, and so do mappings. A field is renamed. A new required field appears. An enum gains a value. A default changes on the target side. A mapping is edited to fix one workflow and breaks another.
| Change | Risk | What to do |
|---|---|---|
| New optional field with a default | Behavior changes silently | Decide explicitly: map it, or set a reviewed default |
| New required field | Calls start failing | Update the contract and mapping before rollout |
| Enum value added | Unmapped values coerced or rejected | Map or reject the new value deliberately |
| Field meaning changed | Same name, different business effect | Treat as a new contract version |
| Mapping edited | Other workflows using the client change too | Check every workflow that depends on it first |
Treat a client like any other published dependency. Compare the old and new contract and mapping side by side, see which workflows use it, test against recorded cases, and require approval before the new version goes live. Paused work stays bound to the version it started with until it's safe to move. For the general pattern, see typed contracts for AI workflows.
Common anti-patterns
| Anti-pattern | Why it fails | What to do instead |
|---|---|---|
| Raw API as a free-form tool | The model guesses units, defaults and semantics | One governed client per business operation |
| Forward whatever JSON the agent produces | Mass assignment and unvalidated fields reach the target | Explicit mapping; fields outside it are never set |
| Let the target fill in defaults | Silent errors that every layer reports as success | Require values or use explicit, reviewed defaults |
| API key in the prompt or tool config | Leakage, misuse and over-broad authority | Runtime holds credentials and attaches them per call |
| "202 means done" | Queued, held or failed work is reported complete | Confirm with read-back, status or callback |
| Retry on timeout | A committed write happens twice | Treat it as unresolved; reconcile first |
| Pass raw responses to the model | Injected instructions and unvalidated data | Validate and pass typed fields only |
| Edit a shared mapping in place | Other workflows change without review | Version, compare, check dependents, approve |
Ten rules for governed API integration
- Give each business operation its own governed client.
- Declare the input and output contract, including units and ranges.
- Map every field explicitly; never set fields outside the mapping.
- Allow no silent defaults: required, mapped or reviewed.
- Keep credentials in the runtime, never in the agent's view.
- Check the acting person's authority on every call.
- Treat accepted as pending and a timeout as unresolved.
- Confirm each write against the system of record.
- Validate responses and pass the agent typed fields only.
- Version contracts and mappings, and compare before publishing.
The result: agents that change systems the way you intended
Agents become useful when they can act on real systems, and dangerous when those actions rest on guesses. Governed API clients move the guessing out of the model and into reviewed, versioned contracts: what fields mean, which defaults apply, who may call what and what counts as done.
The agent still proposes. The runtime validates, maps, authorizes, executes and confirms. When something goes wrong, you can see which contract version ran, which values were mapped from where and what the system of record actually recorded. That's the difference between an integration that works in a demo and one you can let run.
Frequently asked questions
What is a governed API client for AI agents?
It's a reusable, versioned connection to one API operation with a declared contract: typed inputs and outputs, an explicit field mapping, error and timeout meanings, the authority required and how success is confirmed. The agent proposes values; the client validates, maps and executes them.
Should AI agents have direct access to API keys?
Keep keys out of the agent entirely. The runtime holds credentials and attaches them at call time, under the identity and authority of the person the agent acts for. A key in a prompt, tool config or context window can leak, be misused or outlive its purpose.
Why are API field mappings a source of silent errors?
Mappings fail quietly because the API still accepts the request. A missing unit, currency or timezone takes the target's default; a null clears a field; an unmapped enum falls back to a generic value. Nothing errors, and the wrong record is created.
How does this work for agents we already run?
Route the agent's API calls through a governed runtime over MCP or HTTPS. The agent calls a governed client instead of the raw API: inputs are validated and mapped by contract, credentials stay in the runtime, and each write is tracked until your system of record confirms it.
How Frozion connects agents to your APIs
With Frozion's API Client Builder, every API an agent touches gets a client with an explicit contract and mappings, and Frozion carries a write to an effect your system of record confirms. System credentials are stored once in Global Variables and are never shown to an agent or person again. Under Agent Delegation, each call runs within the authority of the person the agent acts for. Durable Execution treats an API timeout as an unresolved outcome, and change control shows every workflow that uses a client, with version compare for workflows and approval to publish.
Sources
- OpenAPI SpecificationMachine-readable API contracts: operations, parameters, schemas, responses.
- JSON SchemaValidation of request and response payloads, including required fields and defaults.
- RFC 9110, HTTP SemanticsStatus codes such as 202 Accepted, which means processing isn't complete.
- RFC 9457, Problem Details for HTTP APIsTyped, machine-readable error responses.
- OWASP API Security Top 10 (2023)Property-level authorization, broken authentication, unsafe consumption of APIs.
- OWASP Top 10 for Agentic Applications (2026)Tool misuse and identity and privilege abuse by agents.
More in Work that finishes
Retries & side effects 2
Durable & event-driven 1
Contracts & routing 3
APIs & integration 1
Other topics



