---
title: "Update an agent"
method: PATCH
path: "/v1/agents/{id}"
tags: ["Agents"]
---

# Update an agent

`PATCH /v1/agents/{id}`

## Request

- Base URL: `https://api.mails.ai`
- URL: `https://api.mails.ai/v1/agents/{id}`
- Auth: HTTP bearer

**Requires scope:** `manage`. Changes an agent's status, recipient lists, send limits, or whether its new mail is read for intent. A pause by our abuse-prevention system or for the agent's own bounce or complaint rate cannot be lifted here (403 `agent_suspended`), and pausing such an agent again keeps that reason. Archiving cannot be undone, so an archived agent's status cannot change (409 `agent_archived`), and a status change that meets an agent archived or paused meanwhile answers 409 too. A key tied to the agent, or an app connected by sign-in, cannot change `allowlist_domains`, `blocklist_domains`, `daily_send_limit` or `hourly_send_limit` (403): they hold the agent to what the workspace allows, so only a key that is not tied to an agent changes them. A test key cannot change an agent that has a live key tied to it, live mail (sent, scheduled or received) or a draft a live key made (403 `live_mode_required`).

## Path parameters

- `id` string, required

## Request body

- UpdateAgentRequest
  - `status` 'active' | 'paused': `paused` makes the agent's send requests fail with 422 `agent_paused`; `active` resumes it. A pause set by the bounce, complaint or abuse checks cannot be lifted this way (403 `agent_suspended`).
  - `allowlist_domains` string[]: When set, this agent sends only to these domains and their subdomains (`acme.com` covers `mail.acme.com`). A recipient in `to`, `cc` or `bcc` outside the list refuses the whole send with 422 `recipient_not_allowed`, in test mode too. A leading `@` is ignored. The test address reply@test.mails.ai is always allowed.
  - `blocklist_domains` string[]: This agent never sends to these domains or their subdomains. A recipient in `to`, `cc` or `bcc` on the list refuses the whole send with 422 `recipient_not_allowed`, in test mode too. The test address reply@test.mails.ai is never blocked.
  - `daily_send_limit` integer, nullable: This agent's own cap on recipients in any 24 hours, on top of your plan's cap: each live send counts once per `to`, `cc` and `bcc` address. Past it a send is refused with 429 `daily_limit_exceeded`, whose `resets_at` says when the send fits again (with a `Retry-After` header only when that is a minute or less away). Test-mode sends are neither counted nor refused. `null` removes it, leaving only your plan's cap.
  - `hourly_send_limit` integer, nullable: This agent's own cap on recipients in any hour, on top of your plan's cap: each live send counts once per `to`, `cc` and `bcc` address. Past it a send is refused with 429 `hourly_limit_exceeded`, whose `resets_at` says when the send fits again (with a `Retry-After` header only when that is a minute or less away). Test-mode sends are neither counted nor refused. `null` removes it, leaving only your plan's cap.
  - `classify_inbound` boolean: Turns intent classification of new mail on or off (never replies in a thread). Turning it on needs a paid plan (402 `feature_not_enabled`); left out, it stays as it is.
  - `address` string, email: The agent's own address, which never changes: any other address answers 400. Accepted so a body that names it alongside `forwarding` works.
  - `forwarding` boolean: Forwarding mode, for an address on your own domain: the mail service hosting it forwards its mail to the agent's `forwarding_address`, so no MX record changes. `POST /v1/agents/{id}/forwarding/verify` then sends a test through the forward. Turning it on or off starts `forwarding_status` again from `not_verified`.

## Response `200`

The updated agent.

