Caching
Successful responses are cached for 60 seconds, on the server, per token and per URL.
This is a shared cache in front of the API, not a hint to your HTTP client. A cached response is returned without the request reaching authentication, the services, or the database.
The cache key
Two things identify a cached response:
- Your token — strictly, a hash of the
Authorizationheader. - The full request URL, including the query string.
Because the token is part of the key, responses are never shared between tokens. A request from a different project cannot be served another project’s cached data.
Because the query string is part of the key, ?page=1 and ?page=2 are separate entries — and so are ?page=1&page_size=20 and ?page_size=20&page=1, which differ as strings even though they mean the same thing.
Reading the cache status
Every response says whether it came from the cache:
HTTP/1.1 200 OKX-Localeo-Cache: hitCache-Control: public, max-age=60X-Localeo-Cache | Meaning |
|---|---|
miss | Handled normally, and the response has now been stored. |
hit | Served from the cache without touching the database. |
unreachable | Neither read from nor written to the cache. |
unreachable is the one that needs explaining, because it does not only mean
the cache is down. Only successful responses are cacheable, so every error
response reports unreachable — a 401 or a 404 is never stored, and you will
see this value on it routinely. It also appears if the cache backend is
unavailable, which is not an error either: the cache is an optimisation, and the
API deliberately keeps serving requests without it.
In short, treat unreachable as “this response did not involve the cache”, and
only hit as a guarantee that no database work happened.
Successful responses also carry Cache-Control: public, max-age=60, so your own HTTP client or CDN may cache them for the same minute.
Consequences worth knowing
A revoked token keeps working briefly
Because a cache hit never reaches authentication, deleting a token does not immediately stop responses to requests that match something already cached. The gap is bounded by the 60-second lifetime.
Fresh data can be up to a minute old
A release published seconds ago may not appear in a GET /releases response you have already made within the last minute. If you need to observe a publish immediately, vary the query string — adding an ignored parameter such as ?t=1743158400 produces a different cache key and forces a fresh read.
Use that sparingly. Every forced miss is a database query and, unlike a cache hit, it counts against your rate limit.
Cache hits are free
A cache hit is not counted against your rate limit, because the cache sits in front of the limiter. Repeatedly requesting the same URL is much cheaper than the request count implies — polling a stable URL once a second for a minute costs one unit of quota, not sixty.
What is not covered by this cache
Translation bundle downloads. Those are static files on the CDN with their own, much longer cache policy — a pinned release is immutable and cached for a year. That is described in Releases & bundles.