Skip to main content

Implement last mile delivery

Learn how to implement a last mile delivery workflow. You can try out this tutorial in your development environment.

note

While this tutorial shows you how to create an order, the order you create is sent to a development version of the Fulfillment engine. You don't need to worry about groceries showing up at the example address we use!

To support your development efforts, this tutorial also includes tips and best practices to consider when you implement the workflow in a production environment.

  1. Before you begin
  2. Find store locations near the customer
  3. Create a Connect user account
  4. Fill a cart
  5. Understand changes required in the checkout process
  6. Reserve a time slot for delivery
  7. Create the order
  8. What happens to an order in a production environment?
  9. Summary

Before you begin#

For this tutorial, you need the following items:

If store locations are not yet in your development environment, contact your Instacart Connect representative.

Variables used in this tutorial#

The following variables are used in requests in this tutorial. When you see a variable, substitute them with values that work in your development environment.

VariableDescription
<instacart_development_domain>The domain of your assigned Instacart development server, such as connect.dev.instacart.tools.
<token>The generated access token.
<location_code>After you find stores, select one to use in this tutorial. You'll need this value when you create an order.
<service_option_id>After you find available time slots, select one to use in this tutorial. You'll need this value when you reserve a time slot.
<service_option_hold_id>After you reserve the time slot, note the ID. You'll need this value when you create the order.

The responses in this tutorial show sample values in place of the variables. The responses that are returned in your environment should have a similar format to the example responses. If you are interested in other possible responses, see the API documentation.

Find store locations near the customer#

By default, if a store location is defined in your environment, a customer can request last mile delivery from it. Pickup only stores are omitted from the response.

Find the stores offering delivery near the specified address. In the request, substitute your values for the variables <instacart_development_domain> and <token>. If you don't have stores near this address, substitute an address that you know is close to one of your stores.

curl --request POST \  --url https://<instacart_development_domain>/v2/fulfillment/lastmile/stores/ \  --header 'Accept: application/json' \  --header 'Authorization: Bearer <token>' \  --header 'Content-Type: application/json' \  --data '{  "find_by": {    "address_line_1": "50 Beale St",    "postal_code": "94105"  }}'

The response contains the array of store locations near the address.

{    "stores": [        {            "name": "Example Location 1",            "location_code": "123-4567",            "flags": {                "alcohol": true,                "pickup": false,                "pickup_only": false            }        },        {            "name": "Example Location 2",            "location_code": "123-4678",            "flags": {                "alcohol": true,                "pickup": false,                "pickup_only": false            }        },        {            "name": "Example Location 3",            "location_code": "123-4789",            "flags": {                "alcohol": false,                "pickup": false,                "pickup_only": false            }        }    ],    "is_partial": false}

From the response returned in your development environment, choose a store to use in this tutorial. You'll substitute the location code for the variable <location_code> in requests.

Production environment tip

When you get the list of stores, you can either choose a store location for the customer or allow the customer to select a store location where they want to shop. You can think of the selected store as the inventory store. If your retailer site passes this store location when it creates an order, the store location is also likely to be the fulfillment store.

Create a Connect user account#

Create the Connect user account and validate the customer's address. The Connect user account contains the minimum information required by Instacart to create and fulfill an order. The account must have at least a unique user ID and the customer address. The user ID is defined by you, but it must be unique for all retailer customers. For example, you might choose user names or loyalty card IDs.

Create the user account and validate the address. In the request, substitute your values for the variables <instacart_development_domain> and <token>.

curl --request POST \    --url https://<instacart_development_domain>/v2/fulfillment/lastmile/validate_address \    --header 'Accept: application/json' \    --header 'Authorization: Bearer <token>' \    --header 'Content-Type: application/json' \    --data '{    "address_line_1": "50 Beale St",    "postal_code": "94105",    "user_id": "kamalsingh1234"}'

A successful JSON response has the status code 200 and the following fields:

