For developers

API Access

Everything you see is served by a clean, versioned REST API — the same contract that will power the upcoming native apps and partner integrations.

Authenticated public API

Create a key on your account, then call an endpoint below — e.g. /api/public/v1/countries with Authorization: Bearer <key>. Free tier: 1,000 requests per month, per API key. Paid plans raise the per-key limit + allow commercial use.

Public endpoints

Every route here needs Authorization: Bearer <key>. Each call is checked against that key's monthly quota — quota is per key, not per account.

GET
/api/public/v1/countriesList all countries with metadata.
GET
/api/public/v1/countries/{slug}Country detail: stats + index scores.
GET
/api/public/v1/categoriesAll categories and groups.
GET
/api/public/v1/indices/{key}{ countries: [...] } ranked array for an index (NOT ISO3-keyed) — identical payload to map; the two are redundant, pick one.
GET
/api/public/v1/map?index=KEY{ countries: [...] } ranked array for an index (NOT ISO3-keyed) — identical payload to indices/{key}; the two are redundant, pick one.
GET
/api/public/v1/compare?slugs=a,b,cCompare 2–5 countries.
GET
/api/public/v1/arbitrage?category=KEYCross-country price arbitrage.
GET
/api/public/v1/exchange-ratesLatest USD-based exchange rates.
GET
/api/public/v1/observations?limit=NRecent price submissions.
GET
/api/public/v1/prices?category=mcmealPrice stats for one item across countries (e.g. mcmeal), or ?country=japan for one country's items.

All responses use a consistent envelope: { "data": …, "meta": … } on success, or { "error": { "message", "code" } } on failure.

Public read endpoints are cache-friendly. API keys and paid tiers are live now — create a key on your account page.

Internal endpoints

These are what this website calls to render itself. They are unversioned in practice, carry no compatibility promise and may change or disappear without notice. Build against the public endpoints above instead.

Most of this tree allows short bursts before slowing a caller down, tracked per server process rather than in a database. A busy site runs several processes at once and a fresh one starts with a full allowance, so this is meant to discourage scripted abuse, not to cap total traffic at an exact number. (/api/v1/categories is exempt and served from cache instead.)

GET
/api/v1/countriesList all countries with metadata.
GET
/api/v1/countries/{slug}Country detail: stats + index scores.
GET
/api/v1/categoriesAll categories and groups.
GET
/api/v1/map?index=KEY{ countries: [...] } ranked array for an index (NOT ISO3-keyed) — identical payload to indices/{key}; the two are redundant, pick one.
GET
/api/v1/indices/{key}{ countries: [...] } ranked array for an index (NOT ISO3-keyed) — identical payload to map; the two are redundant, pick one.
GET
/api/v1/compare?slugs=a,b,cCompare 2–5 countries.
POST
/api/v1/simulatorTravel budget simulation.
GET
/api/v1/arbitrage?category=KEYCross-country price arbitrage.
GET
/api/v1/exchange-ratesLatest USD-based exchange rates.
GET
/api/v1/leaderboardTop contributors.
GET / POST
/api/v1/observationsRecent prices; submit a price (auth).
GET
/api/v1/travel?origin=IATA&month=YYYY-MMRanked travel affordability by month.