# Agent signup

POST /api/auth?action=agent-signup - autonomous agents create an account with an email OTP and receive an sk_ account token. No captcha, no browser.

*ProxyLLM docs · https://proxyllm.ai/docs/api/agent-signup*

Agent signup lets an autonomous agent create a ProxyLLM account by itself: it submits an email, verifies a one-time code from that inbox, and receives an `sk_` [account token](/docs/api/authentication). There is no captcha and no browser step. The new account starts without a membership; every management endpoint answers `402` with a checkout link until a human activates one, and the account is removed automatically 48 hours after signup if nobody does.

Machine-readable instructions for this whole flow live at [proxyllm.ai/auth.md](https://proxyllm.ai/auth.md); point your agent there.

## Step 1: request a code

```
POST https://proxyllm.ai/api/auth?action=agent-signup
```

```bash
curl -X POST "https://proxyllm.ai/api/auth?action=agent-signup" \
  -H "Content-Type: application/json" \
  -d '{"email": "ops@youragency.com", "source": "authmd"}'
```

`source` is optional: a short slug naming the artifact that sent the agent (`mcp`, `authmd`, `clawhub`, `bazaar`, `content`). It is stored on the account for attribution and changes nothing else.

Response:

```json
{
  "ok": true,
  "new_account": true,
  "account_expires_at": "2026-07-17T15:04:05.000Z"
}
```

A 6-digit code lands in the inbox. The email says plainly that an AI agent initiated the signup. If the email already belongs to a ProxyLLM account, the code simply signs in to it (`new_account: false`) and no removal deadline is added.

Disposable email domains are refused: control of a durable inbox is the identity anchor for this lane. Codes are limited to 3 per email per hour on top of a per-IP limit.

## Step 2: verify and receive the token

```
POST https://proxyllm.ai/api/auth?action=agent-verify
```

```bash
curl -X POST "https://proxyllm.ai/api/auth?action=agent-verify" \
  -H "Content-Type: application/json" \
  -d '{"email": "ops@youragency.com", "code": "123456"}'
```

Response:

```json
{
  "user": { "id": "5e2f8c1a-...", "email": "ops@youragency.com" },
  "account_token": "sk_...",
  "token_prefix": "sk_1234567890a",
  "token_scope": "read_write",
  "plan": "free",
  "payment": {
    "checkout_url": "https://whop.com/checkout/plan_...",
    "price_usd": 129,
    "account_expires_at": "2026-07-17T15:04:05.000Z",
    "poll": "GET /v1/organizations/me until plan is \"pro\"",
    "message": "This account has no active membership yet. ..."
  }
}
```

`account_token` is returned exactly once; store it. It is a normal read and write [account token](/docs/api/authentication), revocable any time under Settings. On the first verify, the account owner also gets one email naming the removal deadline and the checkout link, so the human hears about the account even if the agent forgets to mention it.

## Step 3: get a human to activate the membership

Until a membership is active, every management endpoint returns `402` with the same `payment` block and a plain `message` built for relaying to your operator. The one exception is [`GET /v1/organizations/me`](/docs/api/me), which keeps answering so the agent can poll:

```json
{
  "id": "5e2f8c1a-...",
  "email": "ops@youragency.com",
  "plan": "free",
  "token_scope": "read_write",
  "token_label": "Agent signup",
  "payment": { "checkout_url": "...", "account_expires_at": "..." },
  "message": "This account has no active membership yet. ..."
}
```

Hand your operator the `checkout_url`, then poll `me` until `plan` is `"pro"`. From there the full management surface opens: [create routing keys](/docs/api/routing-keys), [connect Codex](/docs/api/codex-session), [register bridges](/docs/api/bridges).

## The 48-hour removal

To prevent spam, an agent-created account that never activates a membership is removed automatically 48 hours after signup. The deadline is fixed at signup and returned as `account_expires_at` in every response above. After removal the token stops working with `410 account_expired`, and the same email may sign up again from scratch. Activation clears the deadline permanently.

## Errors

| Status | Code               | When                                                                           |
| ------ | ------------------ | ------------------------------------------------------------------------------ |
| 400    | (none)             | Missing or invalid email, disposable email domain, or a wrong/expired code.    |
| 402    | `payment_required` | Any management call before a membership is active.                             |
| 410    | `account_expired`  | The 48-hour window passed with no activation. Sign up again.                   |
| 429    | (none)             | Rate limit: more than 3 codes per email per hour, or too many requests per IP. |
| 502    | (none)             | The verification email could not be sent. Try again.                           |
