> ## Documentation Index
> Fetch the complete documentation index at: https://docs.saasybill.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Authenticate with API keys, and limit each key to the scopes it needs

The API uses bearer API keys. Each key belongs to one organisation and carries a set of scopes that decide what it can do.

```text theme={null}
Authorization: Bearer saasybill_live_…
```

A request without a valid key answers `401`. A request whose key lacks the scope for the endpoint answers `403`.

***

## API keys

A key is the prefix `saasybill_live_` followed by 43 random characters.

```text theme={null}
saasybill_live_x3F9k2Lm8QpR4vTn7YbZ1cWdAe5GhJuI6oXsN0MqPyK
```

The prefix tells a person, and a secret scanner, what the string is. If a key ends up in a public repository, the scanner can find it.

<Warning>
  Treat a key like a password. It can create subscriptions and read customer data. Never put it in browser code, a mobile app or a repository. Keep it on your server, in an environment variable or a secrets manager.
</Warning>

### Create an API key

Only an owner or admin can create, view or revoke keys.

<Steps>
  <Step title="Open Developer Settings">
    Go to **Organisation Settings**, then **Developer Settings**, then **API Keys**.
  </Step>

  <Step title="Create the key">
    Click <Badge>Create API Key</Badge> and fill in the fields.

    | Field | Description |
    | - | - |
    | **Name** | A label for you. Up to 100 characters. Use the name of the integration, such as `Signup integration`. |
    | **Permissions** | The [scopes](#scopes) the key holds. Choose only what the integration needs. |
    | **Expires** | <Badge>Never</Badge>, in 30 days, in 90 days, or in 1 year. |
  </Step>

  <Step title="Copy the key">
    Click <Badge>Create Key</Badge>, then copy the key from the **Your New API Key** dialog. It cannot be shown again. If you lose it, create a new key and revoke the old one.
  </Step>
</Steps>

An organisation can have up to 25 active keys. The list shows each key's name, its first few characters, its scopes, when it was last used, and when it expires.

### Revoke an API key

Open the key's menu and click <Badge>Revoke Key</Badge>. Anything using the key stops working straight away, and this can't be undone.

### Key status

| Status | Meaning | API answer |
| - | - | - |
| <Badge color="green">Active</Badge> | The key works. | |
| <Badge>Revoked</Badge> | Someone revoked it. | `401 api_key_revoked` |
| <Badge color="red">Expired</Badge> | It passed its expiry date. | `401 api_key_expired` |

***

## Scopes

A scope grants access to one part of the API. An endpoint names the one scope it needs.

| Scope | Label in the app | Allows |
| - | - | - |
| `customers:read` | Read Customers | [List](/api-reference/customers/list-customers) and [retrieve](/api-reference/customers/retrieve-a-customer) customers |
| `customers:write` | Create Customers | [Create customers](/api-reference/customers/create-a-customer), and Xero contacts where the organisation allows it |
| `catalogue:read` | Read Plans And Charges | List and retrieve [plans](/api-reference/plans/list-plans) and [charges](/api-reference/charges/list-charges) |
| `subscriptions:read` | Read Subscriptions | [List](/api-reference/subscriptions/list-subscriptions) and [retrieve](/api-reference/subscriptions/retrieve-a-subscription) subscriptions |
| `subscriptions:write` | Manage Subscriptions | [Create](/api-reference/subscriptions/create-a-subscription) subscriptions, [change units](/api-reference/subscriptions/change-a-subscriptions-units), [end](/api-reference/subscriptions/end-a-subscription) and [restore](/api-reference/subscriptions/restore-a-subscription) them |
| `invoices:read` | Read Invoices | [List](/api-reference/invoices/list-invoices) and [retrieve](/api-reference/invoices/retrieve-an-invoice) invoices |
| None needed | | [Retrieve the organisation](/api-reference/organisation/retrieve-the-organisation) |

A write scope does not include its read scope. A key that creates subscriptions and also needs to read them holds both `subscriptions:write` and `subscriptions:read`.

<Tip>
  Give each integration its own key with the fewest scopes it needs. A signup integration usually needs `catalogue:read`, `customers:read` and `subscriptions:write`. A reporting integration needs only read scopes.
</Tip>

When a key lacks a scope, the error names it.

```json theme={null}
{
  "error": {
    "type": "permission_error",
    "code": "insufficient_scope",
    "message": "This API key does not have the `subscriptions:write` scope.",
    "request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
  }
}
```

***

## Test keys

Keys with the prefix `saasybill_test_` exist in the format but can't be created yet. If one authenticates, the API refuses it with `403 sandbox_not_available`, so nothing runs against live data by accident.

To test an integration, use a second organisation connected to a Xero Demo Company. See [Testing](/api-reference/testing).

***

## Authentication errors

| Status | Code | Cause |
| - | - | - |
| `401` | `invalid_api_key` | The header is missing or malformed, or the key doesn't exist. |
| `401` | `api_key_revoked` | The key has been revoked. |
| `401` | `api_key_expired` | The key has expired. |
| `403` | `insufficient_scope` | The key lacks the scope the endpoint needs. |
| `403` | `sandbox_not_available` | A `saasybill_test_` key was used. |

See [Errors](/api-reference/errors) for the full list.
