> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usenash.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Outbound Integration

> Synchronous HTTP calls Nash makes to a fleet for quoting, dispatch, modifications, cancellations, and refresh.

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](/api-reference/fleet/update-delivery) endpoint.

This page covers the outbound half — the `fleet.route.*` calls Nash POSTs (or GETs) on the fleet's API.

<Note>
  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.
</Note>

## 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

```mermaid theme={"dark"}
sequenceDiagram
    autonumber
    participant Nash
    participant Fleet
    participant Courier

    Note over Nash,Fleet: Quoting (optional)
    Nash->>Fleet: POST /fleet/routes/quote
    Fleet-->>Nash: 200 { priceCents, etas, expireTime }

    Note over Nash: Nash ranks quotes per merchant strategy<br/>and picks a winner

    Nash->>Fleet: POST /fleet/routes (event: dispatched)
    Fleet-->>Nash: 200 { partnerRouteId, stops: [{ partnerStopId, deliveryId }] }
    Fleet->>Fleet: route to fulfillment, assign courier

    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { courier, externalDeliveryId }
    Nash-->>Fleet: 200 { ...full delivery payload }

    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { status: pickup_enroute, coordinates }
    Courier->>Fleet: arrives at pickup
    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { status: pickup_arrived }
    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { status: pickup_complete, proofOfDelivery }

    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { status: dropoff_enroute, coordinates }
    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { status: dropoff_arrived }
    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { status: dropoff_complete, proofOfDelivery }
```

## 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:

```
Authorization: Bearer <org_api_key>
```

Updates only land on deliveries owned by the fleet's organization. Anything else returns not-found — Nash never leaks existence across organization boundaries.

## Events

| Event                    | Method + path                         | When                                                                                                                                                                                |
| ------------------------ | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fleet.route.quote`      | `POST /fleet/routes/quote`            | Nash is requesting a price/ETA on a route. The fleet responds with a quote in the response body. Only sent if the fleet participates in quoting.                                    |
| `fleet.route.dispatched` | `POST /fleet/routes`                  | Nash committed the route to this fleet for fulfillment. The body carries the full route snapshot — stops with embedded order data and per-order `deliveryId`.                       |
| `fleet.route.updated`    | `POST /fleet/routes/{routeId}`        | A field on an in-flight order changed, or a stop was added mid-flight. The body carries the **full updated route**; an optional `fieldChanges[]` list names the paths that changed. |
| `fleet.route.canceled`   | `POST /fleet/routes/{routeId}/cancel` | The merchant or Nash canceled the route (or one delivery on it). Body carries `cancelReason` and `deliveryIds[]`.                                                                   |
| (refresh)                | `GET /fleet/routes/{routeId}`         | Nash polls for current state. Fleet returns per-stop updates keyed by `deliveryId`.                                                                                                 |

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:

| Field        | Meaning                                                                                                                                                                                                                                              |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`       | Always `"fleet.route"`.                                                                                                                                                                                                                              |
| `event`      | One of `quote`, `dispatched`, `updated`, `canceled`.                                                                                                                                                                                                 |
| `routeId`    | Nash's stable handle for this route. Use it on `GET /fleet/routes/{routeId}`, `POST /fleet/routes/{routeId}`, `POST /fleet/routes/{routeId}/cancel`. For a single-delivery dispatch with no Nash-side route, the delivery id is used as the routeId. |
| `occurredAt` | ISO 8601 timestamp of when the event happened in Nash.                                                                                                                                                                                               |
| `data`       | The route snapshot: `{ id, stops: [...] }`. Update calls add `fieldChanges[]`; cancel calls replace `stops` with `{ deliveryIds, cancelReason }`.                                                                                                    |

## 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

