# SDKs and CLI (/integrations/sdks-and-cli)

<!-- agent-signals: reading_time_min: 10 · est_tokens: 6134 · updated: 2026-09-06 -->
Related: [MCP and Skills](/integrations/mcp-and-skills.md), [Marketplaces and provisioning](/integrations/marketplaces.md)



# Call any AgentMail operation from the CLI, TypeScript, Python, or Go

Install the CLI, TypeScript, or Python client, authenticate once with `AGENTMAIL_API_KEY`, and look up any operation's exact call on each surface. All surfaces call the same API with the same key, so a shell script that provisions inboxes can run next to an application that answers mail.

## Do this

```bash
npm install -g agentmail-cli
export AGENTMAIL_API_KEY="<API_KEY>"
agentmail inboxes list
```

A JSON inbox list confirms the key works. In the SDKs, make the first call `auth.me` instead. It returns the key's identity, the organization, pod, or inbox it is scoped to, which is how code holding a key discovers what it can act on.

## SDK

```bash
npm install -g agentmail-cli                  # CLI (also: brew install agentmail-to/tap/agentmail)
npm install agentmail                         # TypeScript
pip install agentmail                         # Python
go get github.com/agentmail-to/agentmail-go   # Go
```

Construct clients once: TypeScript `import { AgentMailClient } from "agentmail"` then `const client = new AgentMailClient()`, Python `from agentmail import AgentMail` then `client = AgentMail()`. Both read `AGENTMAIL_API_KEY`. Prebuilt CLI binaries for macOS, Linux, and Windows are on the agentmail-cli GitHub releases page. The examples on the page cover CLI, TypeScript, and Python, and the Go SDK at `github.com/agentmail-to/agentmail-go` covers the same API.

