# Authentication

# Authentication

Every call carries an API key as a bearer token:

```bash
curl https://acme.open-helpdesk.com/api/v1/tickets \
  -H "Authorization: Bearer ohd_live_…"
```

Keys are created in **Settings → API & webhooks**. The full key is displayed
once, at creation: we keep a SHA-256 hash and the first characters, so support
can recognise a key in a log without being able to use it. Lose it and you
revoke it and mint another — there is no recovery, by design.

## Scopes

A key carries the scopes it was created with:

| Scope | What it opens |
|---|---|
| `read` | Every `GET`. |
| `write` | Every `POST`, `PATCH` and `DELETE`. |
| `ticket:create` | `POST /tickets` and nothing else. |

`ticket:create` exists for the common case of a contact form or a monitoring
system that should be able to open a ticket and never read one. Give it that
key and a leak costs you nothing but noise.

## What the failures mean

They are deliberately different, because they call for different fixes:

- **401** — the key is missing, malformed, unknown or revoked. Check what you
  sent.
- **403** — the key is *known* but lacks the scope this route needs, or the
  workspace is suspended. Mint a key with the right scope; do not retry.
- **429** — you are over 600 requests per minute. Wait `Retry-After` seconds.

## Keeping a key safe

- Server-side only. A key in a browser or a mobile app is a public key.
- One key per integration, named after it. Revoking then costs you one
  integration, not all of them.
- Every call is recorded in the workspace's audit log with the key that made it,
  so "who did this" always has an answer.
