---
title: "Agent Sign-up"
description: "Let an AI agent create a threadapi account and API key for a user. The user only reads a 6-digit code from their email back to the agent."
---

> Documentation Index
> Fetch the complete documentation index at: https://staging.threadapi.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Sign-up

An AI agent (a skill, an MCP client, a coding assistant) can create a threadapi account for its user and get an API key without a browser. The user confirms by reading a 6-digit code from their email back to the agent.

1. Ask the user for their email address.
2. `POST https://threadapi.dev/api/agent/signup` with the email. threadapi emails a code and returns a `signup_token`.
3. Ask the user for the code.
4. `POST https://threadapi.dev/api/agent/verify` with the token and the code. The response holds the new `api_key`.
5. Store the key where the user's tools can read it, for example as `THREADAPI_API_KEY`, and use it as a [Bearer token](/docs/authentication).

> **Keep the key out of the conversation**
>
> Write the verify response to a file or a variable instead of printing it, and do not echo `api_key` into the chat.

---

## 1. Request a code

```bash
curl -s -X POST https://threadapi.dev/api/agent/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'
```

```json
{
  "status": "code_sent",
  "signup_token": "eyJwdXJwb3NlIjoi…",
  "expires_in": 600,
  "next": "A 6-digit code was emailed to user@example.com. Ask the user for it, then POST …"
}
```

The token and the code are valid for 10 minutes. The answer is the same whether or not the email already has an account.

## 2. Verify the code and get the key

```bash
curl -s -X POST https://threadapi.dev/api/agent/verify \
  -H "Content-Type: application/json" \
  -d '{"signup_token": "<signup_token>", "code": "123456"}' \
  -o threadapi-signup.json
```

`201 Created`:

```json
{
  "status": "account_created",
  "api_key": "tapi_…",
  "credits": 100,
  "limits": { "requests_per_second": 1, "requests_per_day": 100 },
  "next": "Store api_key where the user's tools can read it …",
  "example_request": "GET https://api.threadapi.dev/v1/reddit/post?url=https://www.reddit.com/r/programming/comments/1x144ok/&format=md",
  "docs": "https://docs.threadapi.dev",
  "notes": "The account has 100 free credits; only successful requests use credits. …"
}
```

The user can sign in at [threadapi.dev](https://threadapi.dev/auth/login?utm_source=docs) with the same email to see usage, manage keys, and buy credits.

## Existing accounts

If the email already has a threadapi account, `/api/agent/verify` answers `409 account_exists` once the code is correct, and no key is created. The user signs in at [threadapi.dev/auth/login](https://threadapi.dev/auth/login?utm_source=docs) and creates a key at [threadapi.dev/app/api-keys](https://threadapi.dev/app/api-keys?utm_source=docs).

## Free credits and limits

New accounts get **100 free credits**, once per email address: a `+tag` or a Gmail address with dots counts as the same mailbox. Outside large email providers, only a few new accounts per email domain get them each day. Until the account buys a pack, its keys can make **1 request per second** and **100 requests per day** (UTC); any [credit pack](/docs/pricing) removes the daily limit.

## Errors

Errors use the API's standard envelope:

```json
{
  "error": {
    "code": "invalid_code",
    "message": "That code is wrong. Ask the user to check the email and try again. …",
    "retryable": false
  }
}
```

| Status | Code | What to do |
| :--- | :--- | :--- |
| 400 | `invalid_email` | Ask the user for a valid email address. |
| 400 | `disposable_email` | Temporary inboxes are not accepted. Ask for the user's regular address. |
| 400 | `undeliverable_email` | The domain cannot receive mail. Check the address with the user. |
| 400 | `invalid_request` | Send `signup_token` and a 6-digit `code`. |
| 400 | `invalid_signup_token` | The token is wrong or older than 10 minutes. Start over. |
| 400 | `invalid_code` | Ask the user to check the code. After 3 wrong codes, start over. |
| 400 | `code_expired` | The code is older than 10 minutes. Start over. |
| 400 | `too_many_attempts` | 3 wrong codes. Start over. |
| 409 | `account_exists` | The user creates a key on the website (see above). |
| 429 | `rate_limited` | Too many sign-ups or codes for this network or email. Try again later. |
| 502 | `email_failed` | The code email could not be sent. Retry in a minute. |
| 503 | `agent_signup_busy` | Agent sign-up is paused for a while. Try again later, or the user signs up at [threadapi.dev](https://threadapi.dev/auth/login?utm_source=docs). |
| 503 | `agent_signup_disabled` | Agent sign-up is off. The user can sign up at [threadapi.dev](https://threadapi.dev/auth/login?utm_source=docs). |

"Start over" means calling `/api/agent/signup` again, which sends a new code.

Source: https://staging.threadapi.dev/docs/agent-signup/index.mdx