- Agent
  - `id` string, required: Agent id (`agt_…`).
  - `name` string, required: The agent's name, the part of `email` before the `@`. The agent routes, and `agent` on sends and drafts, take it in place of the id; agents on different domains can share a name, so the id is the safer reference.
  - `email` string, email, required: The agent's address, `<name>@<domain>`, unique across mails.ai: the identity it sends as. It receives mail at `receiving_address`.
  - `domain` string, required: The domain part of `email`: your workspace's `<slug>.mails.ai`, or a custom domain that was verified when the agent was created.
  - `receiving_address` string, email, required: Where this agent receives mail. Every send's Reply-To is this address unless the send sets `reply_to`, so replies reach the agent. `<name>.<slug>@in.mails.ai` for an agent on your mails.ai address (`<name>@in.mails.ai` when the name is the slug); for an agent on your own domain, the name and the whole domain with its dots written as underscores, such as `billing.example_com@in.mails.ai`. Mail to any plus address of it reaches the agent too: add `+` and anything before the `@` (`qa.acme+github@in.mails.ai`, `qa.acme+run-1842@in.mails.ai`), so one agent can give every service or test run its own address. The address used is kept as the message's `delivered_to`, and the `to` filter on received mail matches it.
  - `workspace_id` string, required: Id of the workspace the agent belongs to (`wsk_…`).
  - `status` 'active' | 'paused' | 'archived', required: `active`; `paused`, when its send requests get 422 `agent_paused` and `pause_reason` says why; or `archived` after a DELETE, when it cannot send and the default list leaves it out.
  - `pause_reason` string: Why the agent is paused or archived: `manual` (paused with PATCH), `archived_via_api` (archived with DELETE), or a reason the automatic bounce, complaint and abuse checks set, such as `bounce_rate=0.0612`. Absent when there is none. The list leaves it out.
  - `daily_send_limit` integer: This agent's own cap on recipients in any 24 hours, on top of your plan's cap: each live send counts once per `to`, `cc` and `bcc` address. Past it, a send gets 429 `daily_limit_exceeded`. Absent when unset. The list leaves it out.
  - `hourly_send_limit` integer: This agent's own cap on recipients in any hour, on top of your plan's cap: each live send counts once per `to`, `cc` and `bcc` address. Past it, a send gets 429 `hourly_limit_exceeded`. Absent when unset. The list leaves it out.
  - `allowlist_domains` string[]: When present, this agent sends only to these domains and their subdomains; any other recipient in `to`, `cc` or `bcc` gets 422 `recipient_not_allowed`. The test address reply@test.mails.ai is always allowed. The list leaves it out.
  - `blocklist_domains` string[]: Domains (and their subdomains) this agent never sends to; a recipient on the list gets 422 `recipient_not_allowed`. The test address reply@test.mails.ai is never blocked. The list leaves it out.
  - `classify_inbound` boolean: Whether this agent's new mail is read for intent; a reply in a thread never is. The list leaves it out.
  - `unread_count` integer: Unread threads in the agent's inbox folder, on the list and on the single-agent GET and PATCH.
  - `forwarding` boolean: Forwarding mode: the agent's address is on your own domain, and the mail service that already hosts it forwards its mail to `forwarding_address`, so no MX record changes.
  - `forwarding_address` string, email, nullable: Where to forward the agent's mail: its `receiving_address`. Mail that arrives here is stored, threaded and sent to your webhooks like any received mail, with the agent's own address as the recipient. Null when forwarding is off.
  - `forwarding_status` 'not_verified' | 'verified' | 'failing' | 'null', nullable: `verified` once a test from `POST /v1/agents/{id}/forwarding/verify` arrived through the forward; `failing` when the last test had not arrived 15 minutes after it was sent; `not_verified` before that. Null when forwarding is off.
  - `forwarding_test_sent_at` string, date-time, nullable: When the last forwarding test was sent. Null when none was, or forwarding is off.
  - `forwarding_verified_at` string, date-time, nullable: When a forwarding test last arrived through the forward. Null when none has, or forwarding is off.
  - `created_at` string, date-time: When the agent was created.
  - `updated_at` string, date-time: When the agent last changed: an update, an archive, or an automatic pause or resume. The list leaves it out.

## Other responses

- `400`: Invalid request — malformed JSON or a field failed validation. Also `feature_not_enabled` when this server has a feature switched off (custom domains before they are available).
- `401`: Missing or invalid API key.
- `402`: Payment required: a plan limit (`plan_limit_exceeded`) or a feature the current plan does not include (`feature_not_enabled`). The error object carries `upgrade_url`, the dashboard page where the plan can be changed.
- `403`: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
- `404`: Resource not found in this workspace, or the agent a send names is archived (`agent_archived`).
- `409`: Conflict — duplicate resource, an in-progress idempotent request, a draft or scheduled message that started sending while it was being changed, or a thread deleted for good while one of its messages is being sent (`duplicate_resource`); or an agent name more than one agent has (`agent_name_conflict`: use the agent's id); or a status change on an archived agent, since archiving cannot be undone (`agent_archived`).
- `500`: Internal server error.

---

[API](https://skmtc.dev/mails/apis/mails-ai-api.md) · [All operations](https://skmtc.dev/mails/apis/mails-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mails/apis/mails-ai-api/revisions/4d4930a8c33b?raw)
