Skip to main content
When a fleet is integrated with Nash, the runtime contract has two halves: Nash makes synchronous HTTP calls to the fleet for everything that happens to a route, and the fleet reports state back through the Update Delivery endpoint. This page covers the outbound half — the fleet.route.* calls Nash POSTs (or GETs) on the fleet’s API.
These are synchronous HTTP requests, not async webhook fanout. Nash blocks on the response and acts on it: 200 = accept, 4xx = permanent reject (Nash tries another fleet), 5xx/timeout = retryable failure.

Wire model: every dispatch is a route

A single delivery is a degenerate route of one pickup stop + one dropoff stop; a multi-order job carries N stops. Same envelope, same endpoint (/fleet/routes), same response shape — the fleet implements one schema and Nash handles the single-vs-multi collapse internally.

Integration shape

Onboarding & authentication

At onboarding, Nash provisions an organization for the fleet and records:
  • The API base URL Nash sends route calls to.
  • The outbound auth token Nash includes on every call.
  • An org API key the fleet uses to authenticate inbound calls into Nash.
Outbound auth (Nash → fleet). Nash sends a bearer token in the Authorization: Bearer <token> header on every outbound request. The token is issued at onboarding. The fleet validates the token before processing the body. Inbound auth (fleet → Nash). The fleet sends every inbound request with the org API key as a bearer token:
Updates only land on deliveries owned by the fleet’s organization. Anything else returns not-found — Nash never leaks existence across organization boundaries.

Events

The minimum set required to participate is dispatched, updated, canceled. quote is required only for fleets participating in quoting; refresh is required only when the fleet doesn’t push state inbound on its own.

Wire envelope

Every event has the same top-level shape:

Acknowledgement and retries

Nash expects 200 OK. Other responses are handled as follows:
  • 4xx — treated as a permanent rejection. For fleet.route.dispatched, Nash will route to a different fleet.
  • 5xx or timeout — retried with exponential backoff.
  • 404 on refresh — soft no-op. Fleet doesn’t know about this route (possibly pruned after completion).

fleet.route.dispatched

Sent when Nash commits the route to the fleet. The body carries the full route snapshot. Each stop has an orders[] array with full per-order snapshots embedded — pickup-side AND dropoff-side fields are included on every embedding, so the fleet has everything it needs without follow-up lookups.

Multi-order route

Key shape decisions:
  • Stops are flat and sequenced (0..N-1), mirroring Nash’s Route.stops.
  • Each stop carries orders[] — full per-order snapshots embedded right there. No follow-up lookups.
  • A stop with multiple orders[] means a co-pickup or co-dropoff (multiple orders touched at the same location).
  • stopType is pickup, dropoff, or other (e.g. driver_break) — driver-break stops pass through verbatim from Nash’s optimizer.

Single delivery (degenerate route of one)

A dispatch for one merchant order ships as a route with exactly two stops. When the delivery has no Nash-side Route (single-order dispatch), the delivery id is used as the wire routeId:
The fleet doesn’t have to special-case single vs. batch — both are routes.

Dispatch response

On accept:
Nash stores partnerStopId (per-delivery) as the fleet-side delivery identifier for cross-referencing in logs. Falls back to the Nash delivery id if the fleet doesn’t return one. On reject:
4xx with an optional structured body. Nash treats the route as failed and tries another fleet (or alerts the merchant if no fallback).

fleet.route.updated

Sent when a field on an in-flight order changes (pickup or dropoff window, address, instructions, items), or when a stop is added mid-flight. The body is a full re-send of the route snapshot plus a fieldChanges[] list naming the paths that changed.
Sending the full updated route on every change means the fleet can diff against what they had — no need to track add / remove deltas themselves.

fleet.route.canceled

Sent when the merchant or Nash cancels the route, or one delivery on it. The body carries the route id, the affected deliveryIds[], and a cancelReason.
deliveryIds[] lists the specific deliveries being canceled. For a whole-route cancellation, it’s every delivery on the route; for a single-delivery cancellation on a multi-delivery route, only that one delivery. After a cancellation, any further PATCH /v1/fleet/deliveries/{deliveryId} calls for that delivery are no-ops.

Refresh

Nash periodically polls the fleet for the current state of an in-flight route:
Fleet returns per-stop state in the shape of the inbound PATCH /v1/fleet/deliveries/{id} body, keyed by deliveryId:
Refresh and inbound PATCH share the exact same field set. The fleet can implement one DeliveryUpdate JSON shape and reuse it for both pushing state to Nash (inbound) and returning state to Nash (the refresh GET response).
Nash applies the entry whose deliveryId matches the delivery being refreshed and ignores the rest — they’re siblings on the same route refreshed in their own poll. 404 is a soft no-op (fleet doesn’t know about this route).

fleet.route.quote

Quoting lets the fleet compete on price and ETA against other providers configured by the merchant. It’s opt-in at onboarding — fleets that don’t participate are still eligible to receive dispatches directly when the merchant picks them; they just don’t compete on price.

Flow

  1. Nash receives an order (or multi-stop batch) from the merchant and identifies the fleets eligible to fulfill it.
  2. For each eligible fleet that participates in quoting, Nash POSTs POST /fleet/routes/quote with the route snapshot.
  3. The fleet responds with a quote within the agreed latency budget. Quotes that arrive too late or fail are skipped — they don’t block other fleets’ quotes.
  4. Nash filters quotes against the merchant’s constraints (max fee, max ETA) and the merchant picks a winner.
  5. The winning fleet receives POST /fleet/routes (dispatch). Losing fleets receive nothing — they don’t need to track the outcome.

Quote request

Same wire envelope as the other fleet.route.* calls; event: "quote". Same route-shaped data as dispatch, but each order’s deliveryId is null (the delivery isn’t committed yet).
For batch quoting, the route has N orders with sequenced pickup stops followed by sequenced dropoff stops.

Quote response

Respond with 200 OK and a JSON body, or 4xx to decline:
Decline responses (4xx) are interpreted as ineligible for this route. Nash captures the decline reason from the response body if present ({ "reason": "out_of_service_area" }) but doesn’t retry.

Latency budget

The fleet’s quote endpoint should respond within the budget configured at onboarding (typically 1–3 seconds). Quotes that exceed the budget are dropped for that route. Consistent timeouts move the fleet to a degraded state and Nash will route around it until quote latency recovers.

Rejecting a dispatch

If the fleet can’t accept the route (no capacity, ineligible), it can reject in two ways:
  • Reject in the response. Respond 4xx to POST /fleet/routes (dispatched). Nash treats the dispatch as failed and tries a different fleet.
  • Reject after acceptance. Ack 200, then PATCH /v1/fleet/deliveries/{deliveryId} with status: failed and failure.code: "no_capacity". Nash treats it as a runtime failure and tries a different fleet.

Order field reference

The per-order snapshot embedded under each stop’s orders[] is flat camelCase, with ISO 8601 timestamps and monetary values in minor units.

Required

  • pickupInstructions / dropoffInstructions — gate codes, “leave at door,” etc.
  • requirements — alcohol, age verification, signature, photo POD, barcode scans.
  • weight / height / width / depth — improves vehicle fit.
  • tipAmountCents — passed through to the courier where the fleet supports it.
  • referenceId — short identifier shown to the courier in the fleet’s app.
  • tags — partner-specific routing flags.

Stop-level fields