Control plane · Published 2026-09-04 · Updated 2026-10-21 · AgentiSend
Budgets and the kill switch
Per-key spend ceilings, what happens when one is reached, and the one request that stops everything.
This page answers how to cap what an agent can send and how to stop every agent at once. It exists because an agent can send ten thousand emails while you are at lunch.
A budget is a ceiling, not an alert
A budget is attached to a key, not to an account, and it is enforced before the send, not reported after it. When a key reaches its ceiling the API refuses further sends from that key with agent_budget_exceeded. The fix says to wait for the period to reset — GET /limits/keys/{id} says when — and that raising the budget is a person's decision, made in the console. The account plan inclusion is a separate ceiling: when it is spent the refusal is plan_limit_reached. Nothing queues up behind the refusal and nothing is silently dropped.
Set a key budget with PATCH /limits/keys/{id} and read the current state with GET /limits/keys/{id}. An API key can lower its own budget with that call; raising one is refused with human_action_required and done by a person on the Agents screen in the console.
Two ceilings, deliberately
- Messages per period —
budget_per_periodonPATCH /limits/keys/{id}. - Messages per rolling minute —
rate_ceiling_per_minuteon the same call.
There is no spend or cost counter. Both ceilings count messages.
Warnings arrive before the wall
limit.warning fires on the way up — at 80% of a key budget and at 80% of the plan inclusion — and limit.exceeded fires the first time a key's budget or the plan inclusion refuses a send. Each fires once per key, or once for the account, per period; the next period can fire them again. Both carry api_key_id (null for the plan inclusion), used, budget and period_started_at, and limit.exceeded adds resets_at, when the budget refills. Subscribe to both on a webhook endpoint — see the event catalogue — and you get the first one while there is still something to do about it.
A revoked key is not a key that can spend
Settings → Usage lists the keys that can still send. A revoked key is not one of them. Sends it already made in the last 30 days stay in the account total, and they show as one line, Revoked keys, with how many keys and how many sends. That line has no budget.
A key that was never given its own budget is capped at the emails the plan includes each month. It cannot spend without a ceiling. GET /usage, GET /limits/keys/{id} and get_agent_budget all report that cap. Changing the budget of a revoked key is refused: the key is not there to change.
The kill switch
One request pauses every key on the account:
curl -X POST https://api.agentisend.com/limits/kill-all \
-H "Authorization: Bearer $AGENTISEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "invoice-bot loop"}'It is one request because the moment you need it is the moment you do not want to be reading documentation. While it is on, every send is refused with kill_switch_active; queued sends stay queued and are not lost.
Turning it off is a person's decision. Someone signed in to the console presses Resume all on the Agents screen, which calls POST /limits/resume-all with their session. An API key is refused, even the one that turned the switch on, so an agent cannot switch itself back on:
curl -X POST https://api.agentisend.com/limits/resume-all \
-H "Authorization: Bearer $AGENTISEND_API_KEY"
# {"error": {"code": "human_action_required",
# "message": "This is a person’s decision, so an API key cannot make it.", ...}}Both the pause and the resume are written to the audit log with the reason given.
A single key is paused with POST /limits/keys/{id}/kill and resumed by a person with POST /limits/keys/{id}/resume. The two switches are separate: Resume all lifts only the fleet-wide pause, so a key someone stopped on its own stays stopped until that key is resumed.
A paused key cannot work its way back to sending. It cannot create a key, rotate one, or change a key or a budget; each answers kill_switch_active. It can still pause itself, or every key. A key made by another key starts with a budget and per-minute ceiling no higher than the key that made it, so making a new key does not reset a budget you lowered.
Loop detection
A key that sends the same body to the same recipient repeatedly is caught before the budget is, and the send is held rather than delivered. The held send appears in the approvals queue with the duplicate it matched, so you can see why it stopped.
Rate limits
Every response carries ratelimit-limit, ratelimit-remaining and ratelimit-reset. A 429 carries retry-after and a retry_after_seconds in the body. Wait the stated time; a backoff you guessed is how a backoff becomes a hot loop.