Kaer Maps exposes the travel stack used by the Travel area as one metered HTTP endpoint. The API is currently a beta contract: use the actions documented here, inspect coverage fields, and do not infer live or authoritative data when a response says it is estimated or partial.
Create a key
Open Settings → Developer → API Keys and find the Kaer Maps API card at the foot of the page. Enable the API, choose the minimum capability set, then copy the key. The full kmaps_… value is shown once.
Send the key with either supported header:
X-Kaer-Maps-Key: kmaps_your_keyAuthorization: Bearer kmaps_your_keyBrowser preflight accepts both headers. Never put a Maps key in a public client bundle; call it from your server or another protected runtime.
Or use your account API key
A dedicated kmaps_ key does maps and nothing else. If you would rather hold one credential for everything, a personal account key (kaer_sk_…) with the maps scope reaches the same surface at GET /api/v1/maps, using the query contract on this page and billed at the same per-request rate. Create one in Customise → API access — see Account API.
Endpoint
GET https://app.kaer.ai/api/maps?action=geocode&query=London&limit=5curl --get 'https://app.kaer.ai/api/maps' \
--header 'X-Kaer-Maps-Key: kmaps_your_key' \
--data-urlencode 'action=route' \
--data-urlencode 'from=London' \
--data-urlencode 'to=Brighton' \
--data-urlencode 'mode=drive' \
--data-urlencode 'avoid=tolls,ferries,closures'const params = new URLSearchParams({
action: "poi",
near: "51.5074,-0.1278",
category: "parking",
radius_m: "3000",
limit: "12",
});
const response = await fetch(`https://app.kaer.ai/api/maps?${params}`, {
headers: { "X-Kaer-Maps-Key": process.env.KAER_MAPS_KEY },
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const data = await response.json();Stable actions
| Capability | Actions | Important inputs |
|---|---|---|
| Geocoding | geocode, reverse, place_at, geo_from_ip | query; lat + lon; optional near_lat, near_lon, near_country |
| Routing | route, journey, compare, road_classes, route_traffic, trip_context | from, to, optional via, mode, depart_at, avoid; stops for compare |
| Places | poi, events, fuel_prices, speed_cameras, site_image, site_images | near, category, radius_m, limit |
| Transit | transit, rail, stops, departures | from, to, time, arrive_by; stop_ids |
| Road data | incidents, closures, traffic_status | near or bounded bbox, optional pts, kinds, limit |
| Weather | weather | place or near, optional days |
route accepts mode=drive|truck|walk|bike. A successful response includes provider, geometry, steps, warnings, constraint_status, closure_avoidance, and attribution. If Valhalla falls back to OSRM, unsupported toll, ferry, highway, departure-time or closure constraints are reported as unapplied; they are never returned in avoided.
journey is a door-to-door discovery estimate. It can combine ground and estimated flight legs, but it is not a reservation or operational-status API. compare ranks multi-stop route patterns; it accepts up to eight stops today and can be provider-intensive.
Live flight shopping is intentionally not available to standalone Maps keys yet. action=flights requires an authenticated paid Kaer app session so premium allowance can be checked against the correct account; a Maps key receives 403 MAPS_KEY_SESSION_REQUIRED.
Road closures and charges
Every incidents response carries coverage, coverage_summary, sources, and generated_at.
- Authority or regional feeds can provide near-real-time coverage when a separately deployed normalized ingester is configured. The bundled stack does not ingest Street Manager, National Highways or TfL by itself.
- The worldwide Overpass fallback describes community-mapped construction as road works, not confirmed full closures. It is never used for hard avoidance, and an empty result is not proof that a road is open.
- Bounding boxes are limited to control provider cost. Query a route corridor or an area no larger than 5° per side and 16 square degrees.
verified_absenceis true only when authority snapshots are current, untruncated, and explicitly declare both query completeness and full road-network scope for the exact corridor. A fresh wrapper timestamp cannot substitute for the authority's upstream update watermark.- Route closure avoidance considers the requested departure time, filters the exact corridor before applying its result limit, sends Valhalla's top-level
exclude_polygonscontract, and verifies that the returned line does not intersect an exclusion.closure_avoidance.verifiedadditionally requires complete, current corridor coverage.
UK charge warnings carry authority, verification date, match method, vehicle applicability, official payment/checker URLs, and source URLs. Route intersection is only a prompt to check: ULEZ, LEZ, Congestion Charge and exemptions depend on the vehicle and travel time.
Use only the official services linked in the response:
Errors, limits and caching
| Status | Meaning |
|---|---|
400 | Missing/invalid input, unsupported action, or an oversized query |
401 | Invalid or revoked Maps key |
403 | Key lacks the capability, or the action is session-only |
404 | No matching place or route |
429 | Rate limit reached; respect Retry-After |
502 | Upstream provider failed |
503 | Capacity was shed, or paid metering could not commit; respect Retry-After |
Successful cached responses may carry x-kaer-maps-cache: hit, coalesced, shared-hit, or shared-coalesced. Location-bearing responses use exact canonical requests because coordinates and origin-relative distances are private to that request; shared Redis keys contain only a versioned digest, never raw locations or search text.
The production-shaped stack keeps an in-process L1 on every Next replica and uses the internal Rust/Redis coordinator for fleet-wide caller/provider budgets, short-lived L2 responses, and one token-fenced leader per identical cold miss. If shared coordination is required but unavailable, an expensive community-provider miss returns 503 MAPS_COORDINATION_UNAVAILABLE or MAPS_COORDINATION_BUSY with Retry-After; hot local results retain their bounded fallback. A kaer-maps-server replica is still a public-provider proxy unless the operator explicitly declares that every enabled upstream is self-hosted, so adding replicas alone never raises community-provider budgets.
Keyed calls currently budget 20 work tokens/second with a burst of 80 per account, then return 429; rotating a key does not reset that budget. Most actions cost one token, provider-fan-out actions cost more (compare costs four; journey/context/route-analysis batches cost two). Rotation has a durable 60-second cooldown and bounded revoked-key history. Each successful request is metered at the rate shown in Settings; unsuccessful and permission-denied calls are not billed. If the key counter and wallet ledger cannot commit together, the API returns retryable 503 MAPS_METERING_UNAVAILABLE instead of returning an unmetered success.
Attribution and data quality
Responses derived from OpenStreetMap include an attribution field. If you display those results or a rendered map, show a readable © OpenStreetMap contributors link. Tile renderers must also identify their tile provider.
Venue and event images are returned as signed same-origin /api/maps/image URLs. Do not replace them with the upstream URL: the proxy pins public DNS, rejects private/reserved targets and redirects, limits content type and size, and supplies cache/privacy headers.
Provider fields are part of the contract:
estimated: truemeans a modelled result, not a live itinerary or observation.operational_status: falsemeans fare-shopping data cannot be used for delays, gates or cancellations.coverage_summary.statusandlimitationdescribe what road data was actually checked.coverage[].complete, upstream freshness, andprovider_attributionmust be preserved in any client UI. National Highways data must display “Powered by National Highways’ Transport Data Feeds”.- Hotel and parking POIs are directory records unless a separate inventory provider explicitly supplies availability, tariffs or booking terms.
Rotate or disable a key from Settings if it is exposed. Capability changes take effect on the active key without requiring a rotation. Rotation is serialized and cooldown-protected per account, and a successful request updates the key counter and daily wallet ledger in one database transaction.