Agents
Agent quickstart
Six numbered steps from no account to a delivered email, with the exact request and the exact response shape for each.
Read this if you are a model or a script. Every step is one request. Every request is printed with the response you should expect, and every response shape below comes from openapi.json rather than from prose — the same document at /openapi.json.
Before step 1: $AGENTISEND_API_KEY holds a key that starts with as_. A human creates the first one in the console; step 3 creates the rest. If you do not have one, stop and ask for one. There is no anonymous send.
The base URL is https://api.agentisend.com. Every response carries ratelimit-limit, ratelimit-remaining and ratelimit-reset. Read them; do not discover the ceiling by hitting it.
1. Add the domain you will send from
curl -sS -X POST https://api.agentisend.com/domains \
-H "Authorization: Bearer $AGENTISEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "yourdomain.com"}'Region is optional and defaults to us (Oregon). Pass "region": "eu" for Helsinki.
2. Read the DNS records back, publish them, then verify
GET /domains/{id} returns the records to publish. A human (or your DNS API) publishes them; you then ask for a re-check:
curl -sS -X POST https://api.agentisend.com/domains/9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42/verify \
-H "Authorization: Bearer $AGENTISEND_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"201
{
"click_tracking": true,
"created_at": "2026-09-04T09:14:00Z",
"dkim_selector": "string",
"id": "9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42",
"name": "yourdomain.com",
"open_tracking": true,
"records": [],
"region": "us"
}Until this returns a verified status, a send from that domain answers domain_not_verified, and that error names this endpoint as the fix. Do not retry the send in a loop — retry the verification, and only after the records are actually published.
3. Create your own key, with its own budget
Do not send with the key a human uses. A shared key is a shared blast radius and one ambiguous line in the audit log.
curl -sS -X POST https://api.agentisend.com/api-keys \
-H "Authorization: Bearer $AGENTISEND_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"yourdomain.com","permission":"sending_access"}'201
{
"budget_per_period": "string",
"created_at": "2026-09-04T09:14:00Z",
"domain_scope": "string",
"expires_at": "2026-09-04T09:14:00Z",
"id": "9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42",
"last_used_at": "2026-09-04T09:14:00Z",
"name": "yourdomain.com",
"period": "hourly"
}The token is returned exactly once. Store it before you make another request; there is no endpoint that will show it to you again. The key is created with a budget already on it — 167 operations exist and none of them creates an unlimited sender.
4. Send
curl -sS -X POST https://api.agentisend.com/emails \
-H "Authorization: Bearer $AGENTISEND_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"from":"[email protected]","subject":"Your receipt","to":"[email protected]"}'201
{
"id": "9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42",
"simulated": true,
"warnings": []
}Send Idempotency-Key on every send. If your process dies between the request and the response, repeating the call with the same key replays the original result instead of sending twice. Keys are remembered for 7 days.
For more than one message, use POST /emails/batch: each item succeeds or fails on its own, so one malformed address does not lose the other 499.
5. Read what happened
curl -sS -X GET https://api.agentisend.com/emails/9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42 \
-H "Authorization: Bearer $AGENTISEND_API_KEY"200
{
"api_key_id": "9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42",
"attachments": [],
"bcc": [],
"cc": [],
"created_at": "2026-09-04T09:14:00Z",
"domain": "string",
"from": "[email protected]",
"headers": "string"
}The status is one of 48 event types' worth of history, and GET /emails/{id}/mime returns the exact bytes that left, which is the thing to attach when a recipient says an email never arrived.
For a running process, subscribe a webhook rather than polling: POST /webhooks with the events you care about. Failed deliveries are retried 10 times at 1, 5, 15, 60, 180, 360, 720, 1440, 2880, 4320 minutes and then dead-lettered where you can replay them.
6. Check your standing before a large send
curl -sS -X GET https://api.agentisend.com/trust/standing \
-H "Authorization: Bearer $AGENTISEND_API_KEY"200
{
"history": [],
"next_review_at": "2026-09-04T09:14:00Z",
"reason_codes": [],
"reasons": [],
"sla_deadline_at": "2026-09-04T09:14:00Z",
"state": "ok"
}If this is not ok, a bulk send is the wrong move: the ladder acts on bounce rate at 2% (warn) and 4% (pause), and on complaint rate at 0.05% (warn) and 0.08% (pause). Fix the list first.
The errors you will actually meet
Every 4xx carries code, message, fix and docs_url. Act on fix; it names the endpoint to call next. The five that matter to an autonomous sender:
| Code | What happened | What to do |
|---|---|---|
missing_api_key | No bearer token on the request. | Send Authorization: Bearer as_…. Do not retry without one. |
domain_not_verified | The from-domain has not passed DNS checks. | Publish the records, call POST /domains/{id}/verify, then send. |
agent_budget_exceeded | This key has spent its send budget for the period. | Stop. Ask a human to raise the budget with PATCH /limits/keys/{id}, or wait for the period to reset. Retrying does not help. |
plan_limit_reached | The account has used every email included in its plan this period. | Upgrade in Settings → Billing, or wait until the reset date in the error. |
rate_limit_exceeded | Too many requests in the window. | Wait retry_after_seconds, then continue. This one is safe to retry. |
approval_required | The send matched an approval rule and is held. | Poll the action until a human approves or rejects it. Do not resubmit — a second submission is a second held send. |
kill_switch_active | A human paused this key, or every key on the account. | Do not work around it; report it. Resume is POST /limits/resume-all or POST /limits/keys/{id}/resume. |
The full catalogue, all 71 of them, is at /docs/errors and as Markdown at /docs/errors.md.
The two limits you cannot raise from inside a session
The budget. When it is spent, sends stop and agent_budget_exceeded (the key) or plan_limit_reached (the account inclusion) says so. Nothing is auto-charged, nothing is quietly allowed through, and no request you can make lifts your own ceiling. That is the point of it.
The kill switch. A human can stop every key on the account with POST /limits/kill-all. If your sends start answering kill_switch_active, a person did that deliberately. Do not work around it; report it.
What this service will not do
No cold outreach. There is no lead database, no scraping, and no bulk import of addresses that never asked to hear from you. A request that looks like unsolicited sending is refused, and asking differently will not change the answer.
Where everything else is
- /llms.txt — the index: figures, plans, every operation, error and event.
- /llms-full.txt — every page on this site as Markdown.
- /.well-known/agent.json — every URL above, in one document.
- /how-agents-see-this-site — the fetching contract, with a curl for each claim.
- /docs/guides/agents — the same API over MCP, if you are a client rather than a script.