# Quickstart (/quickstart)

<!-- agent-signals: reading_time_min: 4 · est_tokens: 1845 · updated: 2026-08-03 -->
Related: [Introduction](/introduction.md), [How AgentMail is architected](/architecture.md)



# Create an AgentMail account when needed, then create an inbox and verify a send, receive, and reply loop

Use the CLI for this walkthrough. `curl`, TypeScript, and Python call the same API. Standard API requests use `https://api.agentmail.to/v0` and `Authorization: Bearer <API_KEY>`.

## Obtain an API key when you do not have one

Create an organization, inbox, and API key with the unauthenticated agent signup endpoint. This endpoint has **no `/v0` prefix**.

<CodeGroup>
  ```bash tab="CLI" tab-group="cli+curl"
  agentmail agent sign-up \
    --human-email "<owner@example.com>" \
    --username "my-agent"
  ```

  ```bash tab="curl" tab-group="cli+curl"
  curl -X POST "https://api.agentmail.to/agent/sign-up" \
    -H "Content-Type: application/json" \
    -d '{
      "human_email": "<owner@example.com>",
      "username": "my-agent"
    }'
  ```
</CodeGroup>

Store `api_key` immediately. It cannot be retrieved again. `inbox_id` is the new inbox address.

```json title="Sample response"
{
  "organization_id": "<organization_id>",
  "inbox_id": "my-agent@agentmail.to",
  "api_key": "<api_key>"
}
```

A six-digit OTP is sent to `human_email`. Obtain the code from the human, then verify the organization. This endpoint also has no `/v0` prefix.

<CodeGroup>
  ```bash tab="CLI" tab-group="cli+curl"
  agentmail agent verify \
    --otp-code "<6-digit code>"
  ```

  ```bash tab="curl" tab-group="cli+curl"
  curl -X POST "https://api.agentmail.to/agent/verify" \
    -H "Content-Type: application/json" \
    -d '{ "otp_code": "<6-digit code>" }'
  ```
</CodeGroup>

```json title="Sample response"
{ "verified": true }
```

Re-running signup is safe only before verification: it rotates the API key and resends the OTP. Once verified, signup returns HTTP `403` because the organization already exists. Sign in, then reuse or rotate an existing API key.

## Authenticate

Set the key returned by signup, or an existing key:

```bash
export AGENTMAIL_API_KEY="<API_KEY>"
export AGENTMAIL_BASE_URL="https://api.agentmail.to/v0"
```

<CodeGroup>
  ```bash tab="CLI" tab-group="cli+curl+python+typescript"
  npm install -g agentmail-cli
  agentmail auth me
  ```

  ```bash tab="curl" tab-group="cli+curl+python+typescript"
  curl "$AGENTMAIL_BASE_URL/auth/me" \
    -H "Authorization: Bearer $AGENTMAIL_API_KEY"
  ```

  ```typescript tab="TypeScript" tab-group="cli+curl+python+typescript"
  // npm install agentmail
  import { AgentMailClient } from "agentmail";

  const client = new AgentMailClient({ apiKey: process.env.AGENTMAIL_API_KEY });
  console.log(await client.auth.me());
  ```

  ```python tab="Python" tab-group="cli+curl+python+typescript"
  # pip install agentmail
  import os
  from agentmail import AgentMail

  client = AgentMail(api_key=os.environ["AGENTMAIL_API_KEY"])
  print(client.auth.me())
  ```
</CodeGroup>

```json title="Sample response"
{
  "scope_type": "organization",
  "scope_id": "<organization_id>",
  "organization_id": "<organization_id>",
  "api_key_id": "<api_key_id>"
}
```

## Create an inbox

Create an inbox, then retain its `inbox_id` for the next requests.

<CodeGroup>
  ```bash tab="CLI" tab-group="cli+curl+python+typescript"
  agentmail inboxes create \
    --display-name "Quickstart inbox"
  ```

  ```bash tab="curl" tab-group="cli+curl+python+typescript"
  curl -X POST "$AGENTMAIL_BASE_URL/inboxes" \
    -H "Authorization: Bearer $AGENTMAIL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "display_name": "Quickstart inbox" }'
  ```

  ```typescript tab="TypeScript" tab-group="cli+curl+python+typescript"
  const inbox = await client.inboxes.create({ displayName: "Quickstart inbox" });
  console.log(inbox.inboxId);
  ```

  ```python tab="Python" tab-group="cli+curl+python+typescript"
  inbox = client.inboxes.create(display_name="Quickstart inbox")
  print(inbox.inbox_id)
  ```
