API reference
The RouteKey driver app and your dispatch integrations talk to one REST endpoint. Drivers pull their route on launch, then stream location and upload proof of delivery as they work the stops.
Base URL
All requests are made against your account's region. This deployment is us-central-1.
https://routekey.io/v1
Requests authenticate with an API key as a bearer token. Keys are scoped per account; a driver-app key can read routes and post stop events but cannot change billing or org settings.
Authorization: Bearer rk_live_9f2c81a4d7e0b365
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/routes/:driver_id |
Fetch the driver's optimized stop sequence for the shift. |
| POST | /v1/stops/:stop_id/proof |
Upload proof of delivery — photo and/or signature. This is where the bytes are. |
| POST | /v1/drivers/:driver_id/location |
Report a live GPS position (batched every few seconds while moving). |
| GET | /v1/manifest |
Pull the dispatch manifest for a depot and date. |
Fetch a route
Called by the driver app on launch and on resume. Small and cheap — it's the only call that needs to be fresh, so a reassignment shows up on the driver's next poll.
GET /v1/routes/drv_7f3c9a21?date=2026-07-21
// 200 OK { "route_id": "rt_2026_07_21_a41f", "driver_id": "drv_7f3c9a21", "depot": "atx-north", "stops": [ { "stop_id": "stp_88a1", "seq": 1, "address": "1200 W 6th St, Austin, TX", "window": ["09:00", "11:00"], "lat": 30.2711, "lng": -97.7566 }, { "stop_id": "stp_9c02", "seq": 2, "address": "2100 S Lamar Blvd, Austin, TX", "window": ["09:30", "12:00"], "lat": 30.2470, "lng": -97.7880 } ] }
Upload proof of delivery
Posted at each completed stop. The photo is the largest thing the app sends all day, which is why the SDK compresses on-device and retries on a flaky connection rather than blocking the driver.
POST /v1/stops/stp_88a1/proof Content-Type: multipart/form-data
// fields photo: <binary jpeg, ~1–3 MB> signature: <binary png, optional> outcome: "delivered" lat: 30.2711 lng: -97.7566 captured_at: "2026-07-21T09:14:08Z"
// 201 Created { "proof_id": "pod_5f21c9", "stop_id": "stp_88a1", "stored": true }
A busy route is 60–120 stops a day, each with a 1–3 MB photo, per driver — so a mid-size fleet moves several GB a day up to the endpoint, all from phones on cellular. Size your plan by fleet, not by seats.
Report live location
The app batches GPS points and posts them every few seconds while the driver is moving, so dispatch sees an accurate ETA without draining the phone.
POST /v1/drivers/drv_7f3c9a21/location Content-Type: application/json { "points": [ { "lat": 30.2679, "lng": -97.7731, "t": "2026-07-21T09:11:02Z" }, { "lat": 30.2691, "lng": -97.7702, "t": "2026-07-21T09:11:07Z" } ] }
// 202 Accepted
Driver SDK quickstart
Android (Kotlin). The iOS SDK exposes the same calls.
val client = RouteKey.init( apiKey = "rk_live_9f2c81a4d7e0b365", endpoint = "https://routekey.io" ) // Pull today's route and hand it to the map. val route = client.routes.today(driverId) // At each stop: compress + upload, retry in the background. client.stops.submitProof(stopId, photo, outcome = "delivered")
Errors
| Code | Meaning | What to do |
|---|---|---|
| 401 | API key missing, malformed, or revoked. | Check the bearer token. Driver keys are issued per account. |
| 404 | No route for that driver and date. | Usually a driver with no assigned stops yet. Show an empty-day state. |
| 413 | Proof payload too large. | The SDK compresses to fit; if you post raw, keep photos under 8 MB. |
| 429 | Too many requests from one key. | Honour Retry-After; the SDK backs off on its own. |
Service health for this region is published at /status.