# Sign up as an agent

An agent can create the account without a browser and without a key. Two public routes; the person who owns
the mailbox proves it once by reading one mail. The browser signup form keeps its captcha; these routes stand
behind the limits in the table below instead. Accounts that Linkio staff create follow their own path; the
gate covers these two public routes.

1. Register with `POST /api/signup`:

```
curl -s -X POST https://www.linkio.com/api/signup -H 'content-type: application/json' \
  -d '{"email":"owner@example.com","password":"<8+ chars>","name":"Dana","website":"https://example.com"}'
```

`202` `{"status":"verification_sent"}` is the one success answer, the same for a new, a pending or an already
registered email (the body never says which). `password` needs at least 8 characters; `name` is required;
`website` and `company` are optional strings. Refusals: `400` `INVALID_REQUEST` (not JSON, or email, password
or name missing), `400` `PASSWORD_TOO_SHORT`, `400` `EMAIL_REJECTED` (the address does not parse, its domain has
no MX record, or it is a disposable domain), `429` `RATE_LIMITED` with a `Retry-After` header (a limit in the
table), `409` `IDENTITY_PASSWORD_LOCKED` (the email is a login of another kind with another password). A pending
address registered again gets the same code mailed once more (once a minute, 5 a day). No mail within 10 minutes
means the email is already registered and verified: sign in on the web.

2. The mail "Verify Your Email Address - Linkio" carries the link for a person and, on its own line, the
sentence "Did an AI agent create this account for you? Give it this verification code:" followed by the code.
The person gives the code to the agent.

3. Verify and receive the first key with `POST /api/signup/verify`:

```
curl -s -X POST https://www.linkio.com/api/signup/verify -H 'content-type: application/json' -d '{"token":"<code>"}'
```

`201` `{ accountId, apiKey, keyPrefix, scopes, expiresAt: null, next: { receipt, providerKeys, addMoney, pricing } }`.
`apiKey` is the `acc_` key, shown once. Refusals: `410` `TOKEN_USED` (the code was already used through this
route; the account is verified, use the key it returned; an account blocked while pending answers this too),
`400` `TOKEN_EXPIRED` (older than 24 hours: register the same email again and a fresh mail with the code is sent),
`404` `TOKEN_UNKNOWN` (no pending account created through this route carries the code; if the person clicked
the link first, the code answers `404`: the account is verified, sign in on the web and create a key on
`/account/api-keys`), `400` `INVALID_REQUEST` (no `token`).

4. What the first key can do: it holds 39 scopes, the self-serve list without `billing:write`, `api-keys:read` or `api-keys:write` (the same list as the Automation level), so it reads and
works but cannot change the account's spending limits or card, cannot decide approvals and cannot mint keys
(`403` `owner_only`; the owner adds keys on `/account/api-keys`, and a key for an account whose email is not
verified is refused with `403` `email_not_verified`). Nothing is spendable until the account has its own
provider keys (both live, which also grants the free start described in [Billing, limits and receipts](/docs/api/billing)) or a card:
`GET /api/account/usage/receipt` answers `canStartPaidWork` false until then. `next` names the four calls that
follow.

| Limit | Value | Answer |
|---|---|---|
| Per IP | 2 per hour | `429` `RATE_LIMITED` |
| Per new email | 1 per day | `429` `RATE_LIMITED` |
| Per email domain | 5 per day | `429` `RATE_LIMITED`; shared mail providers such as gmail.com are exempt |
| Verification mail resent | once a minute, 5 per day | `429` `RATE_LIMITED` |
| New emails, all callers together | 60 per hour | `429` `RATE_LIMITED` |
| Code lifetime | 24 hours | `400` `TOKEN_EXPIRED` |

When the hourly cap is reached a new email answers `429` while an already registered one still answers `202`;
the cap is an outbound-mail bound, not a secrecy promise. The limits count per server process.
