Authentication
Most fetch.li endpoints are public GET requests on the demo tier and do not need a key. The POST /v1/vibe/classify endpoint always requires a valid API key. Humans can sign in with email and later connect Google, GitHub, or X. That session is not an API key. See Login.
Plain English summary
An API key proves you are allowed to use paid features (vibe classification) and, on production plans, may unlock higher rate limits. You send the key in a standard HTTP header called Authorization. fetch.li checks the key with Unkey on every protected request before running your job.
Who needs a key
| Endpoint type | Key required? |
|---|---|
All GET endpoints (/v1/moon, /v1/vat, and so on) |
No (demo tier: 60 calls/hour per IP) |
POST /v1/vibe/classify |
Yes, always |
How to send your key
Use the Bearer scheme. The header must look exactly like this (one space after Bearer):
Authorization: Bearer ukdev_live_abc123xyz789
curl
curl -sS https://fetch.li/v1/vibe/classify \
-H "Authorization: Bearer ukdev_live_abc123xyz789" \
-H "Content-Type: application/json" \
-d '{"texts":["Your sample copy here."]}'
JavaScript (Node.js or server-side only)
const response = await fetch("https://fetch.li/v1/vibe/classify", {
method: "POST",
headers: {
Authorization: "Bearer ukdev_live_abc123xyz789",
"Content-Type": "application/json",
},
body: JSON.stringify({ texts: ["Your sample copy here."] }),
});
const data = await response.json();
console.log(data);
Python
import requests
response = requests.post(
"https://fetch.li/v1/vibe/classify",
headers={
"Authorization": "Bearer ukdev_live_abc123xyz789",
"Content-Type": "application/json",
},
json={"texts": ["Your sample copy here."]},
)
print(response.json())
Unkey and what gets verified
fetch.li uses Unkey to issue and verify customer keys. When you send Authorization: Bearer <token>, the API calls Unkey’s verify endpoint. If the key is valid, active, and permitted for this product, the request proceeds.
You receive a customer API key after purchase. That is the token you send in Authorization.
You do not send:
- Your Unkey root key
- Your Anthropic or other upstream provider keys
- Keys embedded in public web pages
Optional deployment settings (UNKEY_API_ID, permissions) can restrict keys to fetch.li only. That is configured on the server, not in your client code.
Security rules (read this)
- Never commit keys to Git. Use environment variables (
.envlocally, secrets manager in production). - Never put keys in frontend repos. Browser JavaScript, React apps, mobile apps shipped to users, and public GitHub repos are not safe places for secrets. Anyone can extract them.
- Call protected endpoints from your server. Your backend holds the key and forwards results to the client if needed.
- Revoke if leaked. Kill the key on the account page, then request a replacement from pricing. Update your environment variables.
Good pattern
User browser → Your server (has UKDEV_API_KEY) → fetch.li
Bad pattern
User browser (key visible in DevTools) → fetch.li
Error responses for auth problems
All errors use the same JSON shape:
{
"error": {
"code": "unauthorized",
"message": "Send Authorization: Bearer <token> with a valid fetch.li API key."
}
}
| HTTP status | error.code |
Typical cause |
|---|---|---|
| 401 | unauthorized |
Missing header, malformed Bearer token, or invalid/expired key |
| 403 | forbidden |
Key valid but lacks permission for this product |
| 429 | rate_limited |
Key hit Unkey usage or rate limits (reason may be RATE_LIMITED or USAGE_EXCEEDED) |
| 503 | unkey_unavailable |
Key verification service temporarily down; retry with backoff |
Example with reason:
{
"error": {
"code": "rate_limited",
"message": "API key was rejected.",
"reason": "USAGE_EXCEEDED"
}
}
Request IDs
Every response includes X-Request-Id (a unique ID for that request). When contacting support about auth failures, include that header value and the approximate time of the call.
Related pages
- Demo tier for key-free GET usage
- Vibe classify for the protected endpoint
- Errors guide for handling failures in your app