# Authentication and keys

> Authenticate with bearer API keys. Live and test keys, what test mode returns, revoking a key and setting a monthly spend limit per key.

Source: https://fileverity.com/en/docs/authentication

Every request needs an API key, sent as a bearer token in the `Authorization` header.

**Authenticated request: cURL**

```bash
curl https://api.fileverity.com/v1/models \
  -H "Authorization: Bearer $FILEVERITY_API_KEY"
```

**Authenticated request: JavaScript**

```javascript
const response = await fetch("https://api.fileverity.com/v1/models", {
  headers: { Authorization: "Bearer " + process.env.FILEVERITY_API_KEY },
});
```

**Authenticated request: Python**

```python
import os
import requests

requests.get("https://api.fileverity.com/v1/models", headers={"Authorization": "Bearer " + os.environ["FILEVERITY_API_KEY"]})
```

Keys are secrets. Call the API from your server, store keys in environment variables or a secrets manager, and never put them in browser code or mobile apps.

## Live and test keys

A key is `fv_live_` or `fv_test_` followed by 40 letters and digits. The prefix sets the mode.

|  | Live key | Test key |
| --- | --- | --- |
| Prefix | `fv_live_...` | `fv_test_...` |
| Runs the models | Yes | No |
| Charged to your balance or free start | Yes | Never |
| Results | Real | Fixed samples |
| `livemode` in responses | `true` | `false` |
| Webhooks | Sent | Not sent |

Both modes share one workspace. They use the same endpoints, validation, rate limits and error codes, so you can build against a test key and switch keys to go live.

## Test mode behavior

- **Text detections.** The request is validated like a live request: minimum length, maximum length and language checks still apply. The response is a fixed `human` result with `score` and `ai_fraction` of `0` and no `segments`. `usage` is computed from your text. Nothing is charged or recorded.
- **Files.** Uploads are validated, but the bytes are not stored, and a JSON upload request returns a test upload object instead of a real pre-signed URL (`upload.test` is `true`) with the file already `uploaded`. Files are separated by mode: a test key cannot read live files, and a live key cannot read test files.
- **Create an analysis.** Returns `200` immediately with `status: succeeded`, a fixed sample with level `L2` and action `accept`, and `livemode: false`. The analysis ID starts with `an_test` and is the same for the same file. The report ID starts with `FV-TEST-` and has no public verification page. The sample report contains only the fields in the sample.
- **Retrieve an analysis.** Works for sample analysis IDs only. **List analyses** always returns an empty list, **cancel** returns `not_cancelable`, and there is no sample PDF. Test keys cannot read live analyses or live report PDFs.

**Sample text detection, test key**

```json
{
  "id": "tdet_Qm4vB7nP1sK8tL3wR6yZ2cXa",
  "object": "text.detection",
  "created": 1793664000,
  "model": "fvdoc-3-text-2026-11-03",
  "livemode": false,
  "language": "en",
  "verdict": "human",
  "score": 0,
  "ai_fraction": 0,
  "segments": [],
  "usage": {
    "characters": 1412,
    "free_characters": 0,
    "billed_units": 2
  }
}
```

## Create and revoke keys

Manage keys in the Console under **API keys**.

- **Create.** Name the key and choose its mode. The full key is shown once. Fileverity stores only a SHA-256 hash and the last four characters, so a lost key cannot be recovered; create a new one.
- **Limit.** A workspace can hold up to 20 active keys. Beyond that, creating a key fails with `key_limit`.
- **Last used.** The Console shows when each key last made a request.
- **Revoke.** Requests that use a revoked key fail immediately with `invalid_api_key`.
- **Members who leave.** When a member leaves the workspace or is removed, the keys they created are revoked. Create production keys from an account that stays with the workspace.

### If a key leaks

1. Create a new key.
2. Update your software to use it.
3. Revoke the old key.

## Monthly spend limits

Each key can have its own monthly spend limit, in whole US dollars. Only workspace owners and admins can set or change it, when you create the key or later with **Edit limit**. A key with no limit is bounded only by your balance.

- The limit counts what the key has spent in the current calendar month in UTC and resets on the 1st.
- A request that would take the key over its limit is rejected with `spend_limit_reached` (HTTP 402) before any work starts, and is not charged.
- Free-start checks cost nothing and do not count. Failed and canceled checks are not charged and do not count.
- Limits apply to live keys. Test keys never spend.

> **Note.** Use a separate key, with its own limit, for each service or environment. A runaway job then cannot spend more than that key's limit.

## Authentication errors

| Code | Status | Meaning |
| --- | --- | --- |
| `missing_api_key` | 401 | No `Authorization: Bearer` header was sent. |
| `invalid_api_key` | 401 | The key is malformed, unknown or revoked. |
| `spend_limit_reached` | 402 | The key reached its monthly spend limit. |

See [Errors](https://fileverity.com/en/docs/errors.md) for the full list.

