# Roles & permissions (/security/roles-and-permissions)

Bitelio's access control is built on granular `resource:action` permission keys — `campaigns:send`, `contacts:delete`, `team:manage`, and so on. Every member has a role, and a role is just a named set of these keys. When a request hits the API, the server resolves the caller's role to its permission set and checks it against the endpoint being called. There's no client-side gate to work around: a member without the right key gets a `403`, full stop.

## Preset roles

Five system roles ship with every project. They're not editable or deletable — if you need something in between, create a [custom role](#custom-roles) instead.

| Role        | Intent                                                                                                                                        |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Owner**   | Full control, including everything about the project itself — the only role that can be trusted with project-level changes.                   |
| **Admin**   | The same operational access as Owner, minus control over the project itself.                                                                  |
| **Editor**  | Create and send content — campaigns, contacts, segments, templates, workflows — without account-level access like billing or team management. |
| **Analyst** | Read-only access across campaigns, contacts, segments, templates, workflows, and analytics.                                                   |
| **Billing** | Manages billing and views analytics; nothing else.                                                                                            |

## Custom roles

When the presets don't fit, create a custom role with any subset of the available permissions and assign it to a member. Custom roles behave exactly like preset roles at request time — the server checks the same permission keys either way.

## Guardrails

A few rules keep roles from being used to lock everyone out or quietly gain more access than intended:

* **Last-Owner protection** — the final Owner on a project can't be removed or demoted. There must always be at least one.
* **No-privilege-escalation** — you can only grant permissions you hold yourself. An Editor can't create a custom role with `billing:manage`, even for someone else.
* **Reserved names** — `Owner` and the other system role names can't be reused for a custom role, so a lookalike role can never be mistaken for the real thing.

## Managing roles

Go to **Settings → Team & Roles** to see the permission matrix and change any member's role from a per-member select. This page itself is gated by the `team:manage` permission, so only members who already have it can change others' access.

## API keys

API keys are scoped independently of roles: each secret key carries its own explicit set of permissions, chosen when it's created, and can never exceed what its creator holds. See the [API Keys guide](/guides/api-keys) for the full list of grantable and non-grantable permissions.

## What's next

<Cards>
  <Card title="Two-factor authentication" href="/security/two-factor-authentication">
    Add a second sign-in step on top of a member's role.
  </Card>

  <Card title="Security & access" href="/security">
    Back to the overview of the access-control surface.
  </Card>
</Cards>
