Skip to content
novilDevelopersOpen Novil
GuidesPushing routes from a TMS

Pushing routes from a TMS

A TMS integration with Novil is one call per dispatched load: POST /v1/routes. Novil takes it from there, matching the truck and driver, computing the routed distance, and building and sending the fuel plan when the truck arrives at the first stop. This guide covers the details that make that one call robust.

Field Required What to send
externalId yes Your TMS’s identifier for the load (an order or movement id). Used for idempotency and to find the route again. Max 200 characters.
reference no The load or order number as dispatchers know it, for example Load 23787. Becomes the route’s name in Novil and pairs re-pushed loads for superseding.
vehicle yes unitNumber exactly as it appears in Novil, or a 17-character vin.
driver yes name (full name as it appears in Novil) or externalId (your driver id, when drivers are synced from a telematics provider).
scheduledStart yes When the truck should leave the first stop, RFC 3339 with an offset.
stops yes 2 to 50 stops in driving order; the last one is the destination. Each needs name, latitude and longitude; address is display-only and arrivalWindow (start, end) records an appointment.

Novil does not geocode. If your TMS stores only addresses, geocode them before pushing.

POST /v1/routes is idempotent by externalId. The first push creates the route and returns 201; every later push with the same externalId updates it in place and returns 200. That makes the integration simple: whenever a load changes in the TMS (new stop, new truck, new departure time), push the whole load again. There is no separate update call and no need to track what changed.

Updates are accepted while the route is held (pending*), draft or planned. Once the route is active the truck is already driving it and the stops cannot change: the push is rejected with 409 and the code route_active. For a load that changes after departure, cancel is not available either (see below); push the changed load under a new externalId so it becomes a fresh route.

Superseding: a new externalId, the same reference

Section titled “Superseding: a new externalId, the same reference”

Some TMSs assign a new id when a load is re-planned or re-dispatched. If a load you already pushed comes back under a new externalId but the same reference, Novil supersedes the old draft instead of creating a duplicate, when the company has supersede enabled. Send reference consistently (the load number dispatchers use) and this happens without any extra work on your side.

The status field tells you where a route is. The pending* statuses mean the route was accepted but is not imported yet; the rest follow the truck.

Status Meaning What you see
pending Accepted, import not attempted yet. pending.reason is not_attempted. Short-lived.
pending_mapping The vehicle or driver is not mapped in Novil. 202 on push. pending.reason is vehicle_unmapped or driver_unmapped; pending.detail says which. Resolves on its own once the mapping exists.
pending_window Scheduled further out than the company’s import window (7 days by default). 202 on push. pending.reason is outside_import_window. Imported when the start enters the window.
draft Imported and waiting for the truck. fuelPlan is null; distanceMiles is set once routed.
planned A fuel plan is ready. fuelPlan holds the plan: totals and one entry per fuel stop.
active The plan has been sent to the driver. fuel_stop entries appear among stops; actualArrival and actualDeparture fill in from the truck’s GPS.
completed The route is finished. Terminal. Plan and actuals remain readable.
error Import failed. Terminal. pending.reason is error; pending.detail explains.
canceled Canceled through the API or in Novil. Terminal.

Novil builds the fuel plan when the truck arrives at the route’s first stop, exactly as it does for routes that come in through a telematics or TMS integration. That is when status becomes planned and fuelPlan stops being null. When the plan is sent to the driver the route becomes active and the plan’s own status becomes active. There is no separate resource to fetch: the route is the plan, and GET /v1/routes/{id} always returns the current one.

fuelPlan has one entry per fuel stop: where (name, address, coordinates, milesFromOrigin), how much (gallonsToFill), at what price (pricePerGallon, net including tax, and totalCost), the expected arrivalFuelPercent and estimatedArrival. Totals and savingsPerGallon (average corridor price minus the plan’s average price) sit at the top. An empty stops list is a valid plan: the truck can reach its destination on the fuel it has. The active plan is returned once one has been sent to the driver; before that, the plan currently selected for the route. Once the route is active, the same fuel stops also appear in the route’s stops timeline as fuel_stop entries, in driving order between the dispatch stops.

DELETE /v1/routes/{id} cancels a route that has not started and returns 204:

  • A held route (pending, pending_mapping, pending_window) is dropped.
  • A draft or planned route is retired in Novil with the reason “Canceled via API”.

Active and completed routes cannot be canceled here; the call returns 409. After a cancel, pushing the same externalId again creates a fresh route rather than reviving the old one, so a “cancel and re-push” is a safe way to start over.

GET /v1/routes lists routes created through the API, newest scheduled start first, with filters for status, externalId (returns at most one route), vehicleId, and a from/to range on the scheduled start. limit is 1 to 100 (default 25) and offset pages through the rest. GET /v1/routes/{id} returns one route by the id you were given at push time.

  • Push a load as soon as it is dispatched. Nothing is sent to the driver until the truck reaches the first stop, so pushing early costs nothing and gives Novil time to resolve mappings.
  • Re-push on every change in the TMS. Idempotency makes this safe.
  • Do not poll a route more often than every few minutes. Use GET /v1/routes?status=pending_mapping to find routes that need a human, and ?status=planned to pick up plans.