Authentication
Authenticate every data request with an API key.
All data endpoints require an API key. Create and manage keys in the dashboard.
Sending your key
Two equivalent options — pick one:
curl "https://api.extractr.dev/ra/search?q=berlin" \
-H "X-API-Key: ext_live_YOUR_KEY"Key format
Secret keys look like:
ext_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0- The
ext_live_prefix is followed by 40 hex characters. - The full secret is returned exactly once, when the key is created. Only a display prefix (e.g.
ext_live_a1b2) is stored — if you lose the secret, create a new key.
Revoking and rotating
Revoke a key any time from the dashboard; it stops working immediately. To rotate without downtime:
- Create a new key.
- Deploy the new key to your services.
- Revoke the old key.
Billing is per account rather than per key, so you can freely create one key per service or environment.
Keep keys server-side
Never ship an API key in client-side code. Anyone with the key can spend your credits. Proxy extractr calls through your backend.
Key scopes
By default a key can call every provider, including ones added after it was created. You can instead restrict a key to named providers — useful when a key goes somewhere you control less tightly, such as an AI agent over MCP or a service that only needs one data source.
Set scopes when creating a key, or edit them later from API Keys → Edit name & access. Changing scopes does not change the secret, so you can tighten a key's reach without redeploying it.
A request from a key whose scopes exclude the provider is rejected with 403 insufficient_scope before any credit is reserved, so it costs nothing:
{
"error": {
"code": "insufficient_scope",
"message": "This API key is not permitted to call the instagram provider."
}
}Scoping is a blast-radius control, not a security boundary between your own services — every key still bills to the same account and shares the same balance.
Rate limits
Every provider enforces a per-key request ceiling, and providers backed by a scarce upstream resource (currently Instagram) set tighter limits plus an account-independent cap protecting the shared pool. Normal integrations sit well below these.
Exceeding a limit returns 429 rate_limited with a Retry-After header, and
costs no credits. X-RateLimit-Limit and X-RateLimit-Remaining accompany the
rejection.
Failure modes
| Situation | Status | Code |
|---|---|---|
| No key supplied | 401 | unauthorized |
| Key malformed, revoked or unknown | 401 | invalid_api_key |
| Key not scoped for the provider | 403 | insufficient_scope |
| Too many requests | 429 | rate_limited |
See Errors for the response shape.