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

# Authentication

> Use bisibility API keys with bearer authentication.

Protected API routes require an API key in the `Authorization` header:

```text theme={null}
Authorization: Bearer bsk_live_...
```

The router accepts a single bearer token. Missing, malformed, revoked, or invalid
keys return `401 Unauthorized` with an `application/problem+json` body.

## Create API keys

Create the first API key from the app's settings area. After that, an existing
admin-capable key can create more keys through the REST API:

```bash theme={null}
curl "$BISIBILITY_BASE_URL/api-keys" \
  -X POST \
  -H "Authorization: Bearer $BISIBILITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "reporting job" }'
```

The raw `token` is returned only when the key is created:

```json theme={null}
{
  "id": "key_abc123",
  "name": "reporting job",
  "prefix": "bsk_live_xxxxxxxx",
  "masked_value": "bsk_live_xxxxxxxx******abcd",
  "token": "bsk_live_...",
  "created_at": "2026-06-28T10:00:00.000Z",
  "last_used_at": null,
  "revoked_at": null
}
```

Store the raw token outside bisibility. The API stores a hash and cannot show it
again.

## Scopes

The router enforces these scope classes:

| Scope   | Allows                                    |
| ------- | ----------------------------------------- |
| `read`  | `GET` requests on protected resources.    |
| `write` | Mutating keyword and rank-check requests. |
| `admin` | API-key management.                       |

Current API keys authenticate with `read`, `write`, and `admin`. The public REST
API does not currently expose a request field for limiting a new key to a subset
of scopes.

## Project scoping

An API key belongs to one project. `GET /projects` returns that project. Routes
that include `{project_id}` accept either the internal project id or the public
`prj_...` id, but the authenticated key must belong to that project.

## Rate limits

Every request includes rate-limit headers:

```text theme={null}
RateLimit-Limit: 600
RateLimit-Remaining: 599
RateLimit-Reset: 60
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 60
```

Defaults:

| Identity                    |                 Default |
| --------------------------- | ----------------------: |
| API key                     | 600 requests per minute |
| Personal access token       | 120 requests per minute |
| Anonymous discovery request |  60 requests per minute |

Set `BISIBILITY_API_KEY_RATE_LIMIT_PER_MINUTE` and
`BISIBILITY_PAT_RATE_LIMIT_PER_MINUTE` or
`BISIBILITY_API_ANON_RATE_LIMIT_PER_MINUTE` to change them. When a limit is
exceeded, the API returns `429` and includes `Retry-After`.

## Idempotency

All non-GET routes accept:

```text theme={null}
Idempotency-Key: unique-operation-id
```

The idempotency cache key is the API key id, HTTP method, pathname, and
idempotency key. Replayed responses include:

```text theme={null}
Idempotency-Replayed: true
```

When Redis or Valkey is configured, idempotency responses are stored there with a
24-hour TTL so replays survive restarts and span app instances. The in-process
Map is only a local-development and test fallback.