{  "address": {    "address_line_1": "50 Beale St",    "postal_code": "94105"  },  "user_id": "kamalsingh1234"}

If the user account already exists, for example if you or someone else has tried this tutorial on your development environment recently, the request returns the status code 400 User already created. You can continue the tutorial with this ID or call the method again with a different user ID.

Production environment tips
  • Save the generated user ID with your other customer account information and reuse it for all orders by that customer. It is up to you to ensure the user ID remains unique and associated with the correct customer. If the same ID is used for multiple customers, you risk introducing security and privacy concerns.
  • Optionally, you can use two calls instead of one: Create a Connect user account and Validate an address.

Fill a cart#

To create an order, you need a cart with some items in it. Use your development environment to add an item to the cart that is available at the selected store.

Understand changes required in the checkout process#

During the checkout process, your storefront needs to include prompts to collect the information necessary to create an order. For this tutorial, the Create a delivery order request contains sample values for these items.

The information to collect before you create an order includes:

  • A valid delivery address.
  • Confirmation to leave the delivery unattended. Default is false.
  • Confirmation if Electronic Benefits Transfer (EBT) is used as a payment method. Default is false.
  • Loyalty card number. (optional)
  • Special instructions. (optional)
  • Tip amount.
  • If a cart contains alcohol, the customer's date of birth. The customer must be old enough to legally purchase alcohol in their region. Advise the customer that they must show identification with their date of birth when the order is delivered and that alcohol cannot be left unattended.
  • If you want to update your customer based on the callbacks your site receives about the status of the order, ask your customer to opt in to receiving SMS notifications.

Near the end of the checkout process, your storefront needs to handle the following tasks:

  • Display the order details for review, and enable a customer to change items or update any of the collected information.
  • Prompt for payment. Reserve the payment amount but wait to process the payment until after your site receives a callback to confirm that the order was delivered. Refunds might affect the total cost of the order.
  • Prompt the user to select a time slot, as described in the next step.

Reserve a time slot for delivery#

Before you can reserve a time slot, you need to retrieve a list of available time slots. After the customer selects a time slot, you can reserve a time slot for 10 minutes.

Retrieve the list of available time slots. In the request, substitute your values for the variables <instacart_development_domain> and <token>.

curl --request POST \    --url 'https://<instacart_development_domain>/v2/fulfillment/lastmile/service_options' \    --header 'Accept: application/json' \    --header 'Authorization: Bearer <token>' \    --header 'Content-Type: application/json' \    --data '{        "postal_code": "75041",        "cart_total_cents": 5400,        "items_count": 12}'

The response contains a list of available time slots. Timestamps are returned in Coordinated Universal Time (UTC).

{    "service_options": [        {            "id": 3310259,            "date": "2021-06-22",            "window": {                "immediate_hour": 2            },            "availability": {                "available": true,                "reasons": [],                "item_codes": []            }        },        {            "id": 10358918,            "date": "2021-06-22",            "window": {                "immediate_hour": 5            },            "availability": {                "available": true,                "reasons": [],                "item_codes": []            }        },        {            "id": 439844911,            "date": "2021-06-22",            "window": {                "start_at": "2021-06-23T02:00:00Z",                "end_at": "2021-06-23T04:00:00Z"            },            "availability": {                "available": true,                "reasons": [],                "item_codes": []            }        },    ...  ]}

From your response, choose a time slot to use in this tutorial. You'll substitute the ID for the variable <service_option_id> in the next request.

Reserve the time slot. In the request, substitute your values for the variables <instacart_development_domain>, <token>, and <service_option_id>.

curl --request POST \    --url 'https://<instacart_development_domain>/v2/fulfillment/lastmile/users/kamalsingh1234/service_options/<service_option_id>/reserve' \    --header 'Accept: application/json' \    --header 'Authorization: Bearer <token>' \    --header 'Content-Type: application/json'

The response contains the details about the reserved time slot with the service option hold ID 357941827.

