# Signup and accounts

> Self-serve signup for buyers and sellers, and the email/password console login. These are the only routes you can call without an API key.

## Signup

### `POST /v1/signup`

**No auth.** Claims an address and sends a confirmation email. **Creates nothing yet.**

| Field | Type | Required | Notes |
|---|---|---|---|
| `role` | `"buyer"` \| `"seller"` | yes | |
| `email` | string | yes | |
| `organizationName` | string | yes | |
| `website` | string | no | helps seller verification |
| `dailyBudgetMinor` | string | no | buyers only: the workspace's daily cap in cents |
| `password` | string | no | enables console sign-in once the email is confirmed |

```json
// 202
{ "signupId": "sgn_…", "status": "pending", "expiresAt": "…", "emailSent": true }
```

There's one pending signup per email and role. Asking again resends the email for the same signup. The response is identical whether or not the address is already known.

### `POST /v1/signup/verify`

**No auth.** Uses the emailed token and creates the tenant and its root key.

| Field | Type | Required |
|---|---|---|
| `token` | string, from the email link | yes |

```json
// 201
{
  "signupId": "sgn_…", "role": "seller", "status": "completed",
  "tenant": { "kind": "provider", "id": "prv_…", "name": "Acme OCR", "walletId": "wal_…" },
  "credential": { "keyId": "akey_…", "token": "zk.akey_….…", "label": "…", "scopes": ["…"] }
}
```

`credential.token` is shown **once**. `walletId` (sellers only) is the settlement wallet. The token can be used only once and expires after 24 hours. If two requests use it at the same moment, only one tenant is created.

### `POST /v1/signup/resend`

**No auth.** Body `{ role, email }`. Always returns `202`. Invalidates the previous link.

### `GET /v1/signup/:id`

**No auth.** The status of a signup by its `signupId`: `pending`, `completed` or `expired`. Returns no email address and no token.

## Console accounts

A console session is an ordinary API key of kind `session`, limited to your tenant.

### `POST /v1/accounts/login`

**No auth.** Body `{ email, password }`. Returns `{ sessionToken, expiresAt?, scopes, account }`. Failed attempts count toward a lockout.

### `POST /v1/accounts/logout`

Revokes **the session presenting it**. It refuses an ordinary API key, so an agent's key can't be revoked from a sign-out button by mistake.

### `GET /v1/accounts/me`

The account behind the current session. Returns `404` for an ordinary API key.

### `POST /v1/accounts/password/forgot`

**No auth.** Body `{ email }`. Always returns `202` with the same body.

### `POST /v1/accounts/password/reset`

**No auth.** Body `{ token, password }`. Revokes every console **session** and **no** API keys, so your agents keep running.

### `POST /v1/accounts/password`

Changes the password while signed in. Body `{ currentPassword, newPassword }`.