</CodeGroup>

```json title="Sample response"
{
  "pod_id": "<pod_id>",
  "inbox_id": "<generated-username>@agentmail.to",
  "email": "<generated-username>@agentmail.to",
  "display_name": "Quickstart inbox",
  "created_at": "2026-07-13T09:15:04Z",
  "updated_at": "2026-07-13T09:15:04Z"
}
```

## Send, receive, and reply

Send a message to the new inbox. Use `text`, not `body`.

<CodeGroup>
  ```bash tab="CLI" tab-group="cli+curl+python+typescript"
  agentmail inboxes:messages send \
    --inbox-id "<inbox_id>" \
    --to "<inbox_id>" \
    --subject "Hello from the quickstart" \
    --text "This is a test message."
  ```

  ```bash tab="curl" tab-group="cli+curl+python+typescript"
  curl -X POST "$AGENTMAIL_BASE_URL/inboxes/<inbox_id>/messages/send" \
    -H "Authorization: Bearer $AGENTMAIL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "to": "<inbox_id>",
      "subject": "Hello from the quickstart",
      "text": "This is a test message."
    }'
  ```

  ```typescript tab="TypeScript" tab-group="cli+curl+python+typescript"
  const sent = await client.inboxes.messages.send("<inbox_id>", {
    to: "<inbox_id>",
    subject: "Hello from the quickstart",
    text: "This is a test message.",
  });
  console.log(sent.messageId, sent.threadId);
  ```

  ```python tab="Python" tab-group="cli+curl+python+typescript"
  sent = client.inboxes.messages.send(
      inbox_id="<inbox_id>",
      to="<inbox_id>",
      subject="Hello from the quickstart",
      text="This is a test message.",
  )
  print(sent.message_id, sent.thread_id)
  ```
</CodeGroup>

```json title="Sample response"
{
  "message_id": "<message_id>",
  "thread_id": "<thread_id>"
}
```

List the inbox until the message arrives, then reply using its `message_id`.

<CodeGroup>
  ```bash tab="CLI" tab-group="cli+curl+python+typescript"
  agentmail inboxes:messages list \
    --inbox-id "<inbox_id>"

  agentmail inboxes:messages reply \
    --inbox-id "<inbox_id>" \
    --message-id "<message_id>" \
    --text "Got it, replying from the quickstart."
  ```

  ```bash tab="curl" tab-group="cli+curl+python+typescript"
  curl "$AGENTMAIL_BASE_URL/inboxes/<inbox_id>/messages" \
    -H "Authorization: Bearer $AGENTMAIL_API_KEY"

  curl -X POST "$AGENTMAIL_BASE_URL/inboxes/<inbox_id>/messages/<message_id>/reply" \
    -H "Authorization: Bearer $AGENTMAIL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "text": "Got it, replying from the quickstart." }'
  ```

  ```typescript tab="TypeScript" tab-group="cli+curl+python+typescript"
  const messages = await client.inboxes.messages.list("<inbox_id>");
  const messageId = messages.messages[0].messageId;
  const reply = await client.inboxes.messages.reply(
    "<inbox_id>",
    messageId,
    { text: "Got it, replying from the quickstart." },
  );
  console.log(reply.messageId, reply.threadId);
  ```

  ```python tab="Python" tab-group="cli+curl+python+typescript"
  messages = client.inboxes.messages.list(inbox_id="<inbox_id>")
  message_id = messages.messages[0].message_id
  reply = client.inboxes.messages.reply(
      inbox_id="<inbox_id>",
      message_id=message_id,
      text="Got it, replying from the quickstart.",
  )
  print(reply.message_id, reply.thread_id)
  ```
</CodeGroup>

The list response contains `messages[]`, newest first. Each message has `message_id` and `thread_id`; the reply response uses the send response shape. List again and confirm the original message and reply have the same `thread_id`.


## Tenant instructions

Every page ships two renditions at one URL. The HTML page is for humans. The Markdown rendition (append .md to any page URL, or request with Accept: text/markdown) is agent-optimized: a Do this section with runnable commands, SDK signatures, exhaustive Facts, a Not supported section listing shapes that do NOT work, an Errors table, and a Verify command. Prefer the Markdown rendition over scraping HTML, and trust Not supported entries instead of retrying those call shapes.