[relaybell docs › Developers › REST API authentication](https://relaybell.com/docs/authentication) · [All docs as Markdown](https://relaybell.com/docs.md) · [Index for AI assistants](https://relaybell.com/llms.txt)

# REST API authentication

> Bearer API keys, scopes and which routes need them, creating and revoking keys, expiry.

All server-side calls use a Bearer API key (starts with `rb_live_`):

```bash
curl https://relaybell.com/api/v1/stats \
  -H "Authorization: Bearer rb_live_xxxxx"
```

Create keys in the dashboard under **Settings → Developers → API keys**. Signing up doesn't make a key for you, and a key can't make other keys: `POST /api/v1/keys` works only with a dashboard session (an API key gets `403 session_required`). A key is shown once, when you create it; relaybell stores only a hash. Keep keys on your server — never put one in code that runs in a visitor's browser (the browser SDK needs only your project ID).

An API key belongs to one website, so calls made with it need no project id. (The dashboard calls the same routes with its session cookie and the website's id in `?projectId=`, the body or an `X-Project-Id` header.)

Every endpoint, with the scope it needs, its parameters, responses, error codes and examples, is in the [API reference](https://relaybell.com/docs/api), generated from the OpenAPI 3.1 document at [/openapi.json](https://relaybell.com/openapi.json) (for code generators, Postman or an AI agent's tools).

## API keys & scopes {#scopes}

Each key has a name, a list of **scopes** (what it may do) and an optional expiry date. Pick *Full access*, *Send only*, or any mix of the scopes below. Keys made before scopes existed have full access.

| Scope | Allows |
| --- | --- |
| `full` | Everything below (and it is the only scope that can list keys with `GET /api/v1/keys`). |
| `send` | `POST /api/v1/notifications` (sends and drafts), `PATCH` / `DELETE /notifications/:id`, `POST /notifications/:id/send` and `/cancel`, `POST /api/v1/upload`. |
| `events:write` | `POST /api/v1/events`. |
| `subscribers:read` | `GET /api/v1/subscribers/export`, `/subscribers/recent`, `/subscribers/:externalId/data` and `/profile`; `GET /api/v1/events`; `GET /api/v1/audience/subscribers`, `/audience/subscribers/facets` and `/audience/segments`. |
| `subscribers:write` | `POST /api/v1/subscribers/import`, `DELETE /api/v1/subscribers/:externalId`, `POST /api/v1/audience/subscribers/bulk-tag` and `/bulk-delete`. |
| `segments:write` | `POST`, `PUT` and `DELETE /api/v1/segments` (`POST /segments/preview` works with any key). |
| `settings:write` | `PUT /api/v1/settings`, `/prompt`, `/welcome`, `/logo`; `POST /reports/test`; changes to topics, automations, sequences (journeys), RSS feeds, recurring schedules, templates, goals and on-site messages. |
| `webhooks:write` | `POST`, `PUT` and `DELETE /api/v1/webhooks`, including `POST /webhooks/:id/test`, `/webhooks/:id/deliveries/:deliveryId/resend` and reading the delivery log (`GET /webhooks/:id/deliveries`). |

Reading works with any valid key: stats, reports, notifications, settings, segments, topics, automations, sequences, feeds, schedules, templates, goals, on-site messages, webhooks and their delivery logs (a key without `full` or `settings:write` doesn't get the Shopify signing secret back from `GET /api/v1/settings`). `GET` and `PUT /api/v1/identity` also work with any key (but only the dashboard can turn verification off — see [Identity verification](https://relaybell.com/docs/identity)). A call the key isn't allowed to make answers `403 { "error": "insufficient_scope", "required": "<scope>" }`; a key past its expiry date answers `401 api_key_expired`; a revoked or unknown key, `401 invalid_api_key`.

| Route | Description |
| --- | --- |
| **POST** `/api/v1/keys` | Dashboard session only. Body `{ name?, scopes?, expiresAt? }`: `name` up to 60 characters (default `"API key"`); `scopes` a list from the table (default `["full"]`; a list with `full` becomes just `["full"]`; anything else answers `400 invalid_scopes`); `expiresAt` an ISO date in the future, within 3 years, or `null` for none (`400 invalid_expiry`). Answers `201 { apiKey, key }` — `apiKey` is the only time you see the key. |
| **GET** `/api/v1/keys` | `{ keys: [{ id, prefix, name, scopes, expires_at, created_at, last_used_at, expired, current }], scopes }` — never the keys themselves. Needs `full`. |
| **DELETE** `/api/v1/keys/:id` | Revokes a key: `{ ok: true }`. The signed-in owner can revoke any key; an API key can revoke only itself (`:id` = its own id or `current`), anything else answers `403 session_required`. |

The **WordPress plugin** gets its own key when you connect a site, with `send` and `events:write` only: enough for publish notifications, WooCommerce events, test sends and user ID verification, but it can't download your subscribers or change your settings.
