---
title: "Authentication & scopes"
description: "Three interchangeable ways to present a key, the restrictions a key can carry, and the scope groups that gate each endpoint."
canonical: "https://thecarapi.com/docs/authentication"
contract_version: "2026-08-19"
api_base: "https://api.thecarapi.com"
source: "https://thecarapi.com/docs/authentication.md"
---

# Authentication & scopes

Three interchangeable ways to present a key, the restrictions a key can carry, and the scope groups that gate each endpoint.

Every documented endpoint requires an API key. Use exactly one authentication method per request — sending two is not an error, but which one wins is not something to depend on.

| Method | Header or parameter | Notes |
| --- | --- | --- |
| Header | `X-API-Key: <key>` | Recommended for server-to-server calls. |
| Bearer | `Authorization: Bearer <key>` | Equivalent to `X-API-Key`. |
| Query string | `?api_key=<key>` | Disabled by default; use only when explicitly enabled for your key. Keys in URLs end up in logs and referrers. |

```bash
# Header — the normal case
curl -H "X-API-Key: $API_KEY" "https://api.thecarapi.com/api/sites"

# Bearer — identical behaviour, useful when your HTTP layer already speaks OAuth
curl -H "Authorization: Bearer $API_KEY" "https://api.thecarapi.com/api/sites"
```

> **Never ship a full-access key to a browser or mobile app** — A key in client code is a public key, whatever the header is called. Issue a separate key with an origin allowlist and the minimum scopes, or proxy through your own backend.

## Key restrictions

| Restriction | Effect when violated |
| --- | --- |
| IP or CIDR allowlist | Requests from outside the list return `403`. |
| Origin allowlist | Browser requests from other origins return `403`. |
| Expiry date | Requests after the date return `401`. |
| Status (revoked, suspended) | All requests return `403`. |
| Scope set | Endpoints outside the set return `403 scope_denied`. |

Repeated authentication failures trigger a temporary `429` lockout on the offending source. A deploy that ships a bad key will lock itself out before you notice the `401`s, so fail fast on `401` rather than retrying.

## Published scope groups

Scopes are groups, not per-endpoint flags. Each endpoint in this reference names the scope it needs in its header row.

| Scope | Published access |
| --- | --- |
| `search` | Inventory search, filter facets (individually or combined via `/api/facets`), sources, and the full model catalog |
| `catalog` | Manufacturer and model-group catalog |
| `seo` | Popular searches and brand/model slug resolution |
| `auctions` | Auction detail, images, price history, and VIN history |
| `details` | Full vehicle details, including upstream fetches |
| `top-offers` | Auctions priced below their market reference |
| `theparking` | European classifieds feed, facets, and models |
| `market` | Cars.bg and auction market price snapshots |
| `calculator` | Import cost calculator and supported countries |
| `ops` | Service health and the API index |

> **Check scopes at startup, not per request** — A missing scope is a deployment problem, not a runtime condition. Call `/api/contract` once when your process starts and fail loudly if the surface you depend on is not there.