| Operation                                    | CLI                                                                                        | TypeScript                                                                                                            | Python                                                                                                                                              |
| -------------------------------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Check the key works, read its scope          | `agentmail inboxes list`                                                                   | `client.auth.me()`                                                                                                    | `client.auth.me()`                                                                                                                                  |
| Create inbox                                 | `agentmail inboxes create`                                                                 | `client.inboxes.create({ displayName })`                                                                              | `client.inboxes.create(request=CreateInboxRequest(display_name=...))`                                                                               |
| List / get inboxes                           | `agentmail inboxes list`, `agentmail inboxes get`                                          | `client.inboxes.list()`, `client.inboxes.get(inboxId)`                                                                | `client.inboxes.list()`, `client.inboxes.get(inbox_id=...)`                                                                                         |
| Update inbox                                 | `agentmail inboxes update`                                                                 | `client.inboxes.update(inboxId, { displayName })`                                                                     | `client.inboxes.update(inbox_id=..., display_name=...)`                                                                                             |
| Delete inbox                                 | `agentmail inboxes delete`                                                                 | `client.inboxes.delete(inboxId)`                                                                                      | `client.inboxes.delete(inbox_id=...)`                                                                                                               |
| Send message                                 | `agentmail inboxes:messages send`                                                          | `client.inboxes.messages.send(inboxId, { to, subject, text })`                                                        | `client.inboxes.messages.send(inbox_id=..., to=[...], subject=..., text=...)`                                                                       |
| List / get messages                          | `agentmail inboxes:messages list`, `agentmail inboxes:messages get`                        | `client.inboxes.messages.list(inboxId)`, `client.inboxes.messages.get(inboxId, messageId)`                            | `client.inboxes.messages.list(inbox_id=...)`, `client.inboxes.messages.get(inbox_id=..., message_id=...)`                                           |
| Reply / reply all                            | `agentmail inboxes:messages reply`, `agentmail inboxes:messages reply-all`                 | `client.inboxes.messages.reply(inboxId, messageId, { text })`, `client.inboxes.messages.replyAll(...)`                | `client.inboxes.messages.reply(inbox_id=..., message_id=..., text=...)`, `client.inboxes.messages.reply_all(...)`                                   |
| Forward message                              | `agentmail inboxes:messages forward`                                                       | `client.inboxes.messages.forward(inboxId, messageId, { to, text })`                                                   | `client.inboxes.messages.forward(inbox_id=..., message_id=..., to=[...], text=...)`                                                                 |
| Update message labels                        | `agentmail inboxes:messages update`                                                        | `client.inboxes.messages.update(inboxId, messageId, { addLabels, removeLabels })`                                     | `client.inboxes.messages.update(inbox_id=..., message_id=..., add_labels=[...], remove_labels=[...])`                                               |
| Get attachment                               | `agentmail inboxes:messages get-attachment`                                                | `client.inboxes.messages.getAttachment(inboxId, messageId, attachmentId)`                                             | `client.inboxes.messages.get_attachment(inbox_id=..., message_id=..., attachment_id=...)`                                                           |
| Search messages                              | `agentmail inboxes:messages search`                                                        | `client.inboxes.messages.search(inboxId, { q })`                                                                      | `client.inboxes.messages.search(inbox_id=..., q=...)`                                                                                               |
| List / search threads in one inbox           | `agentmail inboxes:threads list`, `agentmail inboxes:threads search -q`                    | `client.inboxes.threads.list(inboxId)`, `client.inboxes.threads.search(inboxId, { q })`                               | `client.inboxes.threads.list(inbox_id=...)`, `client.inboxes.threads.search(inbox_id=..., q=...)`                                                   |
| Get thread                                   | `agentmail threads get`                                                                    | `client.threads.get(threadId)`                                                                                        | `client.threads.get(thread_id=...)`                                                                                                                 |
| List / search threads across the key's scope | `agentmail threads list`, `agentmail threads search -q`                                    | `client.threads.list()`, `client.threads.search({ q })`                                                               | `client.threads.list()`, `client.threads.search(q=...)`                                                                                             |
| Create draft                                 | `agentmail inboxes:drafts create`                                                          | `client.inboxes.drafts.create(inboxId, { to, subject, text, sendAt })`                                                | `client.inboxes.drafts.create(inbox_id=..., to=[...], subject=..., text=..., send_at=...)`                                                          |
| List drafts                                  | `agentmail inboxes:drafts list`                                                            | `client.inboxes.drafts.list(inboxId)`                                                                                 | `client.inboxes.drafts.list(inbox_id=...)`                                                                                                          |
| Send / delete draft                          | `agentmail inboxes:drafts send`, `agentmail inboxes:drafts delete`                         | `client.inboxes.drafts.send(inboxId, draftId, {})`, `client.inboxes.drafts.delete(inboxId, draftId)`                  | `client.inboxes.drafts.send(inbox_id=..., draft_id=...)`, `client.inboxes.drafts.delete(inbox_id=..., draft_id=...)`                                |
| Create webhook                               | `agentmail webhooks create`                                                                | `client.webhooks.create({ url, eventTypes, clientId })`                                                               | `client.webhooks.create(url=..., event_types=[...], client_id=...)`                                                                                 |
| List / get webhooks                          | `agentmail webhooks list`, `agentmail webhooks get`                                        | `client.webhooks.list()`, `client.webhooks.get(webhookId)`                                                            | `client.webhooks.list()`, `client.webhooks.get(webhook_id=...)`                                                                                     |
| Update / delete webhook                      | `agentmail webhooks update`, `agentmail webhooks delete`                                   | `client.webhooks.update(webhookId, { eventTypes })`, `client.webhooks.delete(webhookId)`                              | `client.webhooks.update(webhook_id=..., event_types=[...])`, `client.webhooks.delete(webhook_id=...)`                                               |
| Register domain                              | `agentmail domains create`                                                                 | `client.domains.create({ domain })`                                                                                   | `client.domains.create(domain=...)`                                                                                                                 |
| Verify / get domain                          | `agentmail domains verify`, `agentmail domains get`                                        | `client.domains.verify(domainId)`, `client.domains.get(domainId)`                                                     | `client.domains.verify(domain_id=...)`, `client.domains.get(domain_id=...)`                                                                         |
| Update domain settings                       | `agentmail domains update`                                                                 | `client.domains.update(domainId, { subdomainsEnabled })`                                                              | `client.domains.update(domain_id=..., subdomains_enabled=...)`                                                                                      |
| List / delete domains                        | `agentmail domains list`, `agentmail domains delete`                                       | `client.domains.list()`, `client.domains.delete(domainId)`                                                            | `client.domains.list()`, `client.domains.delete(domain_id=...)`                                                                                     |
| Add allow or block entry                     | `agentmail inboxes:lists create`                                                           | `client.inboxes.lists.create(inboxId, direction, type, { entry, reason })`                                            | `client.inboxes.lists.create(inbox_id=..., direction=..., type=..., entry=..., reason=...)`                                                         |
| List / delete entries                        | `agentmail inboxes:lists list`, `agentmail inboxes:lists delete`                           | `client.inboxes.lists.list(inboxId, direction, type)`, `client.inboxes.lists.delete(inboxId, direction, type, entry)` | `client.inboxes.lists.list(inbox_id=..., direction=..., type=...)`, `client.inboxes.lists.delete(inbox_id=..., direction=..., type=..., entry=...)` |
| Create pod                                   | `agentmail pods create`                                                                    | `client.pods.create({ name, clientId })`                                                                              | `client.pods.create(name=..., client_id=...)`                                                                                                       |
| List / get / delete pods                     | `agentmail pods list`, `agentmail pods get`, `agentmail pods delete`                       | `client.pods.list()`, `client.pods.get(podId)`, `client.pods.delete(podId)`                                           | `client.pods.list()`, `client.pods.get(pod_id=...)`, `client.pods.delete(pod_id=...)`                                                               |
| Pod-scoped resources                         | `agentmail pods:inboxes`, `agentmail pods:threads`, `agentmail pods:domains`, and siblings | `client.pods.inboxes`, `client.pods.threads`, and siblings                                                            | `client.pods.inboxes`, `client.pods.threads`, and siblings                                                                                          |
| Create org API key                           | `agentmail api-keys create`                                                                | `client.apiKeys.create({ name })`                                                                                     | `client.api_keys.create(name=...)`                                                                                                                  |
| List / delete API keys                       | `agentmail api-keys list`, `agentmail api-keys delete`                                     | `client.apiKeys.list()`, `client.apiKeys.delete(apiKeyId)`                                                            | `client.api_keys.list()`, `client.api_keys.delete(api_key_id=...)`                                                                                  |
| Mint scoped API key                          | `agentmail inboxes:api-keys create`, `agentmail pods:api-keys create`                      | `client.inboxes.apiKeys.create(inboxId, { name })`, `client.pods.apiKeys.create(podId, { name })`                     | `client.inboxes.api_keys.create(inbox_id=..., name=...)`, `client.pods.api_keys.create(pod_id=..., name=...)`                                       |
| Query event counts / usage totals            | not shown on this page                                                                     | `client.metrics.queryEvents({ eventTypes, period })`, `client.metrics.queryUsage({ usageTypes, period })`             | `client.metrics.query_events(event_types=[...], period=...)`, `client.metrics.query_usage(usage_types=[...], period=...)`                           |
| Get org limits and counts                    | `agentmail organizations get`                                                              | `client.organizations.get()`                                                                                          | `client.organizations.get()`                                                                                                                        |
| Agent sign-up / verify                       | `agentmail agent sign-up`, `agentmail agent verify --otp-code`                             | `client.agent.signUp({ humanEmail, username })`, `client.agent.verify({ otpCode })`                                   | `client.agent.sign_up(human_email=..., username=...)`, `client.agent.verify(otp_code=...)`                                                          |

