# Authentication and scopes

> How an API token authenticates, what its scopes allow, and how the plan and the role add to them.

## The token

Every request carries the token in the `Authorization` header, as `Bearer` followed by the token:

```bash
curl "https://api.nessflow.com/v1/me" \
  -H "Authorization: Bearer $NESSFLOW_TOKEN"
```

A token belongs to a member and acts for **one** team. It expires (90 days by default, 365 at most), and it stops working as soon as its holder leaves the team. No cookie, no session: the API is spoken server to server.

A missing, invalid or expired token answers `401` with the `unauthenticated` code:

```bash expect=401
curl "https://api.nessflow.com/v1/me" \
  -H "Authorization: Bearer invalid-token"
```

## Scopes

A scope combines a **domain** and a **verb**: `projects:read`, `crawls:write`, `positions:write`, `webhooks:read`… A `write` scope does not include the `read` of the same domain. Give each integration only the scopes it needs.

A call without the required scope answers `403` with the `token.missing_scope` code and the `required_scopes` list.

## Three permissions, always

A call must be allowed by all three at once:

1. the team's **plan** opens the verb (`api.not_in_plan`, `api.write_not_in_plan`);
2. the member's **role** allows the action (managing webhooks is reserved to owners and admins);
3. the **token** carries the scope.

Plan refusals name the plan that would lift them (`upgrade_to`): retrying will not change anything.

## Language

Error titles and translated texts follow the `Accept-Language` header (`fr` or `en`, `fr` by default). Codes are never translated.
