Authentication
API keys, the two environments, and where the key goes.
Every request carries a key. Create and revoke them in the dashboard; the secret is shown once, at creation, and stored hashed after that. If you lose it, make a new one.
Sending the key
Authorization: Bearer tf_live_xxxxxxxxxxxxxxxx
X-Api-Key works too, with the same value and no Bearer
prefix. It is accepted because half the world sends that header, not because it is
preferred.
X-Api-Key: tf_live_xxxxxxxxxxxxxxxx
Two environments, one in the key
| Prefix | Costs | Rate limit | For |
|---|---|---|---|
tf_test_… | Nothing | 60 req/min | Wiring up an integration |
tf_live_… | Credits | 600 req/min | Production |
A test key runs every free check and returns the same answer shape, and it is not billed. Somebody building an integration should not be able to spend their month on it before going live, and a tenth of the rate limit means a runaway loop hits a wall early and cheaply rather than in production.
A test key never reaches the model. Sent with "ai": true,
the answer comes from the free checks and says so:
"model": {"asked": true, "read": false, "why": "test_key"}. To see what the
model says, use a live key: the free plan's credits are there for exactly that.
The environment is in the key, which is deliberate: a test key pasted into production config fails loudly instead of quietly billing nothing and letting bad content through unnoticed.
Server side only
Never put a key in a browser, a mobile app, or anything else you ship. A key in client code is a key anyone can read and spend. Call this API from your server.
Rate limits are counted per key, not per IP. Every call from one customer arrives from the same handful of addresses, so an IP limit either throttles a whole customer at once or is set so high it stops nobody. The key is who is paying, so the key is what gets counted.
Requests with no key at all are limited to 20 per minute by IP, and answered with a 401.