# https://compresr.ai/docs/authentication

> Human-readable page: https://compresr.ai/docs/authentication

Every request needs an API key.

Create a key in the [dashboard](/dashboard/api-keys). Copy it right away: you only see the full value once. All keys start with `cmp_`.

Send the key in the `X-API-Key` header on every request.

## Where to put the key

Store your key in the `COMPRESR_API_KEY` environment variable. The SDKs read it for you. With cURL, pass it as a header on each call.

```python
import os
from compresr import CompressionClient

client = CompressionClient(api_key=os.environ["COMPRESR_API_KEY"])
```

**TypeScript**

```typescript
import { CompressionClient } from '@compresr/sdk';

const apiKey = process.env.COMPRESR_API_KEY;
if (!apiKey) {
  throw new Error('COMPRESR_API_KEY is not set');
}

const client = new CompressionClient({ apiKey });
```

**cURL**

```bash
export COMPRESR_API_KEY="cmp_your_api_key"

curl -X POST https://api.compresr.ai/api/compress/question-specific/ \
  -H "X-API-Key: $COMPRESR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "context": "...",
    "query": "...",
    "compression_model_name": "{{DEFAULT_MODEL}}"
  }'
```

The SDKs set the `X-API-Key` header for you on every request. You only attach it by hand when calling the REST API directly.

## Credential resolution

Both SDKs walk a fallback chain and use the first hit.

**Python** — `explicit api_key=` → `COMPRESR_API_KEY` env → INI file at `~/.compresr/credentials`. The INI profile is selected via `COMPRESR_PROFILE` (defaults to `default`).

**TypeScript** — `explicit apiKey` → `process.env.COMPRESR_API_KEY`. File-based pickup is opt-in: `import { createClient } from '@compresr/sdk/auth'`. That helper reads JSON at `~/.compresr/credentials.json`.

Format asymmetry is intentional: Python uses INI at `~/.compresr/credentials` (no extension), TS uses JSON at `~/.compresr/credentials.json`. Different files, different formats — do not share or symlink them.

## CLI: compresr-sdk login / logout

Both SDKs ship a `compresr-sdk` binary.

- `compresr-sdk login` opens a browser flow and writes credentials to the local file (INI for Python, JSON for TS).
- `compresr-sdk logout` clears the local file **and** best-effort revokes the key server-side via `POST /api/authorize/logout`.

Deleting `~/.compresr/credentials` (or `credentials.json`) by hand only removes the local copy — the key stays `ACTIVE` server-side. Use `compresr-sdk logout` to revoke it.

## Base URL and insecure transport

Python reads `COMPRESR_BASE_URL` as a fallback. TypeScript does **not** — TS users must pass `baseUrl` explicitly to the client constructor.

Both SDKs refuse to start against a non-HTTPS `base_url` and raise `CompresrError(code="insecure_base_url")`. Set `COMPRESR_ALLOW_INSECURE=1` to override. Loopback hosts (`localhost`, `127.0.0.1`) are exempt from the check.

## Key format

Every Compresr key starts with `cmp_`. Treat the full string as a secret - it is not recoverable, so if you lose it, revoke the old key and create a new one.

The SDKs validate the `cmp_` prefix client-side before any HTTP call: Python raises `AuthenticationError` ("Invalid API key format. Keys must start with 'cmp_'"), TS throws the same. A present-but-invalid key that reaches the server returns `401 Unauthorized`.

Requests with a valid key but an exhausted budget return `402 Payment Required`. Requests with a wrong-scope key (e.g. a demo key on a paid endpoint) return `403` with `code: 'scope_error'` (`ScopeError` in the SDKs).

Omitting the `X-API-Key` header entirely returns `422` with FastAPI's default envelope (`{"detail":[...]}`), not the standard error envelope. Only a present-but-invalid key returns `401` with the documented envelope shape.

## Best practices

- **Use environment variables.** Read keys from `COMPRESR_API_KEY` in every environment - local, CI, staging, production.
- **Never commit keys.** Add `.env` to `.gitignore`. Use a secret manager (1Password, Vault, AWS Secrets Manager, etc.) for production.
- **Server-side only.** Never embed a key in a browser bundle, mobile app, or any client-side code. The browser will leak it.
- **Rotate regularly.** Rotate every 90 days, and immediately if a key may have been exposed.
- **Set a budget.** Cap each key's monthly spend in the [dashboard](/dashboard/api-keys) so a leak or runaway loop cannot drain your account.

## Rotating a key

Create a new key in the dashboard and deploy it to your environments. Once you have confirmed traffic is flowing on the new key, delete the old one. Keys are revoked immediately on deletion - there is no grace period.

## Budgets and expiry

Each key can carry a monthly budget cap and an optional expiry date, both set at creation in the [dashboard](/dashboard/api-keys). When the budget is exhausted, further requests with that key return `402 Payment Required` until the next billing cycle or until you raise the cap. Expired keys return `401 Unauthorized` after their expiry timestamp.

> **Never expose your API key in client-side code**
> Compresr keys should only be used server-side. Anyone with your `cmp_` key can spend against your account until you revoke it. Keep keys in a secret manager - not in shared docs, chat threads, frontend bundles, or mobile apps.
