# Authentication

Authenticate every request with a Talent-Ray API key.

Every API request is authenticated with an **API key**. Keys are issued by an administrator on behalf of a user, and a key carries exactly that user's role and organization memberships.

## Key format

A Talent-Ray API key:

- starts with the prefix `tr_`
- is **67 characters** long in total
- is shown **once**, at creation — it is stored hashed and can never be retrieved again

```
tr_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```

<Notice type="warning" title="Store the key securely">
The full key is returned only in the response that creates it. If you lose it, revoke the key and mint a new one — there is no way to recover the original value.
</Notice>

## Sending the key

Send the key on every request using the `Authorization` header with the `Bearer` scheme (preferred):

```bash
curl https://app.talent-ray.com/api/admin/api-keys \
  -H "Authorization: Bearer tr_YOUR_KEY_HERE"
```

The `x-api-key` header is accepted as a fallback:

```bash
curl https://app.talent-ray.com/api/admin/api-keys \
  -H "x-api-key: tr_YOUR_KEY_HERE"
```

<Notice type="error" title="Never put the key in a URL">
Do not pass the key as a query parameter. Keys must only travel in a request header.
</Notice>

## Permissions

A key's access equals its owner's role:

| Owner role | Can access |
| --- | --- |
| `admin` | Platform administration, including API key management |
| Employer / org owner | Their organization's data |
| Hiring manager | Only roles assigned to them |

This is the key's **ceiling** — the most it can ever do.

## Scopes

For the versioned `/api/v1/*` endpoints, a key also carries **per-key scopes** — a least-privilege gate *on top of* the owner's permissions. A scope only ever narrows access; it never grants anything the owner can't already do.

- Scopes are named `resource:action`, e.g. `candidates:read`, `roles:write`.
- A key minted with **no scopes** authenticates but cannot call any scope-gated `/api/v1` endpoint.
- Calling an endpoint without its required scope returns `403` with `error: "insufficient_scope"` and `requiredScopes` / `grantedScopes` arrays so you can see exactly what's missing.

| Scope | Grants |
| --- | --- |
| `candidates:read` / `candidates:write` | Read / update candidates |
| `roles:read` / `roles:write` | Read / update roles (jobs) |
| `tests:read` / `tests:write` | Read / update tests |
| `sourcing:read` / `sourcing:write` | Read / create / update / delete potential candidates |
| `pipeline:read` | Read role step templates + candidate step progress |
| `cv-screening:read` | Read CV-screening batch status + results |

Scopes are chosen when the key is minted. The legacy endpoints outside `/api/v1` are not scope-gated — they are governed by the owner's role only.

## Expiry

Keys expire after a configurable period (default **90 days**, range 1–365). An expired key is rejected and must be replaced.

## Getting a key

API keys are minted by an administrator (there is no self-serve flow yet). To request one, [contact us](https://www.talent-ray.com/contact/) with the integration you are building and the access it needs.