Skip to content
unzoi docs

Authentication

One key, two headers that both work, and the same rules on REST and MCP.

The header

Either of these authenticates a request. They are equivalent; pick whichever your HTTP client makes easier.

x-api-key: nai_...
Authorization: Bearer nai_...

The same two work on https://api.unzoi.com/mcp. MCP clients that let you set arbitrary headers usually use x-api-key; ones that only offer a bearer field use Authorization.

curl -s "https://api.unzoi.com/search?q=inflation" -H "x-api-key: $UNZOI_KEY"
curl -s "https://api.unzoi.com/search?q=inflation" -H "Authorization: Bearer $UNZOI_KEY"

What does not need a key

Four endpoints are public, deliberately. An agent deciding whether this API is worth signing up for has to be able to read what it does before it has a key:

Everything else answers 401 without a key.

Handling keys

A key is shown once, at creation. Only its hash is stored, so a lost key is rotated, not recovered — rotation issues the new key before revoking the old one, so there is no window where neither works.

  • Never put a key in a browser. There is no CORS-credentialed mode and no per-origin restriction: a key in front-end JavaScript is a key anyone can read and spend. Proxy through your own server.
  • One key per deployment, not per developer. Every key on a tenant shares the plan, quota and rate limit, so separate keys buy you revocation granularity and usage attribution, not separate budgets.
  • Short-lived keys exist. The console can issue a key with a TTL of up to 24 hours — useful for a demo, a CI run, or handing an agent a credential you do not intend it to keep.

How a request is refused

Four things can turn a request away, and they mean different things.

Status Meaning
200 Success
401 Missing or invalid API key
402 Account suspended (subscription canceled or payment failed)
429 Rate limit exceeded, or the monthly quota is exhausted on a key that stops at its quota rather than billing overage. `retry-after` says how long to wait.

Order matters: the key is checked first, then suspension, then the per-minute rate, then the monthly quota. A 429 therefore never means "your key is wrong", and a 401 never means "you are over budget".

On MCP, two of these move

An MCP client that receives an HTTP error status for a tool call concludes the server has gone away, and stops. That is the correct reading for a missing key — a client with no credential cannot open a session at all — but it is the wrong reading for an account that simply needs paying.

So the MCP endpoint splits them:

Condition REST MCP
Missing or invalid key 401 401 — the session never opens
Rate limit exceeded 429 + retry-after 429 + retry-after — transient, retry the same call
Account suspended 402 A tool error on an open session
Monthly quota exhausted 429 A tool error on an open session

In the last two cases initialize and tools/list still succeed, and the refusal arrives on the call that actually costs something, carrying a machine-readable code the agent can act on. MCP errors shows the exact shape.

What every response tells you

Authenticated responses carry your standing as headers, so backing off correctly never needs a second request.

Header Meaning
x-plan-history-days How far back this plan may query. Absent means the full archive.
x-quota-limit Included requests this calendar month. Absent when unlimited.
x-quota-remaining Requests left in the monthly allowance.
x-quota-reset Seconds until the quota period resets.
x-quota-used Requests used this month, from the durable counters.
x-ratelimit-limit Requests per minute allowed by this plan.
x-ratelimit-remaining Requests left in the current minute.
x-ratelimit-reset Seconds the bucket refills over.

Limits and plans covers what to do with each of them, and GET /account returns the same figures as a body.

Keys are issued and revoked at console.unzoi.com.