# Authentication

> Authenticate every request with a secret API key in the Authorization header. The key prefix selects sandbox or live.

Speedmap uses bearer authentication. Send your secret key in the `Authorization` header on every request to `/v1` and `/mcp`:

```http
Authorization: Bearer sk_test_...
```

_cURL_

```bash
curl "http://localhost:4000/v1/products" \
  -H "Authorization: Bearer sk_test_..."
```

_Node.js_

```javascript
const res = await fetch("http://localhost:4000/v1/products", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.SPEEDMAP_API_KEY}`,
  },
});

const products = await res.json();
if (!res.ok) throw new Error(products.error.message);
console.log(products);
```

_Python_

```python
import os, requests

res = requests.get(
    "http://localhost:4000/v1/products",
    headers={
        "Authorization": f"Bearer {os.environ['SPEEDMAP_API_KEY']}",
    },
    timeout=30,
)
res.raise_for_status()
print(res.json())
```

## Sandbox and live keys

There is one base URL, `http://localhost:4000`. The key decides which environment answers:

| Prefix | Mode | Data | Billing |
| --- | --- | --- | --- |
| `sk_test_` | Sandbox | Deterministic [test data](https://speedmap-delta.vercel.app/docs/sandbox). Nothing reaches NIMC or NIBSS. | Free |
| `sk_live_` | Live | Real NIMC, NIBSS and CAC records. | Charged to your prepaid wallet per completed check |

Sandbox and live are fully separate: verifications, consents, bulk jobs and webhook endpoints created with one mode are invisible to the other. Every response carries `mode` so you can assert you are in the environment you expect.

## Getting live access

Every new account starts in test mode (sandbox). To receive `sk_live_` keys, complete the compliance review from the dashboard (business details, intended use and data protection contact); Speedily switches your workspace to live once it is approved. Until it is approved:

- creating a live key fails with `403 live_access_required`;
- products marked **Preview** (passport, driver's licence, voter's card) stay sandbox-only and return `403 product_not_live` in live mode, whatever your status.

Live checks also need wallet balance: when the balance is lower than the check price the request fails with `402 insufficient_balance`.

## Key hygiene

- **Keys are shown once.** The full secret is displayed only when you create it. Speedmap stores a hash and cannot recover it; if you lose a key, create a new one.
- **Server-side only.** Never ship a secret key in a mobile app, browser bundle or public repository. Call Speedmap from your backend.
- **One key per service.** Create separate keys for each service and environment so you can revoke one without touching the others.
- **Revoke immediately on exposure.** Revoke a key from **Dashboard → API keys**. Revocation takes effect on the next request, which then fails with `401 unauthorized`.
- **Keep keys out of AI tools you do not control.** The [MCP server](https://speedmap-delta.vercel.app/docs/mcp) accepts the same keys; prefer a dedicated sandbox key while you evaluate it.

## Errors

A missing, malformed or revoked key returns `401`:

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key. Send Authorization: Bearer sk_test_... or sk_live_..."
  }
}
```

A valid key that cannot perform the action returns `403` with one of `not_entitled`, `live_access_required`, `product_not_live`, `account_suspended` or `sandbox_only`. See [Errors](https://speedmap-delta.vercel.app/docs/errors).

## Rate limits

Each key has a per-minute request budget shared by `/v1` and `/mcp`. Responses include `RateLimit-Limit` and `RateLimit-Remaining` headers. Past the limit, requests fail with `429 rate_limited` and a `Retry-After` header in seconds.

---

Source: https://speedmap-delta.vercel.app/docs/authentication
