Kaer docs

Maps API

Geocoding, routing, places, transit, road intelligence and weather through Kaer's metered Maps API.

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_key
Authorization: Bearer kmaps_your_key

Browser 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=5
curl --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

CapabilityActionsImportant inputs
Geocodinggeocode, reverse, place_at, geo_from_ipquery; lat + lon; optional near_lat, near_lon, near_country
Routingroute, journey, compare, road_classes, route_traffic, trip_contextfrom, to, optional via, mode, depart_at, avoid; stops for compare
Placespoi, events, fuel_prices, speed_cameras, site_image, site_imagesnear, category, radius_m, limit
Transittransit, rail, stops, departuresfrom, to, time, arrive_by; stop_ids
Road dataincidents, closures, traffic_statusnear or bounded bbox, optional pts, kinds, limit
Weatherweatherplace 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_absence is 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_polygons contract, and verifies that the returned line does not intersect an exclusion. closure_avoidance.verified additionally 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

StatusMeaning
400Missing/invalid input, unsupported action, or an oversized query
401Invalid or revoked Maps key
403Key lacks the capability, or the action is session-only
404No matching place or route
429Rate limit reached; respect Retry-After
502Upstream provider failed
503Capacity 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: true means a modelled result, not a live itinerary or observation.
  • operational_status: false means fare-shopping data cannot be used for delays, gates or cancellations.
  • coverage_summary.status and limitation describe what road data was actually checked.
  • coverage[].complete, upstream freshness, and provider_attribution must 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.