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

> ## Agent Instructions
> Nash exposes two MCP servers. The docs MCP server at https://docs.usenash.com/mcp searches this documentation and needs no credentials. The Nash MCP server at https://mcp.usenash.com/mcp operates an organization's deliveries and needs a Nash API key. See https://docs.usenash.com/reference/build-with-ai.
> Use the Sandbox environment (https://api.sandbox.usenash.com/v1) for anything that creates or dispatches deliveries during development.

# Fast casual restaurant integration

> Quote delivery during checkout, dispatch when payment succeeds, and track every delivery through webhooks.

A fast casual delivery integration comes down to three touchpoints. You quote while the guest is in checkout, dispatch that quote when payment succeeds, and listen to webhooks until the food is at the door. Nash picks the provider (a third-party courier network, a local fleet, or your own drivers) and sends every status back in one normalized format.

This guide is for a restaurant brand, or its ordering platform, that runs its own web or app checkout and wants on-demand (ASAP) delivery. For the same pattern outside restaurants, see the [sample checkout workflow](/guides/checkout-workflow).

## When to use this

* Guests order in your own app or website and choose delivery at checkout.
* You want to show a delivery fee and arrival time before the guest pays.
* Your kitchen needs couriers to arrive when food is ready, not before.
* You want delivery status in your app, your POS, or your kitchen display.

If you batch many orders into planned routes for your own drivers, start with [route optimization](/guides/route-optimization) instead.

## How it works

| Step | When it happens | Nash call | What you get back |
| - | - | - | - |
| 1. Quote | Guest enters a delivery address in checkout | [`POST /v1/order/get_quotes`](/api-reference/order/get-order-quotes) | A Nash order `id`, a list of `quotes` (price, dropoff ETA, expiry), and `failedQuotes` |
| 2. Dispatch | Payment succeeds and the POS order exists | [`PATCH /v1/order/{id}`](/api-reference/order/update-order), then [`POST /v1/order/{id}/autodispatch`](/api-reference/order/autodispatch-order) | A job (delivery), booked with the provider |
| 3. Track | From dispatch until a terminal status | [Webhooks](/reference/webhooks) to your endpoint (type `delivery`) | One event per status change, carrying the full job |

<Frame caption="Your app calls Nash twice, once to quote and once to dispatch. Everything after that comes back as webhooks.">
  <img src="https://mintcdn.com/nashtechnologies/KiOUCImK_x2o0nWt/images/guides/fast-casual-sequence.svg?fit=max&auto=format&n=KiOUCImK_x2o0nWt&q=85&s=d7f589b800488a470b1ba0f7ed1bff52" alt="Sequence diagram in three phases. Checkout: the guest enters a delivery address; your app calls get_quotes; Nash requests quotes from providers and returns an order ID and quotes; your app shows the fee and ETA. Order placed: the guest pays; your app updates the order and calls autodispatch; Nash books the delivery and returns the job. Delivery: the provider reports status changes; Nash sends a delivery webhook; your app shows live status." width="760" height="628" data-path="images/guides/fast-casual-sequence.svg" />
</Frame>

## Before you start

Build and test in Sandbox first. Sandbox has its own API keys and Portal, and pairs [simulated fleets](/reference/environments) with your test orders, so a test order never sends a real courier.

<Steps>
  <Step title="Create an API key and find your Org ID">
    Every request sends `Authorization: Bearer $NASH_API_KEY` and the `Nash-Org-Id` header. See [Authentication](/reference/authentication).
  </Step>

  <Step title="Add your restaurants as store locations">
    Add each restaurant as a [store location](/reference/store-locations), with your own store number as its external ID. A quote then only needs `pickupExternalStoreLocationId`; Nash uses the store's saved address and contact details.
  </Step>

  <Step title="Set up a dispatch strategy">
    A [dispatch strategy](/reference/dispatch-strategies) holds your rules for choosing a provider: cost, speed, a preferred fleet first, a fee cap, auto-reassignment. Apply it with a [dispatch automation](/api-reference/dispatch-strategies/dispatch-automations) so you don't send `dispatchStrategyId` on every call. Keep **Enable Autodispatch** off, so an order isn't booked the moment you quote it.
  </Step>

  <Step title="Register a webhook endpoint">
    In the Portal, under **Settings > Webhook Management**, add an HTTPS endpoint subscribed to `delivery` events. Copy its signing secret for [verification](/reference/webhooks#verifying-webhooks).
  </Step>
</Steps>

## Step 1: Quote during checkout

Call [Create Quote](/api-reference/order/get-order-quotes) once the guest has entered a full delivery address and you know which store will make the food. The response gives the delivery fee and arrival time to show, and a Nash order `id` to keep with the cart.

Call it after the address is confirmed and the cart is close to final, not on every keystroke or cart edit. If the guest changes the address or store, quote again. If they change only the cart, update the order (Step 2).

```bash theme={"dark"}
curl -X POST https://api.sandbox.usenash.com/v1/order/get_quotes \
  -H "Authorization: Bearer $NASH_API_KEY" \
  -H "Nash-Org-Id: $NASH_ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "cart_8812",
    "pickupExternalStoreLocationId": "store-0142",
    "dropoffAddress": "350 5th Ave, New York, NY 10118",
    "dropoffFirstName": "Jordan",
    "dropoffLastName": "Lee",
    "dropoffPhoneNumber": "+12125550123",
    "deliveryMode": "now",
    "pickupStartTime": "2026-09-30T17:15:00Z",
    "valueCents": 3450,
    "itemsCount": 3,
    "description": "2 bowls, 1 drink"
  }'
```

| Field | Why it matters for fast casual |
| - | - |
| `pickupExternalStoreLocationId` | Your store number. Nash looks up the pickup address from the store location. |
| `dropoffAddress` (or address components), name, and phone | A full, valid address is required for a quote; see [Send the address](#send-the-address-single-line-or-components). The phone lets the courier reach the guest. |
| `deliveryMode` | `now` on the first quote. Switch it to `scheduled` if the guest picks a later delivery time. |
| `pickupStartTime` | The earliest the food can be ready: now plus your kitchen prep time, plus any buffer, in UTC. On the first quote, this is the only time you send; see [Choose which time to send](#choose-which-time-to-send). |
| `dropoffStartTime` / `dropoffEndTime` | Leave these out of the first quote. Send them only when the guest picks a later delivery time; Nash then works out the pickup time from drive time. |
| `valueCents`, `itemsCount`, `description` | Order value and size, passed on to the provider so the courier knows what to expect. |
| `externalId` | Your cart or order ID, so you can find the order in the Portal. You can replace it with the POS order number in Step 2. |
| `maxDeliveryFeeCents` | Optional. A cap on the delivery fee; it overrides the dispatch strategy's cap. |

### Choose which time to send

Quote with the earliest pickup time, and let the provider's ETA set the first delivery time the guest sees.

1. **First quote: send the pickup time only.** Set `pickupStartTime` to the earliest the food can be ready: now plus the restaurant's prep time, plus any buffer you want to give the kitchen. Don't send dropoff times.
2. **Show the ETA as the first available time.** Each quote comes back with a `dropoffEta`: the provider's expected arrival for that pickup time. Show the preferred quote's `dropoffEta` to the guest as the earliest delivery time they can choose.
3. **Update the order to match what the guest chose.** Before you dispatch (Step 2), send the time that matches the guest's choice:

| The guest chooses | What to send before dispatch | What Nash does |
| - | - | - |
| The first available time | Nothing changes. Keep `pickupStartTime` as you quoted it. | Books the delivery for that pickup time. |
| A later time | Set `deliveryMode` to `scheduled`, set `pickupStartTime` to `null`, and send the guest's chosen time as `dropoffStartTime` (and `dropoffEndTime` for a window). | Works out when the courier needs to pick up, from drive time, and sends back that pickup time so the restaurant knows when to have the food ready. |

Don't send both a pickup time and a guest-chosen dropoff time for the same order. One anchors the delivery; Nash calculates the other.

### Send the address: single line or components

Nash needs a deliverable dropoff address to quote. You can send it two ways, and you pick one per request; mixing them returns a validation error.

| | Single line | Address components (preferred) |
| - | - | - |
| What you send | `dropoffAddress`: the whole address as one string, such as `"350 5th Ave, Apt 4B, New York, NY 10118"` | Each part in its own field, plus coordinates: `dropoffAddressNumber`, `dropoffAddressSecondarynumber`, `dropoffAddressFormattedStreet`, `dropoffAddressCity`, `dropoffAddressState`, `dropoffAddressZip`, `dropoffAddressCountry`, `dropoffLat`, `dropoffLng` |
| What Nash does | Parses and geocodes the string, then returns the parsed components in the response | Uses your components and coordinates as sent, without geocoding again |
| If it goes wrong | An address Nash can't parse fails validation (for example, "Address not found") | You own the accuracy of what you send |
| Use it when | Your checkout only has a free-text address | Your checkout already has a structured address, such as from an address autocomplete or a saved guest profile |

Send components if you have them. The address the guest confirmed at checkout is the one the courier gets, with the unit number in its own field and the pin where your autocomplete put it, rather than a second geocode of a typed string. Required components are `dropoffAddressFormattedStreet`, `dropoffAddressCity`, `dropoffAddressZip`, `dropoffAddressCountry`, `dropoffLat`, and `dropoffLng`.

```json theme={"dark"}
{
  "pickupExternalStoreLocationId": "store-0142",
  "dropoffAddressNumber": "350",
  "dropoffAddressSecondarynumber": "4B",
  "dropoffAddressFormattedStreet": "5th Ave",
  "dropoffAddressCity": "New York",
  "dropoffAddressState": "NY",
  "dropoffAddressZip": "10118",
  "dropoffAddressCountry": "US",
  "dropoffLat": 40.7484,
  "dropoffLng": -73.9857
}
```

Don't send `dropoffAddress` or `dropoffPlaceId` alongside components. A Google Place ID (`dropoffPlaceId`) works like the single line: Nash looks it up and geocodes it. The pickup side follows the same rules, but with `pickupExternalStoreLocationId` Nash takes the pickup address from the store location. See [Order address validation](/api-reference/order/order-address-validation-geocoding) and [Order validations](/api-reference/order/order-validations).

### Read the response

* `id` is the Nash order ID. Store it with the cart; Steps 2 and 3 use it.
* `quotes` lists the options, each with `totalPriceCents`, `dropoffEta`, `expireTime`, and `providerName`. Show the guest the quote whose `tags` include `autodispatch_preferred_quote`; that's the one autodispatch will book.
* `failedQuotes` lists providers that can't take the order. If `quotes` is empty, delivery isn't available to this address, so offer pickup instead.

You don't have to charge the guest the Nash price. You can charge a flat delivery fee and use the quote only to confirm delivery is available and to show an ETA.

If the guest abandons the cart, do nothing. An order that was quoted but never dispatched doesn't need to be canceled.

## Step 2: Dispatch after checkout completes

Once payment succeeds and the order exists in your POS, update the Nash order with the final details, then dispatch it. Dispatching books the delivery with the provider and returns a job (delivery), which you track in Step 3.

### Update the order

Use [Update Order](/api-reference/order/update-order) with the Nash order `id` from Step 1. Swap in the POS order number and add what the courier needs at the counter and at the door:

```bash theme={"dark"}
curl -X PATCH https://api.sandbox.usenash.com/v1/order/$NASH_ORDER_ID \
  -H "Authorization: Bearer $NASH_API_KEY" \
  -H "Nash-Org-Id: $NASH_ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "POS-20260930-0417",
    "referenceId": "417",
    "pickupInstructions": "Order #417 on the pickup shelf by the door",
    "dropoffInstructions": "Apt 4B, buzz 4B",
    "tipAmountCents": 500
  }'
```

`referenceId` is shown to the courier where the provider supports it, so use the short number your staff call out at the counter.

If the guest chose a later delivery time instead of the first available one, send the time change in the same update: switch `deliveryMode` to `scheduled`, clear the pickup time, and send their chosen dropoff time (see [Choose which time to send](#choose-which-time-to-send)).

```json theme={"dark"}
{
  "deliveryMode": "scheduled",
  "pickupStartTime": null,
  "dropoffStartTime": "2026-09-30T19:00:00Z"
}
```

### Dispatch the order

Call [Autodispatch Order](/api-reference/order/autodispatch-order). Nash books the quote your dispatch strategy prefers, the one tagged `autodispatch_preferred_quote`, which is the quote you showed the guest in Step 1. Your provider rules live in the strategy, so you can change them in the Portal without a code change.

<Note>
  [Select Quote](/api-reference/order/select-quote) (`POST /v1/select_quote` with a `quoteId`) books one specific quote. It's available, but use it only when Nash's built-in selection strategies can't express what you need. It hard-codes the provider choice in your code, and you lose strategy features like auto-reassignment and fee caps. If you think you need it, talk to Nash first; a strategy change usually covers it.
</Note>

Autodispatch returns `{ "job": { ... } }`. Save `job.id` on your POS order; webhooks reference it.

* **Check the quote hasn't expired.** Every quote has an `expireTime`. If the guest spent a long time in checkout, call [Refresh Quotes](/api-reference/order/refresh-order-quotes) with the `orderId` first. The price shouldn't change unless the order did.
* **Dispatch once per order.** Mark the POS order as dispatched when the call succeeds. If the call times out, don't retry blindly: read the order with [Get Order](/api-reference/order/get-order) and dispatch again only if it has no job.
* **Plan for a failed dispatch.** If the call returns an error or no provider can take the order, alert the store, then retry after refreshing quotes, switch the order to pickup, or refund the delivery fee.

## Step 3: Receive status updates through webhooks

After dispatch, Nash sends a webhook every time the delivery changes status, so you don't need to poll. Every payload has three fields: `type` (`delivery` for status changes), `event` (the new status), and `data` (the full job, the same shape as the dispatch response).

```json theme={"dark"}
{
  "type": "delivery",
  "event": "dropoff_enroute",
  "data": {
    "id": "job_R7FXJrfB99bpvpzf6CriJC",
    "isBatch": false,
    "portalUrl": "https://portal.usenash.com/active/job_R7FXJrfB99bpvpzf6CriJC",
    "jobConfigurations": [ { "tasks": [ { "status": "dropoff_enroute" } ] } ]
  }
}
```

### Map statuses to what the guest sees

Nash normalizes every provider's statuses into [one list](/reference/delivery-status). A fast casual app usually needs only a few guest-facing states:

| Nash `event` | Guest-facing message | Store action |
| - | - | - |
| `created`, `not_assigned_driver` | "Finding a courier" | None |
| `assigned_driver` | "Courier assigned", with name and ETA | Get the bag ready |
| `pickup_enroute`, `pickup_arrived` | "Courier heading to the restaurant" / "Courier at the restaurant" | Hand off the bag |
| `pickup_complete`, `dropoff_enroute` | "On the way", with live tracking | None |
| `dropoff_arrived` | "Courier has arrived" | None |
| `dropoff_complete` | "Delivered", with proof of delivery if present | Close the order |
| `canceled_by_provider`, `canceled_by_nash`, `failed`, `expired` | "We're sorting out your delivery" | Alert the store (see [Edge cases](#edge-cases)) |
| `canceled_by_customer` | "Delivery canceled" | Refund per your policy |

Every completed delivery passes the seven statuses below in order; Nash infers a status if a provider skipped it. Other statuses can arrive in between, and not every provider sends every status.

<Frame caption="With auto-reassignment on, a provider cancel isn't the end: Nash books another provider on the same job, and a new task starts again at created.">
  <img src="https://mintcdn.com/nashtechnologies/KiOUCImK_x2o0nWt/images/guides/fast-casual-status-lifecycle.svg?fit=max&auto=format&n=KiOUCImK_x2o0nWt&q=85&s=f1b007bb8ae3fca764532e21668f4289" alt="Delivery status lifecycle. Active delivery: created, assigned_driver, pickup_enroute, pickup_arrived, dropoff_enroute, dropoff_arrived, dropoff_complete, each with a guest message. From any active status a delivery can end early as canceled_by_provider, canceled_by_nash, canceled_by_customer, failed, or expired; with auto-reassignment a new task starts at created." width="760" height="304" data-path="images/guides/fast-casual-status-lifecycle.svg" />
</Frame>

### Build your webhook handler

1. **Verify the signature.** Nash sends webhooks through Svix. Check the `svix-id`, `svix-timestamp`, and `svix-signature` headers against your endpoint's signing secret, ideally with a Svix SDK. See [Verifying webhooks](/reference/webhooks#verifying-webhooks).
2. **Respond with a `2xx` quickly.** Queue the work and acknowledge right away. Failed deliveries are retried on a backoff; see the [retry policy](/reference/webhooks#retry-policy).
3. **Deduplicate.** Retries and multiple tasks can send the same event twice. Key on `svix-id`, and never move an order backward: ignore `dropoff_enroute` once you've seen `dropoff_complete`.
4. **Handle reassignments.** When Nash reassigns a delivery, the old task ends and a new task starts on the same job. A cancel on the old task doesn't mean the delivery is over; read `jobConfigurations[].advancedTask` for the attempt that's live. See [Reassignments and courier changes](/reference/webhooks#reassignments-and-courier-changes).
5. **Match on the job ID.** Look up your order by `data.id`, the `job.id` you saved in Step 2.

### Real-time tracking for the guest

You can show the guest a live map two ways: build it yourself from location webhooks, or let Nash host it. The hosted page is the faster path, since it needs no map or backend work on your side.

| | Build it yourself | Nash-hosted tracking |
| - | - | - |
| How it works | Subscribe to [`courier_location`](/reference/webhooks#courier-location-events) webhooks. Nash sends the courier's position every 1 to 2 minutes while the provider reports it. Draw it on your own map. | The job's `publicTrackingUrl` opens a Nash-hosted page with the courier on a live map and real-time status. Link to it, or [embed it](/reference/nash-embedding) in your app or site with an `<iframe>`. |
| Guest messages | You send them, driven by `delivery` webhooks. | Nash can send SMS and email updates with the tracking link, from templates you set in the Portal. See [Notifications](/reference/notifications). |
| Branding | Fully yours. | Your logo and colors. Nash can also serve the page on your own domain; talk to your Nash team. |
| Before dispatch | Your own "order received" screen. | Turn on [tracking before dispatch](/reference/nash-embedding#tracking-before-dispatch) and the same link shows an order-received screen, then switches to live tracking once a courier is booked. |
| Best for | Brands with an app team that wants the map inside a native screen. | Getting live tracking to guests quickly, with no backend work. |

You can also mix them: embed the hosted page in your app and use `delivery` webhooks for your own order-status screen and kitchen display.

## Edge cases

| Situation | What to do |
| - | - |
| Quote expired before payment | Call [Refresh Quotes](/api-reference/order/refresh-order-quotes), then dispatch. If the new price is above what you charged, decide up front whether you absorb it or cap it with `maxDeliveryFeeCents`. |
| Guest changes the cart after quoting | [Update the order](/api-reference/order/update-order) with the new value, item count, and description. Quote again only if the store or address changed. |
| Address is out of range, or no provider is available | `quotes` comes back empty and `failedQuotes` says why. Hide delivery and offer pickup; don't let the guest pay for delivery. |
| Guest or store cancels after dispatch | [Cancel the job](/api-reference/job/cancel-job-by-job-id). You'll get a `canceled_by_customer` webhook. Provider cancellation fees can apply once a courier is assigned. |
| Provider cancels, or the delivery fails | You get `canceled_by_provider` or `failed` (see `failureReason` on the task). If auto-reassignment is on in your dispatch strategy, Nash books another provider on the same job and you'll see new task events. If not, alert the store to dispatch again. |
| Kitchen is running late | Set `pickupStartTime` from real prep time when you quote, and update the order before dispatch if the kitchen is backed up. Couriers who wait may add wait fees. |
| Large or catering orders | Send accurate `valueCents`, `itemsCount`, and size so only providers that can take the order quote it. Use `deliveryMode: "scheduled"` with a dropoff window for catering. |
| Duplicate or out-of-order webhooks | Expected. Deduplicate on `svix-id` and only move an order forward. |

## Go-live checklist

* [ ] Every restaurant is a store location with its external store number
* [ ] A dispatch strategy and automation are set, and **Enable Autodispatch** is off
* [ ] Checkout quotes only after a full address and shows the fee and ETA (or your flat fee)
* [ ] Addresses go to Nash as components (with coordinates) wherever your checkout has them
* [ ] The first quote sends only `pickupStartTime` (prep time plus buffer), and the guest's first available time is the quote's `dropoffEta`
* [ ] A later time the guest chooses goes on the update as `dropoffStartTime`, with `deliveryMode` set to `scheduled` and `pickupStartTime` set to `null`
* [ ] An empty `quotes` list hides delivery and offers pickup
* [ ] The Nash order `id` and `job.id` are saved on the POS order
* [ ] Dispatch runs once per order, after payment, with a refresh if the quote expired
* [ ] The webhook endpoint verifies Svix signatures, returns `2xx` quickly, and deduplicates on `svix-id`
* [ ] Every terminal status (`dropoff_complete`, cancels, `failed`, `expired`) updates the guest and the store
* [ ] Tested in Sandbox: quote, dispatch, a full status run, a cancel, and a provider failure
* [ ] Production API key, Org ID, and webhook endpoint are set up separately from Sandbox

## Beyond the basics

Quote, dispatch, and webhooks cover the core flow. Most other day-to-day work happens in the Nash Portal, and most of it is also in the API, so you can build it into your own systems when that fits better.

| Capability | Usually done in the Portal | API option |
| - | - | - |
| Delivery incidents and refunds | Report a damaged, missing, or late order and request a refund | [Create a delivery incident](/api-reference/job/create-delivery-incident), then track it with [Get refund requests](/api-reference/job/get-refund-requests). See [Refunds & incidents](/reference/refunds-and-incidents). |
| Cancel a delivery | Cancel from the delivery's page | [Cancel Job](/api-reference/job/cancel-job-by-job-id) |
| Portal views in your own tools | Staff use the Portal directly | Nash can embed selected Portal widgets in your ops tools or admin console. See [Need something richer?](/reference/nash-embedding#need-something-richer) |
| Workflows | Build automations in the Portal, such as alerting a store when a delivery runs late | [Create](/api-reference/workflow/create-workflow), [update](/api-reference/workflow/update-workflow), [test](/api-reference/workflow/test-workflow), and [trigger](/api-reference/workflow/trigger-workflow) workflows. See [Workflows](/reference/workflows). |
| Guest notifications | Set SMS and email templates and triggers | [Create notification triggers](/api-reference/notifications/create-notification-trigger) |
| Store locations | Add and edit restaurants | [Create or update a store location](/api-reference/store-locations/create-or-update-store-location-by-external-identifier) from your own system |
| Dispatch strategies | Set provider rules, fee caps, and auto-reassignment | [Create](/api-reference/dispatch-strategies/create-dispatch-strategy) and [update](/api-reference/dispatch-strategies/update-dispatch-strategy) strategies |

For more advanced builds, such as embedded ops tooling, custom workflows, or syncing refunds into your finance systems, reach out to your Nash team or [support@usenash.com](mailto:support@usenash.com).

## Related

<CardGroup cols={2}>
  <Card title="Sample checkout workflow" icon="cart-shopping" href="/guides/checkout-workflow">
    The general quote, update, dispatch, and track pattern for any checkout.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/reference/webhooks">
    Event types, payload shape, signature verification, and retries.
  </Card>

  <Card title="Delivery status" icon="list-check" href="/reference/delivery-status">
    Every normalized status, terminal statuses, and the guaranteed order.
  </Card>

  <Card title="Embed live tracking" icon="map-location-dot" href="/reference/nash-embedding">
    Put Nash's hosted tracking page inside your app or site.
  </Card>
</CardGroup>
