Authentication
Bearer keys, how they're issued, per-key rate limits, and why there's no CORS support.
Bearer keys
Every request to POST /v1/compress needs an Authorization header:
Authorization: Bearer ikb_live_…
GET /v1/health is the one route that needs no key — it’s a liveness check, and it’s meant to be
pollable by anything (uptime monitors included) with no credential to manage.
A missing header, a malformed header, or a key that doesn’t match anything on file all come back
as the same 401 unauthorized — this endpoint never distinguishes “you sent no key” from “you sent
the wrong key” in its response, so a stranger probing for valid keys learns nothing from the
difference.
How a key is issued
Keys are issued manually, out of band — there is no self-serve signup endpoint. Email privacy@imagekbreducer.com to ask for one. What gets stored against your key is exactly three fields: a name, a creation timestamp, and the key’s own SHA-256 hash — never the key itself in plaintext, and nothing about any request you make with it. See Privacy for the full accounting.
Treat a key like any other bearer credential: don’t commit it, don’t embed it in a browser
bundle, and don’t put it anywhere a request’s Authorization header could be read by someone
other than your own backend.
Per-key rate limit
Each key is limited to 10 requests per 60 seconds, counted per key — not globally, so one key
being throttled never affects another. The counter for a key lives in its own Durable Object,
keyed by that key’s hash, which is what makes “per key” structural rather than a convention: two
keys cannot reach the same counter. A request over the limit gets 429 rate-limited with a
Retry-After header carrying the seconds left in that key’s current window. Rate limiting happens
before Content-Length checking or any parsing of the request body: a throttled key pays nothing for
a request beyond the auth check itself.
The window is a fixed 60 seconds, not a sliding one, so a caller who spends their whole allowance at the end of one window and again at the start of the next can briefly exceed the nominal rate across that boundary.
If the limiter itself is unreachable, requests are refused, not waved through: you get
503 rate-limiter-unavailable with Retry-After: 60. Failing closed is deliberate — an outage in
the only per-key cost control must not become an unmetered API.
Why there’s no CORS support
This API sends no Access-Control-* header on any response, on any route, ever — not even a
permissive one on OPTIONS /v1/compress, which answers 204 Allow: POST and stops there. That
OPTIONS response is not a CORS preflight response; there is no CORS support anywhere in this
Worker for it to be a preflight response for. It’s the same status a browser preflight would
see, but it carries none of what a preflight needs to actually authorize a cross-origin request,
so a browser calling this API directly will always fail with a CORS error, on every browser.
This is deliberate, not an oversight: this is a server-to-server API, meant to be called from your own backend, where your key stays out of anything a page visitor’s browser can inspect. A page in a browser embedding a bearer key to call this API directly is exactly the failure mode this design refuses to make possible — see the Limits page’s framing of the whole endpoint as “refuse before spending,” of which this is one instance.