# Authentication

> Send the app's REST API key in a header. Keys are per app, shown once, can be locked to IP addresses, and can be revoked.

URL: https://docs.xulo.io/api/authentication

## Get a key

In the dashboard, open the app's **Settings → Keys & IDs** and create a REST key. Give it a name and, if you want, the IP addresses allowed to use it.

The key starts with `xulo_`. It is shown once, when you create it. Store it on your server, for example as `XULO_REST_KEY`. It must never ship inside an app.

## Send the key

Any one of these headers works:

```http
Authorization: Key xulo_...
Authorization: Bearer xulo_...
X-Xulo-Key: xulo_...
```

A key in the query string is not accepted. The call returns 401.

## One key, one app

A key belongs to one app.

- The body's `app_id` must be that app's App ID. Another app's id returns 404.
- If the body has a `bundle_id`, it must be that app's bundle id. Another bundle id returns 404.
- `GET /api/v1/notifications/{id}` with another app's send returns 404.

An organization key that starts with `perk_` is not a REST key and returns 401. So does the App ID.

## IP lock

A key can be locked to IP addresses or ranges, such as `203.0.113.7` or `203.0.113.0/24`. Set them when you create the key, or later under **IP lock**.

- With no addresses set, every address is allowed.
- With addresses set, a call from anywhere else returns 403, and the key's last use is not updated.

## Revoke

Revoke a key in **Settings → Keys & IDs**. A revoked key returns 401.

## Errors

| Status | Body | When |
| --- | --- | --- |
| 401 | `{"message":"Missing REST API key."}` | No key in a header. |
| 401 | `{"message":"Invalid REST API key."}` | The key is wrong or revoked. |
| 403 | `{"message":"This REST key is locked to other IP addresses."}` | The IP lock refused the address. |

See [Errors](https://docs.xulo.io/api/errors) for the rest.