```json theme={"dark"}
{
  "type": "fleet.route",
  "event": "dispatched",
  "routeId": "rte_abc123",
  "occurredAt": "2026-05-09T14:00:00Z",
  "data": {
    "id": "rte_abc123",
    "externalId": "merchant-route-7",
    "stops": [
      {
        "stopType": "pickup",
        "sequence": 0,
        "location": { "lat": 37.7749, "lng": -122.4194 },
        "arrivalTime": "2026-05-09T15:00:00Z",
        "endTime": "2026-05-09T15:15:00Z",
        "serviceTime": 300,
        "orders": [
          {
            "id": "ord_1",
            "deliveryId": "dlv_1",
            "externalId": "merchant-order-42",
            "referenceId": "ACM-42",
            "deliveryMode": "scheduled",

            "pickupAddress": "123 Main St, San Francisco, CA 94102, US",
            "pickupBusinessName": "Acme Bakery",
            "pickupFirstName": "Manager",
            "pickupPhoneNumber": "+14155551212",
            "pickupInstructions": "Use the side door",
            "pickupStartTime": "2026-05-09T15:00:00Z",
            "pickupEndTime": "2026-05-09T15:15:00Z",
            "pickupBarcodes": ["ACME-PKG-001"],

            "dropoffAddress": "456 Market St, San Francisco, CA 94103, US",
            "dropoffFirstName": "Jane",
            "dropoffLastName": "Customer",
            "dropoffPhoneNumber": "+14155553434",
            "dropoffInstructions": "Leave at door",
            "dropoffStartTime": "2026-05-09T15:45:00Z",
            "dropoffEndTime": "2026-05-09T16:15:00Z",

            "items": [
              { "name": "Sourdough Loaf", "quantity": 2 },
              { "name": "Croissant", "quantity": 6 }
            ],
            "valueCents": 4200,
            "tipAmountCents": 500,
            "currency": "USD",
            "weight": 3.2,
            "requirements": ["age_verification_on_delivery"],
            "tags": ["catering"]
          }
        ]
      },
      {
        "stopType": "dropoff",
        "sequence": 1,
        "location": { "lat": 37.7895, "lng": -122.4001 },
        "arrivalTime": "2026-05-09T15:45:00Z",
        "endTime": "2026-05-09T16:15:00Z",
        "orders": [
          { "id": "ord_1", "deliveryId": "dlv_1", "...": "same per-order snapshot as above" }
        ]
      }
    ]
  }
}
```

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`:

```json theme={"dark"}
{
  "type": "fleet.route",
  "event": "dispatched",
  "routeId": "dlv_zyx987",
  "occurredAt": "2026-05-09T14:00:00Z",
  "data": {
    "id": "dlv_zyx987",
    "stops": [
      {
        "stopType": "pickup",
        "sequence": 0,
        "orders": [{ "id": "ord_1", "deliveryId": "dlv_zyx987", "...": "..." }]
      },
      {
        "stopType": "dropoff",
        "sequence": 1,
        "orders": [{ "id": "ord_1", "deliveryId": "dlv_zyx987", "...": "..." }]
      }
    ]
  }
}
```

The fleet doesn't have to special-case single vs. batch — both are routes.

### Dispatch response

On accept:

```json theme={"dark"}
{
  "partnerRouteId": "fp-route-99",
  "stops": [
    { "sequence": 0, "deliveryId": "dlv_1", "partnerStopId": "fp-s-1" },
    { "sequence": 1, "deliveryId": "dlv_1", "partnerStopId": "fp-s-2" }
  ]
}
```

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:

```json theme={"dark"}
{ "error": { "code": "no_capacity", "message": "Out of vehicles in this zone" } }
```

`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.

```json theme={"dark"}
{
  "type": "fleet.route",
  "event": "updated",
  "routeId": "rte_abc123",
  "occurredAt": "2026-05-09T14:30:00Z",
  "data": {
    "id": "rte_abc123",
    "fieldChanges": ["dropoffStartTime", "dropoffEndTime"],
    "stops": [ "...full stops array..." ]
  }
}
```

<Tip>
  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.
</Tip>

```mermaid theme={"dark"}
sequenceDiagram
    autonumber
    participant Merchant
    participant Nash
    participant Fleet

    Merchant->>Nash: PATCH /v1/order/{id} (new dropoff time)
    Nash->>Nash: validate, update order
    Nash->>Fleet: POST /fleet/routes/{routeId}<br/>{event: updated, data.fieldChanges: ["dropoffStartTime"], data.stops: [...]}
    Fleet-->>Nash: 200 OK
    Note over Fleet: Fleet re-routes courier<br/>or 4xx if uncommittable
```

## `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`.

```json theme={"dark"}
{
  "type": "fleet.route",
  "event": "canceled",
  "routeId": "rte_abc123",
  "occurredAt": "2026-05-09T14:45:00Z",
  "data": {
    "id": "rte_abc123",
    "deliveryIds": ["dlv_1"],
    "cancelReason": "canceled_by_merchant"
  }
}
```

`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.

```mermaid theme={"dark"}
sequenceDiagram
    autonumber
    participant Merchant
    participant Nash
    participant Fleet

    Merchant->>Nash: cancel order
    Nash->>Nash: mark order canceled
    Nash->>Fleet: POST /fleet/routes/{routeId}/cancel<br/>{event: canceled, data.deliveryIds: [...], cancelReason: ...}
    Fleet-->>Nash: 200 OK
    Fleet->>Nash: PATCH /v1/fleet/deliveries/{deliveryId} { status: canceled_by_provider }
    Note over Nash,Fleet: Nash terminates the lifecycle;<br/>further PATCHes are no-ops
