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

# Authentication

> API keys, test and live mode, and keeping keys safe.

Every request (except `GET /v1/health`) carries a secret API key as a bearer token:

```bash theme={null}
curl https://api.fastcac.com/v1/ping -H "Authorization: Bearer fc_test_..."
```

The base URL is `https://api.fastcac.com/v1` in both modes.

## Test and live keys

| Prefix | Mode | What it does |
| - | - | - |
| `fc_test_` | Test | Simulated end to end: never reaches CAC, never moves money. Outcomes can be forced with [`simulate`](https://docs.fastcac.com/test-mode). |
| `fc_live_` | Live | Real registrations with CAC. `simulate` parameters are ignored. |

The key decides the mode. Responses look exactly the same in both modes and don't say which mode
they came from, so code written against a test key runs unchanged with a live key. Objects created
in one mode can't be seen from the other: a test registration id returns `404` with a live key.

Create, name, roll and revoke keys at [developers.fastcac.com](https://developers.fastcac.com).
Developers can manage test keys; live keys need an admin or owner.

## Keep keys secret

* Call the API from your server only. Requests from a browser (any request with an `Origin`
  header) are refused, so a key can't be used from front-end code even by mistake.
* Store keys in a secret manager or environment variable, never in source control.
* If a key leaks, revoke it in the dashboard. It stops working at once.

## When authentication fails

```json 401 theme={null}
{
  "error": {
    "type": "authentication_error",
    "code": "api_key_missing",
    "message": "Send your API key as `Authorization: Bearer <key>`.",
    "param": null,
    "request_id": "req_ikijCXuFkXM77TyIeNynDZAn"
  }
}
```

| `code` | Meaning |
| - | - |
| `api_key_missing` (401) | No `Authorization: Bearer` header. |
| `invalid_api_key` (401) | The key is malformed, unknown, revoked or expired. |
| `too_many_failed_attempts` (429) | Too many failed attempts from your IP address in the last minute. |
| `browser_requests_not_allowed` (400) | The request came from a browser. Call the API from your server. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.