Skip to content

50,000 free calls a month, card-free. Get an API key →

Documentation menu
docs / api / post-v1-ev-plan
routing

POST/v1/ev/plan

API key required, sent as Authorization: Bearer snk_… or ?api_key=snk_….

What it does

The algorithm

  1. Base route. One auto route over origin + waypoints + destination, with the request's costing_options verbatim.
  2. Leg sampling. Each manoeuvre of that route becomes one sn_ev::LegSample: its length and its own average speed, which is finer than a leg summary and so makes the steady-state assumption in sn_ev::consumption_over_legs better. Manoeuvre-free routes fall back to one sample per leg, and a route with more than MAX_LEG_SAMPLES manoeuvres has consecutive ones coalesced.
  3. Elevation, or an honest absence. When elevation is enabled the gateway's own height service is asked for the elevation at every leg boundary, and each leg's gain and loss come from its two ends. When it is not enabled, or the DEM has no coverage, the legs are built with sn_ev::LegSample::without_gradient, the consumption model runs flat (the only thing it can do) and the response says gradient_data: "absent". A gradient is never silently assumed to be zero.
  4. Direct plan. sn_ev::consumption_over_legs over the whole route from start_soc. If the arrival state of charge is at or above min_arrival_soc and the reserve was never breached, that is the plan: no charger work and no matrix call happen at all.
  5. Candidates. Otherwise, charge points from the store are projected onto the route (corridor::nearest_on_route), filtered to those the vehicle can plug into at a rated power inside the corridor budget, and capped at MAX_PLAN_CANDIDATES spread along the route rather than clustered; the /v1/charging/along corridor machinery, with a spread instead of a power ranking, because a planner needs reach and a search needs kilowatts.
  6. One matrix. Origin + candidates → candidates + destination, one (n+1)² matrix through the gateway's own engine with the request's costing options, giving every hop a real driving time and distance: never a crow-flies guess.
  7. Greedy with lookahead. crate::ev::plan_stops walks the route choosing stops so the state of charge never breaches reserve_soc, preferring a stop that finishes the journey, then the furthest one (fewer stops), then the cheapest by driving plus charging time. A charger from which nothing further can be reached even on a full battery is refused rather than taken. At most eight passes.
  8. Final geometry. The chosen stops are merged with the waypoints in route order and the route is recomputed through them, so the geometry returned is the journey actually described.
  9. Or an honest no. When no plan exists (a charger desert, a connector mismatch, a gap wider than the vehicle's range), the answer is a 200 with feasible: false, the named cause, and the furthest point on the route the vehicle can actually reach. Never a fabricated plan.

Stated limitations

A hop's energy is sliced out of the base route's legs and the detour surplus charged as one gradient-unknown leg (see crate::ev::hop_legs); matrix cells are upper bounds on route cost, not route costs; the consumption model's own ±15 % motorway bound and its urban bias are stated in sn_ev; charging curves are best-case, measured on a warm pack. The plan is a plan, not a promise.

Call it

bash
curl -fsS -X POST "https://api.mapmap.ai/v1/ev/plan" \
  -H "Authorization: Bearer $MAPMAP_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json

Request body

application/json

EV journey plan: origin + destination (+ optional waypoints), a vehicle (profile: "small_hatch" | "saloon" | "suv" | "van", or an inline object of EvProfile fields over a base), start_soc (default 0.9), min_arrival_soc (default 0.1), reserve_soc (default 0.1, the mid-route floor), a connectors filter, min_kw, ambient_temperature_c, max_detour_minutes (default 15, max 120) and Valhalla costing_options (the costing is always auto)

The OpenAPI document declares this body as a free-form JSON object with no field list, so there is nothing here to generate a table from. The prose above is what the gateway states about it; the raw document is the authority.

Responses

200The plan, feasible or honestly not: {feasible, plan: {stops, total_drive_s, total_charge_s, total_duration_s, total_distance_m, start_soc, arrival_soc, min_arrival_soc, reserve_soc, energy_kwh}, stops[]: {charger_id, name, operator, source, lat, lon, connector: {standard, power_kw, dc, power_kw_source; derived when the feed did not publish the rating}, charger_kw, arrive_soc, depart_soc, charge_s, detour_s, along_route_position, off_route_m, status, status_live}, legs[]: {from, to, duration_s, distance_m, start_soc, end_soc, min_soc, consumed_wh, regen_wh}, soc_trace[], gradient_data: "complete" | "partial" | "absent", gradient: {legs_total, legs_with_gradient, fraction}, route: {duration_s, distance_m, length_m}, geometry_polyline6, coverage_note (ALWAYS present), sources[], availability: {live, note}, provenance: {profile, availability, consumption_model, charge_model}, charging_attribution}. When feasible is false the answer carries reason: {code, message} and furthest_reachable, never a fabricated stop list
400Invalid request
401Missing or invalid API key
429Quota or rate limit exceeded
501The charge-point dataset is not enabled (SN_CHARGE_DIR unset)
502Upstream routing engine failed

Error bodies follow the shared problem model documented on API conventions.

Also under routing

Generated from https://api.mapmap.ai/openapi.json on 2026-09-17 · operationId post_ev_plan