# Authentication

Every request carries a key or a token as a bearer credential. Here is how each kind works and what it can reach.

Send a credential in the `Authorization` header of every request:

```text title="Header"
Authorization: Bearer lup_org_live_…
```

There are no sessions, cookies or query-string keys in the public API. A request without a valid credential gets **401** with the code `auth.unauthenticated`, whatever the reason, so the response never tells an attacker whether a key exists.

## Two kinds of credential

|  | Organization key | Personal access token |
| --- | --- | --- |
| Starts with | `lup_org_live_` | `lup_pat_live_` |
| Belongs to | The organization | One member, in one organization |
| Use it for | Integrations: a sync, a pipeline, an automation | Your own scripts and tools |
| Can do | What its permissions allow | Its permissions, limited to what you can still do |
| When its creator leaves | Keeps working | Stops working |
| Expires after | 1 year at most | 90 days by default, 1 year at most |
| Created in | **Settings › API keys** | **Settings › Tokens** |

Not sure which one you need? Read [Keys or tokens?](/guides/keys-or-tokens).

## Permissions

A credential carries a list of permissions, chosen when it is created, such as `leads:read` or `leads:update`. Each endpoint in the [API reference](/reference) names the permission it needs. Without it the API answers **403** `auth.forbidden` and names the missing permission in `params.permission`.

Give each credential the fewest permissions that do its job. You can't widen a credential later; create a new one instead.

<Note title="Keep credentials secret" tone="warning">
  Never put a key in a URL, a front-end bundle, a log or a support message. If one leaks, revoke it in the app; it stops working on the next request.
</Note>
