One key. 251 countries. Predictable JSON.
A read-mostly REST API over the same dataset the dashboard uses. Stable schema, ISO-3 country keys, citations on every record. No SDK required — plain HTTPS and JSON.
Quickstart · 4 lines of code
Compare cost of living across three countries with one request.
- Create a free account.
- Copy your key from /dashboard/profile.
- Run the request →
- Open the response in /dashboard/compare.
curl https://api.costmaps.com/api/v1/cost-of-living/countries/DEU \ -H "Authorization: Bearer cm_live_..."
Authentication
Every request must include an Authorization header with a Bearer token. Keys are created and rotated from /dashboard/profile. Keys are scoped to a single project; rotate at will.
Authorization: Bearer cm_live_a3f4c9e0b2d54f8a91ec4d6b0e2f4a8c
Test keys. Keys prefixed cm_test_ hit a fixture dataset and don't count against quota — use them in CI.
Endpoints by module
Every module follows the same shape: /api/v1/<module>/countries/<ISO-3>. For multi-country requests, use the compare endpoint instead.
Get cost of living · single country
Returns the harmonized basket for a single country, with subcategories and provenance on every record. The response is stable across minor releases.
DEU, JPN, or GBR.curl "https://api.costmaps.com/api/v1/cost-of-living/countries/DEU" \ -H "Authorization: Bearer cm_live_..."
{
"country_code": "DEU",
"country_name": "Germany",
"currency_code": "EUR",
"currency_symbol": "€",
"prices_by_category": {
"groceries": [
{ "item_name": "Milk (1L)", "price_usd": 1.12, "source": "photo", "recorded_date": "2026-06-01" }
]
},
"total_items": 42,
"last_updated": "2026-03-12T08:14:00Z"
}Rate limits
Limits apply per API key, per UTC day. Every response includes the headers X-CostMaps-Limit, X-CostMaps-Remaining, and X-CostMaps-Reset.
| Plan | Requests / day | Burst (per minute) | Concurrent |
|---|---|---|---|
| Free | 100 | 20 | 2 |
| Pro | 1,000 | 120 | 5 |
| Business | 10,000 | 600 | 25 |
| Enterprise | 100,000 | 3,000 | 100 |
When a request is throttled the API returns 429 Too Many Requests with a Retry-After header in seconds. The dashboard remains usable even when API quota is exhausted.
Errors
The API returns standard HTTP status codes. The response body always includes a stable error.code string you can match on.
{
"error": {
"code": "country_not_found",
"message": "No country with ISO-3 code XYZ",
"status": 404,
"docs": "https://costmaps.com/docs#errors"
}
}| Status | Code | When |
|---|---|---|
400 | invalid_parameter | Query parameter failed schema validation. |
401 | missing_auth | No Authorization header. |
403 | plan_required | Endpoint requires a higher tier (e.g. exports). |
404 | country_not_found | ISO-3 unknown or not seeded. |
429 | rate_limited | Daily limit reached — see Retry-After. |
5xx | upstream_unavailable | An upstream source is temporarily unreachable; safe to retry. |
Compare countries · POST
Unified comparison: cost-of-living index, salary, tax estimate, and PPP-adjusted affordability for a base country against one or more comparison countries in a single call.
curl -X POST https://api.costmaps.com/api/v1/compare \
-H "Authorization: Bearer cm_live_..." \
-H "Content-Type: application/json" \
-d '{
"base_country_code": "DEU",
"compare_country_codes": ["JPN", "GBR"],
"job_title": "Software Engineer",
"experience_level": "mid"
}'{
"base_country_code": "DEU",
"job_title": "Software Engineer",
"experience_level": "mid",
"results": [
{
"country_code": "DEU",
"country_name": "Germany",
"salary_median_usd": 68420,
"col_index": 72.3,
"tax_estimate_pct": 39.5,
"net_salary_usd": 41394,
"ppp_adjusted_salary": 57270,
"affordability_ratio": 1.14
},
{
"country_code": "JPN",
"country_name": "Japan",
"salary_median_usd": 60890,
"col_index": 81.0,
"tax_estimate_pct": 30.0,
"net_salary_usd": 42623,
"ppp_adjusted_salary": 52630,
"affordability_ratio": 0.98
}
]
}