```

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:

```
GET /fleet/routes/{routeId}
```

Fleet returns per-stop state in the shape of the inbound `PATCH /v1/fleet/deliveries/{id}` body, keyed by `deliveryId`:

```json theme={"dark"}
{
  "stops": [
    {
      "deliveryId": "dlv_1",
      "status": "pickup_complete",
      "coordinates": { "latitude": 37.78, "longitude": -122.41 },
      "courier": { "name": "Sam", "phoneNumber": "+14155550000" }
    },
    {
      "deliveryId": "dlv_2",
      "status": "pickup_enroute"
    }
  ]
}
```

<Note>
  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).
</Note>

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).

```mermaid theme={"dark"}
sequenceDiagram
    autonumber
    participant Nash
    participant Fleet

    Note over Nash: periodic refresh from tracker
    Nash->>Fleet: GET /fleet/routes/{routeId}
    Fleet-->>Nash: 200 { stops: [{ deliveryId, status, coordinates, ... }, ...] }
    Nash->>Nash: apply each stop entry via the same code path as inbound PATCH
```

## `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).

```json theme={"dark"}
{
  "type": "fleet.route",
  "event": "quote",
  "routeId": "ord_abc123",
  "occurredAt": "2026-05-09T14:00:00Z",
  "data": {
    "stops": [
      {
        "stopType": "pickup",
        "sequence": 0,
        "location": { "lat": 37.7749, "lng": -122.4194 },
        "orders": [{
          "id": "ord_abc123",
          "deliveryId": null,
          "pickupBusinessName": "Acme Bakery",
          "pickupPhoneNumber": "+14155551212",
          "pickupStartTime": "2026-05-08T15:00:00Z",
          "pickupEndTime": "2026-05-08T15:15:00Z",
          "...": "..."
        }]
      },
      {
        "stopType": "dropoff",
        "sequence": 1,
        "location": { "lat": 37.7895, "lng": -122.4001 },
        "orders": [{
          "id": "ord_abc123",
          "deliveryId": null,
          "dropoffFirstName": "Jane",
          "dropoffPhoneNumber": "+14155553434",
          "dropoffStartTime": "2026-05-08T15:45:00Z",
          "dropoffEndTime": "2026-05-08T16:15:00Z",
          "...": "..."
        }]
      }
    ]
  }
}
```

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:

```json theme={"dark"}
{
  "externalQuoteId": "<fleet-quote-id>",
  "priceCents": 1500,
  "currency": "USD",
  "pickupEta": "2026-05-08T15:55:00Z",
  "dropoffEta": "2026-05-08T16:20:00Z",
  "expireTime": "2026-05-08T15:30:00Z"
}
```

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.

```mermaid theme={"dark"}
sequenceDiagram
    autonumber
    participant Nash
    participant Fleet
    participant FleetB as Backup Fleet

    Nash->>Fleet: POST /fleet/routes (event: dispatched)
    Fleet--xNash: 4xx { error: { code: "no_capacity" } }
    Nash->>Nash: mark dispatch failed, try another fleet
    Nash->>FleetB: POST /fleet/routes (event: dispatched, same routeId)
    FleetB-->>Nash: 200 OK
```

## 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

| Field                                 | Meaning                                                                                                                                                |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                                  | Nash order id. Stable across modifications.                                                                                                            |
| `deliveryId`                          | Identifier the fleet uses on subsequent updates via `PATCH /v1/fleet/deliveries/{deliveryId}`. Present on dispatch / update / cancel; `null` on quote. |
| `externalId`                          | Merchant's order identifier — useful for fleet-side reconciliation.                                                                                    |
| `pickupAddress`                       | Full address string.                                                                                                                                   |
| `pickupBusinessName`                  | Store / restaurant name.                                                                                                                               |
| `pickupPhoneNumber`                   | E.164 — for courier-to-store contact.                                                                                                                  |
| `pickupStartTime` / `pickupEndTime`   | When the order will be ready (window).                                                                                                                 |
| `dropoffAddress`                      | Customer address.                                                                                                                                      |
| `dropoffFirstName`                    | Recipient first name.                                                                                                                                  |
| `dropoffPhoneNumber`                  | E.164 — for SMS tracking and courier contact.                                                                                                          |
| `dropoffStartTime` / `dropoffEndTime` | Promised delivery window.                                                                                                                              |
| `items`                               | List of `{ name, quantity, ... }`.                                                                                                                     |
| `valueCents`                          | Subtotal in minor units.                                                                                                                               |
| `currency`                            | ISO 4217.                                                                                                                                              |
| `deliveryMode`                        | `now` or `scheduled`.                                                                                                                                  |

### Recommended

* `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

| Field                     | Meaning                                                 |
| ------------------------- | ------------------------------------------------------- |
| `stopType`                | `pickup`, `dropoff`, `driver_break`, etc.               |
| `sequence`                | 0-indexed position in the route.                        |
| `location`                | `{ lat, lng }`.                                         |
| `arrivalTime` / `endTime` | Window for this stop.                                   |
| `serviceTime`             | Seconds the courier is expected to spend at the stop.   |
| `orders[]`                | Per-order snapshot — see "Order field reference" above. |
