API & webhooks for Dashivo Pro fleets
Connect Dashivo Pro to your own systems. Read your fleet's data, create routes from your orders, and hear the moment something happens.
Included with every Dashivo Pro plan. Owners and Admins create keys in the console under Company › API & webhooks, each with only the permissions it needs.
Start in two minutes
- In the console, open Company › API & webhooks and choose Create key. Name it for the system that will use it and tick what it may do. You confirm it's you, then the key is shown once: copy it to your server's secret settings.
- Send it with each request:
curl https://pro.dashivo.app/api/public/v1/drivers \
-H "Authorization: Bearer dshv_sampleprefix_…"
Every answer is JSON. An error looks like {"error": {"code": "insufficient_scope", "message": "…"}} with the HTTP status that fits it.
Keys and permissions
A key belongs to your company and works with its creator's authority. It stops at once when it's revoked, when it expires, or when the person who made it is no longer an Owner or Admin. We keep only a fingerprint of the key, never the key itself. Every key action and every data pull is written to Company security › Audit log (pulls as one line per key and hour, with the count), and the console lists the last requests of each key.
| Permission | What it allows |
|---|---|
drivers:read | Drivers, their teams and vehicle, on shift or not |
vehicles:read | Vehicles |
routes:read | Routes, stops and their status, proof of delivery and its photos |
routes:write | Create routes and dispatch them |
locations:read | The latest position of drivers on shift who share it |
alerts:read | The alert log (30 days) |
events:read | Driving events (30 days) and the event video inbox |
scores:read | Driver scores for 7, 30 or 90 days |
footage:read | Footage details: when, who, kind, length, size, locked. Never the video: it plays in the console, where every view is checked and logged. |
webhooks:manage | Add and remove webhook endpoints (what Zapier uses) |
Endpoints
All under https://pro.dashivo.app/api/public/v1. The OpenAPI document describes every field.
| Request | Answer |
|---|---|
GET /me | Your company and the key's permissions |
GET /drivers, /drivers/{id} | Drivers (?email= finds one) |
GET /vehicles, /vehicles/{id} | Vehicles |
GET /routes, /routes/{id} | Routes; one route with its stops, each stop's status and proof of delivery |
POST /routes | Create a route from orders or stops, and dispatch it if you like |
POST /routes/{id}/dispatch | Send a route to its driver |
GET /media/{id} | A proof-of-delivery photo or signature |
GET /locations | Live positions |
GET /alerts | Alerts |
GET /events | Crashes, police stops, hard braking, fast starts, sharp turns, speeding, phone use, SOS and driver reports |
GET /event-videos | The event video inbox: each event, its clip and whether it was reviewed or coached |
GET /scores | Driver scores and their factors |
GET /footage | Footage details |
GET / POST /webhooks, DELETE /webhooks/{id} | Webhook endpoints (up to 50 added through the API, 10 in the console) |
GET /webhook-events/recent?type=…&limit=… | Your latest events of one type (up to 10), each exactly as a webhook would deliver it; an empty list when there are none |
Create a route from your orders
curl https://pro.dashivo.app/api/public/v1/routes \
-H "Authorization: Bearer $DASHIVO_KEY" -H "Content-Type: application/json" \
-d '{"name": "Order 1042", "driver_id": "…", "dispatch": true,
"stops": [{"address": "100 Main St, Denver, CO", "note": "Ring twice"},
{"address": "200 Oak Ave, Denver, CO", "lat": 39.75, "lon": -104.97,
"window_start": "09:00", "window_end": "11:00", "dwell_minutes": 5}]}'
A stop without lat and lon is looked up by its address (up to 40 in one request); one we can't find is refused with address_not_found and its index, never guessed. With "dispatch": true the driver gets the route at once, exactly as if dispatch sent it from the console.
Lists, limits and errors
- Lists come newest first, 50 at a time (
limitup to 200). Whenhas_moreis true, sendnext_cursorback ascursor. Most lists takesince(an ISO 8601 time). - Each key may make 120 requests a minute, 30 of them creating or dispatching routes. Every answer says how many are left (
X-RateLimit-Remaining); over the limit you get 429 withRetry-After. - 401: no key, a wrong one, or one revoked, expired or stopped. 403: the key lacks the permission. 402: your company's plan is read-only, so writes wait.
Webhooks
Add your server's HTTPS address in the console (or with POST /webhooks) and choose its events. We post a JSON message within seconds:
| Event | When |
|---|---|
stop.arrived | A driver arrived at a stop |
stop.completed | A stop was done, with its proof of delivery |
stop.skipped | A driver skipped a stop, with the note |
route.dispatched | A route was sent to its driver, with its stops |
route.accepted, route.declined | The driver answered |
alert.created | A critical or warning alert reached dispatch |
crash.detected | A driver's phone detected a crash |
police_stop.started | A driver started police stop recording |
inspection.failed | An inspection had failed items, with each one |
event_video.ready | A clip of a crash or harsh-driving event finished uploading |
POST /your/endpoint
Dashivo-Event: stop.completed
Dashivo-Signature: t=1792857600,v1=5f2c…
{"id": "8c1d…", "type": "stop.completed", "created_at": "2026-10-24T15:20:04Z",
"api_version": "2026-10-24", "organization_id": "…",
"data": {"route": {"id": "…", "number": 1042, "name": "Order 1042"},
"driver": {"id": "…", "name": "Jordan"},
"stop": {"index": 0, "address": "100 Main St, Denver, CO", "lat": 39.741, "lon": -104.989},
"proof_of_delivery": {"recipient_name": "Sam", "photo_urls": ["/api/public/v1/media/…"], "…": "…"}}}
Answer with any 2xx within 10 seconds. Anything else is tried again after 1 minute, 5 minutes, 30 minutes, 2, 6, 12 and 24 hours, then marked failed. The delivery log in the console shows each try and your server's answer, and can send one again. An endpoint where every delivery fails for 3 days is switched off until you turn it back on. A retry can arrive twice, so use the event's id to skip repeats. Addresses must be public HTTPS; we don't follow redirects.
Check a signature
Each endpoint has its own signing secret, shown once when you add it. v1 is an HMAC-SHA256 of the timestamp, a dot and the raw body. Compare it in constant time and refuse old messages:
import hashlib, hmac, time
def verify(secret: str, body: bytes, header: str, tolerance=300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t = int(parts["t"])
if abs(time.time() - t) > tolerance:
return False
mac = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(mac, parts["v1"])
const crypto = require("crypto");
function verify(secret, rawBody, header, tolerance = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > tolerance) return false;
const mac = crypto.createHmac("sha256", secret).update(`${parts.t}.`).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(parts.v1));
}
Zapier
The API is ready for Zapier: triggers subscribe with POST /webhooks and unsubscribe with DELETE /webhooks/{id}, and GET /me tests the connection. Our Zapier app is coming soon, with these triggers and actions:
- Triggers: Stop completed, Stop skipped, Route accepted, Route declined, New alert, Crash detected, Police stop started, Inspection failed, Event video ready.
- Actions: Create route (and dispatch it), Dispatch route. Search: Find driver by email.
Until then, Zapier's own Webhooks step can receive any of our events today.
Put your fleet
on the record.
Tell us about your company and the vehicles you run. We'll set up Dashivo™ Pro with you, and reply within one business day.
Your footage is private · Messages end-to-end encrypted · $20 per device a month, 200 GB of cloud storage included