## Facts

* All three surfaces read the API key from the `AGENTMAIL_API_KEY` environment variable. Explicit alternatives: `--api-key` on any CLI command, `apiKey` in the TypeScript constructor, `api_key` in the Python constructor.
* The CLI and SDKs add the `v0/` API prefix to every request themselves. A base URL must be the bare host: `https://api.agentmail.to` (default US) or `https://api.agentmail.eu` (EU region).
* Base URL overrides: the `--base-url` flag (CLI), the `baseUrl` option or `environment` with `AgentMailEnvironment.EuProd` (TypeScript), `environment` with `AgentMailEnvironment.EU_PROD` or a custom `AgentMailEnvironment(http=..., websockets=...)` (Python).
* Both SDKs retry failed requests with exponential backoff: 2 retries by default, on `408`, `429`, and `5xx`, waiting out a `Retry-After` header first. The request timeout defaults to 60 seconds.
* Per-request options override retries, timeout, and headers for one call: a final options argument in TypeScript, `request_options` in Python. The idempotency key on sends travels the same way.
* Inbox create: omit `username` and AgentMail generates the address. Python create takes a request object, imported with `from agentmail.inboxes import CreateInboxRequest`. Each inbox's address is in the `email` field of responses.
* Send returns the new message's `message_id` and the `thread_id` of the conversation it starts. Keep both to reply or follow up later.
* Custom `metadata` on inbox create and update: string, number, or boolean values, up to 256 keys, keys and string values up to 256 characters. An update merges the map, a `null` value removes that key, and `"metadata": null` clears the whole map.
* Deleting an inbox permanently removes its messages, threads, and drafts.
* Message list returns newest first with optional `labels` and time filters. Thread get returns every message, oldest first.
* Every list endpoint paginates the same way: pass `limit` (`--limit`) and `page_token` (`--page-token`, `pageToken`), read `count` and the entries from the page, then pass the response's `next_page_token` back as `page_token`. Loop until a response has no `next_page_token`. Most lists also take `ascending` for oldest first.
* Search is free text, ranked by relevance across senders, recipients, subjects, and message bodies. It exists for threads and for messages, per inbox or across the key's scope.
* A draft with `send_at` is delivered by AgentMail at that time, with no scheduler on your side. Deleting a draft also cancels a scheduled send.
* TypeScript draft recipient fields take arrays even for a single address, and TypeScript `drafts.send` requires a request object, `{}` when there are no label edits.
* Webhook create returns the `secret` used to verify delivery signatures. AgentMail delivers through Svix, and the `svix` libraries for TypeScript and Python verify in one call. Webhook delete stops deliveries immediately.
* Typed webhook payload classes: `serialization.events.MessageReceivedEvent.parse(payload)` in TypeScript, `MessageReceivedEvent(**payload)` imported from `agentmail` in Python. Both SDKs also include WebSocket clients that stream the same events over a persistent connection.
* Domain create returns the exact DNS records to publish. After `verify`, watch `status` with get. Inboxes can be created on the domain when `status` reads `VERIFIED`.
* Allow and block lists exist per inbox, per direction (`receive`, `reply`, `send`). An entry containing `@` matches one address, anything else matches a whole domain. Delete an entry with the same direction, type, and value it was created with.
* Pod create with `client_id` (your own tenant id) is idempotent: a retry returns the existing pod. Inboxes, threads, drafts, domains, lists, webhooks, API keys, and metrics all exist under pod routes. Delete a pod once it is empty.
* The full `api_key` value is returned only once, at creation. An inbox key acts only on its inbox, a pod key only inside its pod.
* Agent sign-up returns `api_key`, `inbox_id`, and `organization_id`, and emails a 6-digit code to the human. `agent verify`, authenticated with the new key, lifts the pre-verification limits.
* `organizations get` returns the organization's effective limits, add-ons and grants included, next to its current counts. These are the values enforcement uses.
* CLI output is JSON by default. `--format` takes `pretty`, `yaml`, or `explore`, `--transform` filters with GJSON syntax, and `--debug` logs each HTTP request and response.

