Matching vehicles and drivers
A pushed route names its truck and driver the way your TMS knows them. Novil resolves those names to its own vehicle and driver records through the same mappings fuel-card transactions use, so once a unit or a driver is mapped for one purpose it is mapped for all of them.
What Novil matches on
Section titled “What Novil matches on”| You send | Matched against |
|---|---|
vehicle.unitNumber |
The unit number exactly as it appears in Novil. |
vehicle.vin |
The 17-character VIN, for fleets whose unit numbers differ between systems. |
driver.name |
The driver’s full name as it appears in Novil (the name field on GET /v1/drivers). |
driver.externalId |
The telematics provider’s driver id, when drivers are synced to Novil from that provider. |
Send one of the two fields for each. VIN and externalId are the more stable choices when you have them; unit numbers and names are what most TMSs have.
Check before you push
Section titled “Check before you push”Two read-only endpoints let you see how a truck or driver will match:
curl "https://app.novilfleet.com/v1/vehicles?unitNumber=4471" -H "Authorization: Bearer $NOVIL_API_KEY"curl "https://app.novilfleet.com/v1/vehicles?vin=3AKJHHDR5NSMK1234" -H "Authorization: Bearer $NOVIL_API_KEY"curl "https://app.novilfleet.com/v1/drivers?name=whitfield" -H "Authorization: Bearer $NOVIL_API_KEY"{ "data": [{ "id": "drv_a17c", "name": "Dana Whitfield", "displayName": "Dana W.", "externalId": null }], "total": 1, "limit": 25, "offset": 0}Both lists are paged with limit (up to 100) and offset. Pulling the full vehicle list once and reconciling it against your fleet is a good first step in any rollout: every unit number that is in your TMS but not in Novil will become a pending_mapping route the first time it is dispatched.
When a route is held: pending_mapping
Section titled “When a route is held: pending_mapping”If the vehicle or driver is unknown, POST /v1/routes still succeeds: it returns 202 Accepted, assigns a route id, and holds the route with status: "pending_mapping":
{ "id": "b4f1c1e2-6f4b-4a8c-9a3e-2c5d8e7f1a90", "externalId": "ord_88214", "reference": "Load 23788", "name": "Load 23788", "status": "pending_mapping", "environment": "live", "pending": { "reason": "vehicle_unmapped", "detail": "Unit number 4488 is not mapped to a vehicle. Map it under Settings › Vehicle Matching." }, "vehicle": { "id": null, "unitNumber": "4488" }, "driver": { "id": "drv_a17c", "name": "Dana Whitfield" }, "scheduledStart": "2026-09-15T11:00:00Z", "stops": [ { "sequence": 0, "name": "Dallas DC", "type": "waypoint" }, { "sequence": 1, "name": "Memphis Yard", "type": "destination" } ], "distanceMiles": null, "fuelPlan": null, "createdAt": "2026-09-13T14:42:17Z"}pending.reason is vehicle_unmapped or driver_unmapped, and pending.detail names the value that did not match. The matched side (here the driver) already has its Novil id.
Fixing it
Section titled “Fixing it”Someone with access to the Novil app maps the value under Settings › Vehicle Matching or Settings › Driver Matching, pointing the unmapped unit number or name at the right record. Novil then imports the held route on its next pass, which runs every five minutes. Nothing needs to be resent: the route keeps its id and moves to draft on its own.
The mapping is remembered, so every later route with the same unit number or name matches immediately.
Watching for held routes
Section titled “Watching for held routes”Your integration does not need to do anything about a 202, but dispatchers usually want to know. Two options:
- Surface the
202and itspending.detailin the TMS, so whoever dispatched the load sees that Novil needs a mapping. - Periodically list
GET /v1/routes?status=pending_mappingand raise the ones that have been waiting.
Poll GET /v1/routes/{id} (or the list) to see the status change; there is no need to re-push.
The other hold: pending_window
Section titled “The other hold: pending_window”Routes scheduled further out than the company’s import window, 7 days by default, are accepted with 202 as pending_window with pending.reason of outside_import_window. They are imported automatically when their scheduledStart enters the window. Push loads as soon as they are dispatched regardless of how far out they are; the window is handled for you.
All pending reasons
Section titled “All pending reasons”pending.reason |
Status | Meaning |
|---|---|---|
vehicle_unmapped |
pending_mapping |
vehicle.unitNumber or vehicle.vin did not match a vehicle. |
driver_unmapped |
pending_mapping |
driver.name or driver.externalId did not match a driver. |
outside_import_window |
pending_window |
scheduledStart is beyond the import window. |
not_attempted |
pending |
Accepted, import not tried yet. |
error |
error |
Import failed; pending.detail explains. |