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

# Authentication

> Create Developer API keys and authenticate public API requests with Bearer tokens.

# Authentication

Public API requests use Developer API keys.

## Create an API key

Create an API key from **Developer API** in the user menu. The full key is shown only once. Store it like a password.

API keys use this shape:

```text theme={null}
subm_<public-id>.<secret>
```

Only the SHA-256 hash of the full API key is stored on the server.

## Send the key

Send the key as a Bearer token:

```bash theme={null}
curl \
  -H "Authorization: Bearer $SUBSCRIPTION_MANAGER_API_KEY" \
  https://your-site.example/api/v1/subscriptions
```

## Scopes

Each API key carries scopes that bound what it can do:

| Scope   | Allows                                                                           |
| ------- | -------------------------------------------------------------------------------- |
| `read`  | List and read subscriptions; call the analytics and audit endpoints              |
| `write` | Everything `read` allows, plus create, update, cancel, pause, resume, and delete |

`read` is always present. By default a new key is granted both `read` and `write`. To create a read-only key — useful for analysis agents that should never modify data — pass a `scopes` array when creating the key:

```json theme={null}
{ "name": "Analysis agent", "scopes": ["read"] }
```

A write operation attempted with a read-only key returns `403 insufficient_scope`. The created key object includes its `scopes`.

## Failed authentication limits

Invalid API key attempts are rate-limited per client identity. The default limit is:

```text theme={null}
300 failed authentication attempts per hour
```

Set `API_FAILED_AUTH_RATE_LIMIT_PER_HOUR` to override the default.

## Security notes

* Do not expose API keys in browser code.
* Treat API keys like passwords.
* Revoke keys that are no longer needed.
* Use one key per integration where possible.
* Rotate keys if a secret may have been copied into logs or prompts.
