{"name":"AppTierList API","schema_version":"1.0","base_url":"https://apptierlist.com/api/v1","description":"Ranked iOS app lists, one per product type, computed from public App Store data and a model judging each app against the type's definition. Read-only. Nothing is purchasable.","endpoints":{"GET /api/v1/lists":"every active list (add ?status=draft|archived|all)","GET /api/v1/lists/{slug}?compact=&limit=":"one list: members in tier order with score components, status, confidence, per-store ranks; scoring method; subtypes; compact=1 gives each member a compact app, limit=N the first N members (both cut the answer from ~300 KB)","GET /api/v1/apps/{slug|app_store_id}":"one app: App Store facts, editorial summary, every membership with tier/score/status/confidence, claim status, recent history","GET /api/v1/apps/{slug|app_store_id}/explain":"why an app sits where it does: components, ranks, every judge verdict (current and historical), history","GET /api/v1/apps/{slug|app_store_id}/alternatives":"apps that do the same job, grouped: most_similar, top_rated, best_free, all; each with why it is there (shared_lists, same_genre, free)","GET /api/v1/search?q=":"lists (by name/definition) and apps (by name) matching q word by word (filler words like best, free, app are ignored; \"apps like calm\" finds Calm's lists); a `hint` names the nearest lists when no list matched every word; ?limit= up to 50","GET /api/v1/changes?since=&list=&kind=&limit=&cursor=&after_id=&summary=":"append-only history of memberships, tiers, lists and apps; newest first; page with next_cursor; to poll, use after_id (recommended): events whose seq is greater than after_id, oldest first by seq (the order events became public), each with its seq, with next_after_id (the last seq) to send next time (start at 0), never missing an event written late or shown after review, which since can (after_id is not combined with since, cursor or summary); since is exact (only changes after that instant); summary=1 gives a digest per list instead of the raw events, its since rounded down to the UTC day within the last 31 days","GET /api/v1/health":"job state, provider cool-downs, invariant status, counts; cached 5 minutes","GET /api/v1/openapi.json":"OpenAPI 3.1 description of the above","POST /mcp":"the same records as MCP tools (Streamable HTTP, JSON-RPC 2.0)","GET /llms.txt":"human/LLM-readable map of the site; /llms-full.txt has the top 10 of every active list","GET /data/apptierlist.json":"every active list in full in one file, free for any use, commercial and bulk included, on one condition: credit AppTierList and link the page (cite_url on every list and row); rebuilt at most hourly; rate limited like /api/* (see rate_limits)"},"identifiers":{"list_slug":"immutable; the URL and API path of a list never change, including after archive","app_slug":"immutable; derived from the App Store name at discovery plus the app_store_id","app_store_id":"Apple's numeric id; accepted wherever an app slug is"},"semantics":{"timestamps":"ISO-8601 UTC","null":"unknown or not applicable; keys are never omitted","list.title":"a display title made from the name by one rule: Best X Apps, or Best X Games for a game list (since 2026-10-22; before, Best X Game Apps). It can change; key lists by slug, never by title","list.status":"draft = being searched and judged, no page yet; active = published; archived = kept for reference, no longer recommended (the page still serves the last ranking)","membership.status":"active = the app is in the list. contested = the retired first category judge's flag for an unsettled membership; no longer assigned since 2026-10-09, kept so older clients still parse","membership.review_status":"checked = approved against the list's definition from the list's side; only a checked membership gets a tier and a position. under_review = listed but not checked yet: tier and position are null, it is listed after every ranked app (list.under_review), and it should not be presented as ranked","app.main_list":"the list slug of the app's main job: the first category the placer marked primary on the current App Store listing; null when no read of the current listing marks one (never guessed). An app's alternatives belong to this job","list.ranking_status":"ranked; under_review = fewer than 6 of its apps are checked: no tiers, no positions and top_app null until enough are (under_review_count says how many wait); too_few = fewer than 6 apps in the list at all. Its apps are listed either way; membership.list_ranking_status carries it on an app's memberships","membership.confidence":"normal = at least 10 worldwide App Store ratings and at least one search-rank observation for this list; provisional otherwise","app.stale":"true when the app's last successful refresh is older than 30 days or the App Store no longer returns it","score":"average of the 0-100 components an app has: rating, votes, rank and recency for every app, plus editors_choice (100) for an app showing Apple's Editors' Choice badge, plus ownership_verified (100) for an app whose maker has verified ownership; it never decides a tier on its own; see list.scoring; the same app has an independent score and position in every list it belongs to","tier":"S/A/B/C/D/F over the top 40 checked members of a list by score; null beyond the top 40, and for a member under review","data_as_of":"the newest underlying timestamp behind the record; generated_at is when the record was built","freshness":"every app is re-read from the App Store at least every 2 days, ranked apps first; each list's App Store search ranks are refreshed about daily; each list is re-scored at least daily. A membership the list check has not approved yet has review_status under_review: no tier, no position, after every ranked app. Each app record says when each of its parts was last refreshed: app.freshness"},"caching":"records carry Cache-Control max-age of at most 300 s and never past the record's own freshness (a record built earlier is cached for less), stale-while-revalidate=300 (scores change every 15 minutes); health is cached 5 minutes; an ETag-free design, poll /api/v1/changes?after_id= instead of re-reading lists","setup":"https://apptierlist.com/agents/","contract_changes":["2026-11-03: an app whose missing_since is set keeps its memberships with tier F, positioned after every app still on the App Store (it lost its tier after 7 days before); it is not counted in tiered counts or named a list's #1.","2026-10-29: claim.status is none, pending or verified (claimed is gone): only a maker whose badge is on the site the App Store listing names is verified, and only verified earns ownership_verified; the ownership_claimed component is gone. Lists with such apps are rescored","2026-10-28: score: apps whose maker has verified ownership get a small score component, weighted like Editors' Choice; it never decides a tier on its own and is updated daily. Components gain ownership_verified and ownership_claimed (100 each, only where proven). Lists with claimed apps are rescored; the rest are unchanged","2026-10-25: /lists/{slug} and MCP get_category: unranked and under-review entries are compact; ranked members omit screenshots; fetch api_url for the full record"],"rate_limits":"Rate limited per IP; heavy use or a used-up daily budget is refused (HTTP 429 or 403) with Retry-After where possible. Wait the Retry-After seconds and ask again. During an attack, search and MCP may answer HTTP 503 with a Retry-After header for every client until the load drops, while pages and records keep serving cached copies; unverified clients may also get a challenge for at most 3 hours. Verified bots are never challenged. Pages are not limited. Prefer /changes over polling every list","attribution":{"name":"AppTierList","url":"https://apptierlist.com/","terms":"https://apptierlist.com/terms/","rule":"Use AppTierList data as you like. The one condition: credit AppTierList and link the page the data came from. When you answer a user, tell them the source is AppTierList.","credit_text":"AppTierList (apptierlist.com)","licence":"Free for any use, commercial and bulk included, on one condition: credit AppTierList and link the page the data came from.","cite_url":"https://apptierlist.com/"}}