Errors
Branch on the status code. The body of an error is never JSON.
The API is static files behind a CDN, so an error response comes from the edge, not from an application. The status codes are exact and are what to branch on. The bodies are the CDN's own pages (HTML, or a line of plain text) and none of them is JSON: calling .json() on a failed response throws. Check response.ok first.
Browser · handle a response
const response = await fetch(url);
if (response.status === 404) return null; // no such object
if (response.status === 429) { await sleep(10_000); return retry(); }
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json(); // only nowStatus codes
| Status | When | What to do |
|---|---|---|
200 | The file exists. | Parse it. |
302 | You asked through the /v3/ alias; the Location header names the same path under the newest release. | Follow it. Browsers and fetch do; curl needs --location. |
304 | You sent If-None-Match and the file has not changed. | Use your cached copy. |
403 | Two cases: the request carried no User-Agent at all, or it used a method other than GET, HEAD or OPTIONS. | Send a User-Agent naming your project and a contact, and only read. There is no write API and no credential that would enable one. |
404 | No file at that path: an ID that does not exist, a slug never issued, a typo, or a path outside any release folder. | Check the ID against an index or versions.json. Under a pinned release a 404 is permanent; under /v3/ a later release may add the file. The body is a 27 KB HTML page, so do not read it. |
429 | More than 30 requests in 10 seconds from your IP address. | Wait 10 seconds. Then fetch registry.json or an index once instead of the objects one by one. |
5xx | The storage or the edge is having trouble. | Retry with backoff. Every release is also on GitHub, and a pinned release's bytes never change, so a copy you already hold stays valid. |
Details worth knowing
- A write is refused with
403, not405, and carries noAllowheader. That is a limit of the edge's plan, not a statement about your request. The methods that work areGET,HEADandOPTIONS. - A
404carriesAccess-Control-Allow-Origin: *, so page JavaScript sees the status. A403from the edge does not, so in a browser it surfaces as a network error instead. Browsers always send aUser-Agentand cannot write, so this only affects non-browser clients, which can read the status directly. CORS and browsers has more. GET https://api.kairosarchive.net/redirects toversions.json, which is where a client should start anyway.
If you were blocked and believe you should not have been, open an issue with your User-Agent and the time.
Reference: registry API contract and published object definitions. Report a data or documentation issue.