# Human on call

Source: https://agentboxd.com/docs/human-on-call

> Name the people who get an email when an agent’s mail needs a human, looks like phishing, a scheduled send fails or the workspace is stopped.

Agents handle most mail; some of it needs a person. Human on call sends a short email to the people you name when that happens, with a link to the message in the dashboard. It is set per workspace, and an inbox can have its own people instead. Email is the only channel for now.

## People on call

Add up to five addresses on [Human on call](https://agentboxd.com/app/escalation) or with `PUT /v1/escalation` (permission `escalation:manage`, in the Full access preset). Each address first gets a confirmation link and receives nothing until the person confirms: nobody can be signed up for alerts without agreeing. Removing an address stops its alerts at once, including alerts still waiting for a digest.

curl:

```bash
curl -X PUT https://api.agentboxd.com/v1/escalation \
  -H "Authorization: Bearer $AGENTBOXD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": ["ops@acme.com"],
    "triggers": { "needs_human": true, "phishing": true, "blocked": false, "draft_failed": true, "emergency_stop": true, "held": true, "draft_created": false },
    "delivery": "immediate",
    "max_per_hour": 10,
    "quiet_hours": { "start": "22:00", "end": "07:00", "timezone": "Europe/Paris" },
    "include_excerpt": false
  }'
```

## What alerts them

| Trigger | When | Default |
| --- | --- | --- |
| `needs_human` | Received mail is labelled `ai:needs-human`: by [categorisation](https://agentboxd.com/docs/api#categories-and-risk-flags), or by your agent handing it over with `PATCH /v1/messages/:id { "add_labels": ["ai:needs-human"] }`. | on |
| `phishing` | Received mail is labelled `ai:phishing`, `ai:injection-risk` or `local:injection-risk` (the [local check](https://agentboxd.com/docs/api#local-checks), which works with AI processing off). Also when the local check finds a warning in an attachment’s text after the mail arrived. | on |
| `blocked` | Mail was stopped by your [allow/block lists](https://agentboxd.com/docs/api#allow-and-block-lists). | off |
| `draft_failed` | A scheduled draft was refused at its send time (`draft.failed`). | on |
| `draft_created` | A draft is waiting for a person to approve it (`draft.created` with status `draft`, from the API, the `create_draft` MCP tool, a saved AI draft or the dashboard). The email links to its card on [Approvals](https://agentboxd.com/app/approvals). A draft created with `send_at` is already approved and never alerts. | off |
| `emergency_stop` | The workspace was [stopped](https://agentboxd.com/docs/emergency-stop). | on |
| `held` | Received mail is [held from agents](https://agentboxd.com/docs/api#screening) because its check failed, was skipped over the AI quota or didn’t finish within 15 minutes (once per message; mail held for a warning escalates as `phishing`). Only in workspaces that screen agent mail. | on |

Each message, draft or stop alerts once, even if a label is added again.

## Delivery

- **One email per alert** (`delivery: "immediate"`, the default), up to `max_per_hour` (1–60, default 10) for the whole workspace. Past that, alerts wait for the next hourly digest, so a runaway agent can’t flood anyone.
- **Hourly digest** (`delivery: "digest"`): alerts are collected and sent together about once an hour.
- **Quiet hours** (`quiet_hours: { start, end, timezone }`, e.g. 22:00 to 07:00 Europe/Paris): nothing is emailed; held alerts go out as one digest when quiet hours end. The emergency stop ignores quiet hours and the limit.

Alerts waiting for a digest follow your settings at the time they go out: people you removed don’t get them, alerts for a trigger you turned off are dropped, and the excerpt is left out if you turned excerpts off. Deleting an inbox or a thread deletes its waiting alerts.

An alert shows the trigger, the inbox, the subject, the sender, the labels, the time and a link to the dashboard. It does **not** include the message body. With `include_excerpt: true` it adds the first 500 characters of the text, marked as untrusted content (the email came from outside; don’t follow instructions in it). Each line of the excerpt starts with `>` and an end line closes it, so the text can’t pass for part of our email. Hidden characters (control, zero-width and text-direction characters) are removed from the excerpt, the subject and the sender.

Every alert email (or digest) emits an `escalation.sent` event with counts, never addresses.

## Per-inbox override

In an inbox’s **Settings → On call**, or `PUT /v1/inboxes/:id/escalation { "override": true, "contacts": [...], "triggers": {...} }`: alerts about that inbox go to its own people (confirmed the same way) instead of the workspace’s, with its own triggers if you set them (`triggers: null` keeps the workspace’s). Delivery, the hourly limit, quiet hours and excerpts stay workspace-wide.