{    "service_option_hold": {        "id": 357941827,        "expires_at": "2021-06-22T20:58:33Z",        "service_option": {            "id": 10358918,            "date": "2021-06-22",            "window": {                "immediate_hour": 5            },            "availability": {                "available": true,                "reasons": [],                "item_codes": []            }        }    }}

From your response, note the service option hold ID. You'll substitute this value for the variable <service_option_hold_id> when you create the order. The reservation is held for 10 minutes. To book the time slot, create the order.

Production environment tips
  • Convert the UTC timestamps to the customer's time zone before displaying the time slots.
  • To avoid disappointing your customers, make the reservation as close to the end of the checkout process as possible. If a reservation expires before the order is created, Connect still attempts to book the time. Generally speaking, time slots have capacity for more than one order. If, however, the time slot capacity is fully booked, your storefront needs to prompt your customer to select a different time slot.
  • If your retailer site enables customers to change a reserved delivery time slot, send the request again with the new time slot. Connect expires the previous time slot and uses the new one. A user account can have only one time slot reserved.

Create the order#

Send a request to create an order as soon as possible after reserving the time slot. The order requires a retailer-generated order ID.

Create the order. In the request, substitute your values for the variables <instacart_development_domain>, <token>, <service_option_hold_id>, and <location_code>.

curl --request POST \    --url 'https://<instacart_development_domain>/v2/fulfillment/lastmile/users/kamalsingh1234/orders' \    --header 'Accept: application/json' \    --header 'Authorization: Bearer <token>' \    --header 'Content-Type: application/json' \    --data '{    "order_id": "xyz123456",    "service_option_hold_id": "<service_option_hold_id>",    "location_code": "<location_code>",    "locale": "en-US",    "first_name": "Kamal",    "last_name": "Singh",    "user_phone": "800-555-0101",    "initial_tip_cents": 200,    "items_count": 12,    "bags_count": 3,    "items_weight": 15,    "cart_total": 5400,    "alcoholic": false,    "leave_unattended": true,    "special_instructions": "Ring the doorbell.",    "address": {        "address_line_1": "50 Beale St",        "postal_code": "94105"    }}'

The response contains details about the order with the order ID xyz123456.

{    "id": "xyz123456",    "status": "brand_new",    "order_url": "https://<instacart_development_domain>/s/dWl2N3U1d203",    "created_at": "2021-06-22T20:57:22Z",    "cancellation_reason": "",    "locale": "en_US",    "fulfillment_details": {        "store_location": "123-4789",        "window_starts_at": "2021-06-22T20:57:21Z",        "window_ends_at": "2021-06-23T01:57:21Z"    }}
Production environment tip

It can take several seconds to receive confirmation that the order is created. For your storefront, consider what you want to show to the customer while they wait for confirmation.

What happens to an order in a production environment?#

As previously mentioned, an order created in a development environment is not fulfilled. To complete this tutorial, let's review what happens to orders created in a production environment.

In a production environment, a retailer employee receives the order. Based on the selected time slot, the employee shops for the order. Optionally, the retailer site can provide a way for the customer to update an order or cancel an order.

When the order is ready, the employee brings the bags to a staging area. Your retailer site calls the Stage an order endpoint, which updates the order status to staged. The order is batched for delivery during the selected time slot. The assigned Instacart shopper picks up and delivers the order.

important

Instacart dispatches an Instacart shopper only after the order status is set to staged. To ensure the delivery is made within the selected time slot, be sure to stage orders with enough lead time for an Instacart shopper to get to the store, pick up the order, and arrive at the customer's location.

tip

You can get the order status for the user account, including the order status, with the Get an order method.

Summary#

In this tutorial, we found stores near a customer that offered delivery, created a user account, and validated the address. Then we learned what information needs to be collected during checkout. We reserved a time slot and created an order. Finally, we discussed what happens in a production environment while the order is in the fulfillment process.