## Not supported

* A lost API key value cannot be read again. Delete the key and create a replacement.
* Agent sign-up is for first-time users only.
* Webhook update does not merge `event_types`. The list sent replaces the subscription in full, so include every type wanted after the change.
* The metrics queries appear in TypeScript and Python only on this page. No CLI command is documented for them.

## Errors

| Error                            | HTTP status | Cause                                                                                            | Fix                                                                                                                            |
| -------------------------------- | ----------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| Key missing or invalid           | 401         | No usable key: `AGENTMAIL_API_KEY` unset and no explicit key on the call, or the value is wrong. | Export a valid `AGENTMAIL_API_KEY`, or pass `--api-key` (CLI), `apiKey` (TypeScript), `api_key` (Python).                      |
| `username` taken on inbox create | 403         | The requested `username` is already in use.                                                      | The response carries up to three available alternatives in `suggestions`. Use one, or omit `username` for a generated address. |
| Every call returns `404`         | 404         | The base URL already contains `/v0`, which doubles into requests to `/v0/v0/...`.                | Set the base URL to the bare host, `https://api.agentmail.to`.                                                                 |

## Verify

```bash
agentmail inboxes list
```

Success prints JSON with an `inboxes` array, one entry per inbox with its `inbox_id` and address in `email`. A `401` means the key is missing or invalid, a `404` means the base URL is wrong.

## Related

* `/quickstart` - get an API key and create a first inbox.
* `/integrations/mcp-and-skills` - the same operations as MCP tools instead of code.
* `/core/receive` - inbound calls, parameters, and attachment downloads in depth.
* `/core/send` - outbound parameters, scheduled drafts, and idempotent sends.
* `/core/conversations` - threads and label patterns.
* `/core/inbound-control` - how allow and block list entries match and interact.
* `/advanced/webhooks` - event catalog, payload shapes, and delivery contract.
* `/advanced/websockets` - the SDK WebSocket clients that stream the same events.
* `/advanced/custom-domains` - DNS records, verification statuses, and troubleshooting.
* `/advanced/multi-tenant` - pod provisioning and offboarding flow.
* `/advanced/plans-and-usage` - metrics parameters, scopes, and permissions.
