Most APIs are "agent-compatible": an agent can call them. Far fewer are agent-native: an agent can accomplish the whole job on its own, with no human un-sticking it halfway. We spent a few weeks turning Send16 (an email platform) from the first into the second, and the gap turned out to be smaller and weirder than expected. Here's the whole thing.
The wall: onboarding, not the API
Our send endpoint was fine. An agent could form a request. But it couldn't succeed, because like almost every email API we required domain verification — SPF, DKIM, DMARC — before we'd send a single message. That's a reasonable anti-abuse default for humans. For an unattended agent it's fatal: step one is "edit your DNS," which the agent can't do. So the first send always failed, and a failed first action is where agent workflows die.
The lesson: for an agent, onboarding is the API. The happy path has to include a first success that needs no out-of-band human step.
Fix 1 — a zero-DNS sandbox sender
We added a sandbox sender. If you send from onboarding@send16.com, Send16 delivers it — with no domain, no DNS, no verification — but only to your own account owner's email. Verify a domain later to send to anyone else.
curl -X POST https://api.send16.com/api/transactional/api/send \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"from":"onboarding@send16.com","to":"you@example.com","subject":"It works","html":"<p>Hello from an agent</p>"}'
That "only to yourself" constraint is the whole trick: it's a real, deliverable send (the agent sees the full lifecycle — queued, sent, delivered) but it can't be abused to spam strangers, because the only reachable address is one you already control.
Fix 2 — an identity endpoint the agent calls first
An agent dropped into a workspace doesn't know who it is or what it's allowed to do. So we added:
GET /api/me
which returns the workspace, the plan/quota, the account owner, and the sandbox_recipient — the exact address the sandbox can reach. One call and the agent is oriented. Our docs literally say "call this first."
Fix 3 — an llms.txt for the runtimes that can't npm install
Not every agent runtime can install an SDK. So https://send16.com/llms.txt documents the raw HTTP contract: the send endpoint, how to read delivery status by log_id, the sandbox trick, and the /api/me bootstrap. It's the same information a human skims from the docs, arranged for a model.
A subtle but important detail we got wrong first: delivery status. The obvious-looking /api/messages/:id was plan-gated (it's the inbox log). Agents kept hitting 403. The right endpoint is GET /api/emails/:id with the log_id from the send response — ungated, returns sent -> delivered -> opened. If your llms.txt points an agent at a gated endpoint, it'll loop on a permission error forever. Point it at the ungated one.
Fix 4 — an MCP server (and why tools/list must work keyless)
For MCP clients (Claude Desktop, Cursor, Claude Code) we ship send16-mcp — 79 tools over stdio, plus a hosted Streamable-HTTP endpoint for remote clients.
Two things worth stealing if you build one:
Multi-tenant key threading. In hosted HTTP mode each request carries its own
Authorization: Bearer sk_live_.... We thread it through the whole request withAsyncLocalStorage, so one process safely serves many users and every tool call runs against the connecting user's workspace.tools/listmust succeed without a key. Registries and clients introspect your server before anyone authenticates — they start it and ask for the tool list. If your server hard-exits on a missing API key at startup, it fails every registry's health check. Validate the key lazily, attools/calltime, not at boot.
Proving it: the cold-agent test
The honest way to know if you succeeded is to stop reasoning about it and run a cold agent: fresh context, no prior knowledge of your product, one instruction — "send an email with Send16." Then watch.
Ours found the docs, called /api/me, sent from the sandbox, and confirmed delivery — roughly four calls, no human intervention. The first time it worked end-to-end without us feeding it anything was the moment "agent-native" stopped being a slogan.
If you own an API and want to know whether an agent can really use it: give a cold agent your public docs and one goal, and don't help. Where it gets stuck is your actual onboarding backlog.
Takeaways (portable to any API)
- Onboarding is the API. Guarantee a first success with no out-of-band human step.
-
Give the agent a
whoami. One call that returns identity + capabilities. - Publish an llms.txt pointing at ungated endpoints; verify each one an agent will hit.
-
Make introspection keyless.
tools/list(or your schema/discovery route) must not require auth. - Test cold. A blind agent + one goal is the only benchmark that doesn't lie.
Send16 is an email platform for developers and marketers. The MCP server is open source: github.com/spruikco/send16-mcp · npx send16-mcp · send16.com/mcp.
Top comments (0)