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

# Invoice AI API Authentication: API Keys and Scopes

> Create Invoice AI API keys in Settings, pass them as Bearer tokens on each request, and assign scopes to restrict what each key can do.

# Authentication

The Invoice AI API uses **API keys** for authentication. Every request to a protected endpoint must include a valid key in the `Authorization` header. There are no sessions, cookies, or OAuth flows — just a long-lived secret you send with each request.

## Creating an API Key

1. Sign in to the Invoice AI dashboard.
2. Navigate to **Settings → API Keys**.
3. Click **Create key**, give it a descriptive name, and select the scopes it needs.
4. Copy the key immediately — it is shown only once.

<Warning>
  Guest accounts cannot hold API keys. If you signed in without an email
  address, add an email and password under **Settings → Account** before
  creating keys.
</Warning>

<Note>
  Treat API keys like passwords. Never commit them to source control, expose
  them in client-side JavaScript, or log them in plaintext. Rotate any key you
  suspect has been compromised from the same settings page.
</Note>

## Sending the API Key

Pass the key as a **Bearer token** in the `Authorization` request header:

```http theme={null}
Authorization: Bearer inv_live_...
```

### Example

```bash theme={null}
curl https://invoice.horizonpay.co/api/v1/invoices \
  -H "Authorization: Bearer inv_live_..."
```

All API keys begin with the prefix `inv_live_` followed by a random string. Keys are tied to a single workspace; they cannot access resources belonging to a different workspace.

## Scopes

When you create a key, you choose which scopes to grant. A key can only perform operations covered by its assigned scopes — requests that require a scope the key lacks return `403 Forbidden`.

Granting the narrowest set of scopes your integration actually uses is good practice: if a key is leaked, the blast radius is limited.

| Scope               | What it allows                                             |
| ------------------- | ---------------------------------------------------------- |
| `business:read`     | Read your business profile, tax ID, and bank details       |
| `clients:read`      | List and retrieve clients                                  |
| `clients:write`     | Create, update, and archive clients                        |
| `products:read`     | List and retrieve products and prices                      |
| `products:write`    | Create, update, and archive products and prices            |
| `invoices:read`     | List and retrieve invoices, including PDFs                 |
| `invoices:write`    | Create, edit, and delete invoice drafts                    |
| `invoices:finalize` | Finalize invoices (assign an invoice number) and void them |
| `invoices:send`     | Email invoices to clients                                  |
| `payments:write`    | Mark invoices as paid                                      |
| `webhooks:manage`   | Create, update, and delete webhook endpoints               |

<Tip>
  A key used only for syncing invoice data to your data warehouse needs only
  `invoices:read` and `clients:read`. A key used by a billing automation
  service that creates and finalizes invoices needs `invoices:write`,
  `invoices:finalize`, and `clients:read` (to look up customers), but not
  `webhooks:manage`.
</Tip>

### Scope inheritance

There is no inheritance between `read` and `write` scopes. A key with `invoices:write` cannot list invoices unless it also has `invoices:read`. Grant both when your integration does both.

## Authentication Errors

<ResponseField name="401 Unauthorized" type="error">
  Returned when the `Authorization` header is missing, malformed, or contains a
  key that does not exist or has been deleted. See the
  [Errors](/api-reference/errors) reference for the full response format.
</ResponseField>

<ResponseField name="403 Forbidden" type="error">
  Returned when the key is valid but lacks the scope required by the endpoint
  you called. Check the endpoint documentation for the required scope, then
  either add that scope to an existing key or create a new key with the correct
  scopes.
</ResponseField>

### Example 401 response

```json theme={null}
{
  "type": "https://invoice.horizonpay.co/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "No valid API key was provided."
}
```

### Example 403 response

```json theme={null}
{
  "type": "https://invoice.horizonpay.co/errors/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "This API key does not have the invoices:write scope."
}
```

## Key Management

| Action                   | Where                              |
| ------------------------ | ---------------------------------- |
| Create a key             | Settings → API Keys → Create key   |
| Rename a key             | Settings → API Keys → ··· → Rename |
| View last-used timestamp | Settings → API Keys list           |
| Delete (revoke) a key    | Settings → API Keys → ··· → Delete |

Deleting a key is permanent and takes effect immediately. Any in-flight request carrying that key will receive a `401` response. There is no grace period.

<Tip>
  Use distinct keys per integration environment. A key for local development,
  a key for staging, and a key for production means you can rotate or revoke
  any one of them without disrupting the others.
</Tip>
