# Sign Up (/api-reference/sign-up)

<!-- agent-signals: reading_time_min: 3 · est_tokens: 1273 · updated: 2026-09-29 -->
Related: [Attach Human](/api-reference/attach-human.md), [Verify](/api-reference/verify.md), [List Inboxes](/api-reference/list-inboxes.md), [Create Inbox](/api-reference/create-inbox.md), [Search Inboxes](/api-reference/search-inboxes.md), [Get Inbox](/api-reference/get-inbox.md)

# Sign Up

`POST /v0/agent/sign-up`

> Create a new agent organization with an inbox and API key. This endpoint is for signing up for the first time. If you've already signed up, you're all set — just use your existing API key.
>
> A 6-digit OTP is sent to the human's email for verification.
>
> `human_email` is optional. Without it, the inbox can receive email but cannot send to anyone until a human is attached with the attach human endpoint. There is also no way to recover the API key, so store it durably. Calling sign-up again without `human_email` creates a new organization, which needs a different `username`: the original username stays with the lost organization's inbox.
>
> This endpoint is idempotent. Calling it again with the same `human_email` will rotate the API key and resend the OTP if expired.
>
> The returned API key has limited permissions until the organization is verified via the verify endpoint.
>
> **CLI:**
> ```bash
> agentmail agent sign-up --human-email user@example.com --username my-agent
> ```

## OpenAPI

```json
{
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "human_email": {
              "type": "string",
              "description": "Email address of the human who owns the agent. A 6-digit OTP will be sent to this address.\nOmit it to get a receive-only inbox: it can receive email but cannot send until a human is attached with the attach human endpoint."
            },
            "username": {
              "type": "string",
              "description": "Username for the auto-created inbox (e.g. \"my-agent\" creates my-agent@agentmail.to)."
            },
            "source": {
              "type": "string",
              "description": "The SDK, framework, or platform issuing this sign-up (e.g. `agentmail-python`, `agentmail-cli`, `agentmail-mcp`).\nIdentifies the caller — answers \"who is signing up\".\nMax 2048 characters."
            },
            "referrer": {
              "type": "string",
              "description": "The channel that drove this sign-up — where the agent or its developer discovered AgentMail\n(e.g. `agent.email`, a partner URL, a campaign tag). Answers \"where did this sign-up come from\".\nMax 2048 characters."
            }
          },
          "required": [
            "username"
          ],
          "description": "Request body to sign up an agent.",
          "title": "AgentSignupRequest"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Response with status 200",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "organization_id": {
                "type": "string",
                "description": "ID of the created organization."
              },
              "inbox_id": {
                "type": "string",
                "description": "ID of the auto-created inbox."
              },
              "api_key": {
                "type": "string",
                "description": "API key for authenticating subsequent requests. Store this securely, it cannot be retrieved again."
              }
            },
            "required": [
              "organization_id",
              "inbox_id",
              "api_key"
            ],
            "description": "Response after successful agent sign-up.",
            "title": "AgentSignupResponse"
          }
        }
      }
    },
    "400": {
      "description": "Error response with status 400",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Name of error.",
                "title": "ErrorName"
              },
              "code": {
                "type": "string",
                "description": "Stable, machine-readable error code in snake_case (for example, not_found or missing_permission). Branch on this rather than the message text.",
                "title": "ErrorCode"
              },
              "message": {
                "type": "string",
                "description": "Error message.",
                "title": "ErrorMessage"
              },
              "errors": {
                "description": "Validation errors. Each entry has a path and a message identifying the invalid field."
              },
              "fix": {
                "type": "string",
                "description": "The concrete next action that resolves the error.",
                "title": "ErrorFix"
              },
              "docs": {
                "type": "string",
                "description": "Link to the error reference entry for this code.",
                "title": "ErrorDocs"
              }
            },
            "required": [
              "name",
              "errors"
            ],
            "title": "ValidationErrorResponse"
          }
        }
      }
    }
  }
}
```
