> ## Documentation Index
> Fetch the complete documentation index at: https://docs.r3al.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Team: accounts, invites, roles

> Register/login, invite teammates with a role, and manage the roster.

Real accounts (`users` table), real sessions (30-day tokens), real invites -- no fake data, no mail service (invites are shareable links you send yourself). Capped at `R3AL_MAX_ACCOUNTS` (default 3) while this is in testing.

These endpoints live under `/v1/auth/*` and are **not** gated by the general `/v1/*` API-key requirement -- registration/login obviously can't require a token you don't have yet. `/register`, `/login`, and `/site-login` do have their own [rate limit tier](/api/rate-limiting).

## Register & login

```bash theme={null}
curl -X POST https://platform.r3al.ai/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"name": "Ada", "email": "ada@example.com", "password": "s3cur3-enough"}'
```

```json theme={null}
{
  "user": { "id": "u_abc123", "name": "Ada", "email": "ada@example.com", "role": "admin", "created_at": 1752600000.0 },
  "token": "r3l_sess_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "api_key": "r3l_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

The **first account** on a team becomes `admin` automatically. Every registration after that defaults to `member` unless it redeems an invite that specifies a different role.

New accounts must verify their email before minting keys and running jobs. The platform emails a verification link; the SDK page prompts you until it is confirmed.

```bash theme={null}
curl -X POST https://platform.r3al.ai/v1/auth/verify-email \
  -H "Content-Type: application/json" \
  -d '{"token": "<verification token from the email>"}'
```

```bash theme={null}
curl -X POST https://platform.r3al.ai/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "ada@example.com", "password": "s3cur3-enough"}'
```

Login always mints a **fresh** API key alongside the session token (previous keys aren't auto-revoked -- if you rely on a stable long-lived key, mint one explicitly via `POST /v1/keys` instead of relying on the login-minted one).

`token` doubles as a Bearer credential for the rest of `/v1/*` -- see [Authentication](/api/authentication).

## Invites

Admin-only. No email is sent -- copy the returned `token` into a link (`/auth?invite=<token>`) and send it yourself.

```bash theme={null}
curl -X POST https://platform.r3al.ai/v1/auth/invites \
  -H "Authorization: Bearer <admin session token>" \
  -H "Content-Type: application/json" \
  -d '{"email": "teammate@example.com", "role": "developer"}'
```

```json theme={null}
{
  "id": "inv_a1b2c3d4e5f6",
  "email": "teammate@example.com",
  "invited_by": "u_abc123",
  "token": "r3l_invite_xxxxxxxxxxxxxxxxxxxxxxxx",
  "created_at": 1752600000.0,
  "role": "developer"
}
```

`email` is optional -- omit it to create a link anyone can redeem once. `role` defaults to `member` if omitted.

| Endpoint                              | Role required      | Notes                                                                       |
| ------------------------------------- | ------------------ | --------------------------------------------------------------------------- |
| `GET /v1/auth/invites`                | Any signed-in user | List pending (unredeemed) invites                                           |
| `POST /v1/auth/invites`               | Admin              | Create an invite, decides the redeemer's role                               |
| `DELETE /v1/auth/invites/{id}`        | Admin              | Revoke a pending invite                                                     |
| `GET /v1/auth/invites/lookup/{token}` | Public             | Look up an invite by token (used by the sign-up page to prefill/lock email) |

## Roster & roles

```bash theme={null}
curl https://platform.r3al.ai/v1/auth/users -H "Authorization: Bearer <session token>"
```

```json theme={null}
{
  "users": [
    { "id": "u_abc123", "name": "Ada", "email": "ada@example.com", "role": "admin", "created_at": 1752600000.0 }
  ],
  "count": 1
}
```

Any signed-in user can view the roster. Changing a role is Admin-only:

```bash theme={null}
curl -X PATCH https://platform.r3al.ai/v1/auth/users/u_def456/role \
  -H "Authorization: Bearer <admin session token>" \
  -H "Content-Type: application/json" \
  -d '{"role": "member"}'
```

Refuses (`409`) to demote the platform's last remaining Admin. See [Authentication](/api/authentication) for what each role can do.

## Session lifecycle

| Endpoint               | Purpose                                                                                                     |
| ---------------------- | ----------------------------------------------------------------------------------------------------------- |
| `GET /v1/auth/status`  | Public. `{"account_count", "max_accounts", "registration_open"}` -- powers the sign-in page's capacity note |
| `GET /v1/auth/me`      | Current signed-in user                                                                                      |
| `POST /v1/auth/logout` | Deletes the current session token server-side                                                               |
