Skip to content

Caching & freshness

A verdict is a cacheable fact — and a decaying one. The API gives you both: validators so you can cache cheaply, and explicit signals so you know when an answer has gone stale.

A verdict response carries:

HeaderMeaning
ETagStable hash over (slug, macosVersion, chip, lastVerified)
Last-ModifiedMirrors the verdict’s lastVerified date
Cache-Controlpublic, max-age=3600, stale-while-revalidate=86400 for verdicts

Revalidate cheaply with a conditional request — an unchanged verdict returns 304 with no body:

Terminal window
curl https://api.doesitarm.com/v1/verdicts/slug:adobe-photoshop \
-H 'If-None-Match: "abc123"'
# → 304 Not Modified if the verdict hasn't changed

A verdict body is tier-independent — a free caller and a paid caller get the identical verdict for the same (slug, macosVersion, chip). So verdict responses are public and are not varied on Authorization; splitting the cache per key would fragment the CDN for zero benefit (and public + Vary: Authorization is a known shared-cache footgun). Genuinely key-scoped responses — the paid change feed — are marked Cache-Control: private instead.

Freshness is the product’s promise, so it’s explicit in the response, not implied by age:

  • stale (body field) — true when the verdict is past its freshness threshold and a re-test is queued. You still get the last known answer.
  • X-DoesItARM-Stale (header) — the same signal, readable without parsing the body.
  • lastVerified (body) / Last-Modified (header) — when the answer was last confirmed.

Treat stale: true as “trust, but re-check soon” — not as an error. Re-tests fire on a new macOS or Game Porting Toolkit release, an app update, a report surge, or a scheduled cadence; the change feed tells you the moment a cached verdict actually changed, so you can invalidate precisely instead of polling. The concept behind all of this is How verdicts work.