Empowering Restaurants through Integration

Follow

Create Order Submission

For a given location, Grubhub passes parameters that identify which menu items and options a user would like to order (using the identifiers returned from the "Show Menu" call) along with:

Grubhub expects a response (presented to the user) with the

The order submission request payload closely resembles the order validation request payload. Grubhub only sends one order submission request, but may send multiple order validations. The order submission reflects the last corresponding order validation request sent. The order submission is an indication for the provider to send this order down to their Point-of-Sale and begin prepping the order for completion.

 

Request Endpoint

POST /locations/:provider_location_id/order_submissions

 

Example Request Body

{
  "order_submission": { 
    "desired_ready_time": "2016-03-11T11:44:08",
"force_prices": false, "fulfillment_type": "pickup",
"calculated_tax": 0,
"grubhub_order_number": "430515324805810", "items": [ { "item": { "category_group_id": "6734384", "category_id": "11124", "name": "Turkey Sandwich", "price": 679, "provider_id": "1324", "quantity": 1, "recipient_name": "Joe Smith", "metadata": { "integration_id_needed_for_submission": "1234" }, "special_instructions": "Hold the mayo", "options": [ { "option": { "metadata": { "integration_id_needed_for_submission": "1111" }, "price": 100, "option_group_display_order": 4, "provider_id": "67478", "option_group_id": "565", "quantity": 2 } }, { "option": { "price": 0, "option_group_display_order": 2, "provider_id": "32791", "option_group_id": "577", "quantity": 1 } } ],
"tax_rate": "0.07" } }, { "item": { "category_group_id": "6734384", "category_id": "75759", "name": "Slice of cake", "price": 199, "provider_id": "9876", "quantity": 2, "recipient_name": "Jane Smith", "options": [ { "option": { "price": 0, "option_group_display_order": 1, "provider_id": "62459", "option_group_id": "123", "quantity": 1 } } ],
"tax_rate": "0.07" } } ], "location_time_zone": "America/New_York", "metadata": { "revel_authentication_token": "asdf232342453asdTSfs" }, "paid_via_ach": false,
"paid_via_ach": true,
"prepaid": true, "tip": 100, "merchant_funded_discount": 100, "special_instructions": "please double bag my order", "include_disposable_utensils": true, "user": { "born_at": "1986-03-11T11:44Z", "first_name": "joe", "gender": "male", "last_name": "smith", "email": "example@gmail.com", "password": "password123", "phone": "4445556666" }
"uuid": "4h3834000f1c0545c8d823da5a47e0b8" } }

 

Example Response Body

{
  "order_submission": {
    "order_id": 15612,
    "tax": 123,
    "total": 978,
    "tip": 100,
    "provider_funded_discount": 100,
    "merchant_funded_discount": 100,
    "service_fee": 50,
    "expected_ready_at": "2016-03-11T11:44:08",
    "metadata": {
      "authentication_token": "asdf232342453asdTSfs"
    }
  }
}

 

Example Request Body (Restaurant Self-Delivery)

{
  "order_submission": {
    "delivery_fee": 300,
    "delivery_address": {
      "street_address": "One Federal Street",
      "extended_address": "Floor 6",
      "locality": "Boston",
      "region": "MA",
      "postal_code": "02110",
      "latitude": 42.356257,
      "longitude": -71.057225,
    "desired_ready_time": "2016-03-11T11:44:08",
"force_prices": false, "fulfillment_type": "delivery", "grubhub_order_number": "443213323803422",
"calculated_tax": 0, "items": [ { "item": { "category_group_id": "6734384", "category_id": "11124", "name": "Turkey Sandwich", "price": 878, "provider_id": "1324", "quantity": 1, "recipient_name": "Joe Smith", "options": [ { "option": { "metadata": { "integration_id_needed_for_submission": "1111" }, "price": 100, "option_group_display_order": 2, "provider_id": "67478", "option_group_id": "565", "quantity": 2 } } ],
"tax_rate": "0.07" } } ], "location_time_zone": "America/New_York", "merchant_funded_discount": 100, "metadata": { "revel_authentication_token": "asdf232342453asdTSfs" }, "paid_via_ach": false,
"paid_via_ach": true,
"prepaid": true, "special_instructions": "sauce on the side", "include_disposable_utensils": false, "tip": 100, "user": { "born_at": "1986-03-11T11:44Z", "first_name": "joe", "gender": "male", "last_name": "smith", "email": "example@gmail.com", "password": "password123", "phone": "4445556666" },
"uuid": "3bff033014c3013921b85e87feee5a7c" } }

 

Example Response Body (Restaurant Self-Delivery)

{
  "order_submission": {
    "order_id": 15612,
    "delivery_fee": 300,
    "tax": 123,
    "total": 978,
    "tip": 100,
    "provider_funded_discount": 100,
    "merchant_funded_discount": 100,
    "service_fee": 0,
    "expected_ready_at": "2016-03-11T11:44:08",
    "metadata": {
      "authentication_token": "asdf232342453asdTSfs"
    }
  }
}

 

Errors

If errors occur, Grubhub expects a response in the format:

{
  "error": {
    "type": "provider",
    "message": "ITEM NOT AVAILABLE ERROR: Italian B.M.T.",
    "error_details": {
      "failed_items": [
        {
          "provider_id": "/Cart/Product2.aspx?ID=30106&gID=3",
          "name": "Italian B.M.T."
        }
      ]
    }
  }
}

 

Error Types

Site Errors: 422 HTTP status code

The underlying merchant ordering site renders an error that would have been displayed to the user to explain something like "Sorry, this location is closed right now" or "Oh no! We're out of guacamole". In this case, please return the actual error message the site renders to the user, an error code of 422.

Item Or Option Unavailable Errors: 422 HTTP status code

This is a subset of the case above, but should be handled with the following criteria in
mind:

Integration Errors: 500 HTTP status code

If your service cannot interact with the merchant for some reason, please pass back a relevant message to help us understand what's going wrong along with an error code 500. Grubhub displays its own error message to the user.

This should include the scenario when the underlying merchant is non-responsive, i.e. perhaps their location ordering provider is down, in which case your integration lets Grubhub know so we can communicate to the user.

Parameter Errors: 500 HTTP status code

If we send you parameters that do not match your expectations and a message telling
us the error. This error will not be shown to the user, but may be used for informing us
we need to refresh our menu for the location. Send an error code of 500.

Menu Not found: 404 Error Code

If Grubhub attempts to issue a call and the merchant/location is no longer available from the provider (whether temporarily or permanently), subsequent requests from Grubhub for actions on that merchant should return a 404.

Service Down

If your service is down, Grubhub returns a generic error to the user, Error code 500.

Timeout Threshold

Order validation request expects a response within 25 seconds.

 

Payment

All Grubhub orders are prepaid and paid via ACH (Automated Clearing House). Grubhub will not send any payment information. Please consult with your Grubhub Account Advisor for information regarding payment reconciliation.

 

Amounts

All amounts are always in cents.

 

Handling Nested Options

Please note that Grubhub will return options in a "flattened" fashion in our ordering requests. This means that all options selected within an item will be returned on the same level, including the nested options. This will be returned by display order within the option group and display order within the option. The order of the options is similar to what is displayed and selected by the diner.

Grubhub returns the parent option group as option_group_id , which can help identify the nested option leveling.

 

Negative Options

Grubhub does not return any option groups or options that were NOT selected by the diner. We suggest adding a separate option group for negative options such, as "Remove Toppings".

 

Utensils Support

By default, all Grubhub orders have include_disposable_utensils set to "true". When a diner opts out of receiving utensils via the Grubhub Marketplace UI, the order payloads reflect this by sending include_disposable_utensils as "false" . This is sent on both the Order Validation and Order Submission request payload.

 

Ready Times

For the order_submission response, if the merchant doesn’t give an actual ready time for an order, please still include the expected_ready_at attribute, just have it be null. We only want it if an actual order ready time estimate is returned from the merchant. In the case Grubhub receives an expected_ready_at of nil we will generate our best estimation.

 

Special Instructions

Special_instructions on both the order and items are optional. If either is included in the post, they should be submitted along with the order. If they are omitted, then you don’t need to do anything relating to special instructions. Please also account for cases where “special_instructions”: null included is in the post.

Also note that, for delivery orders only, the delivery_address may include delivery_instructions for the driver such as Ring doorbell or Leave order on porch.

 

Order ID

This should be from the merchant (if available) to assist our users in retrieving their orders. String/integer are both accepted.

 

Handling Changes Between OV and OS

There are scenarios when certain attributes (special instructions on the order level, tips and desired_ready_time) may change between the OV and the OS. In this case, Grubhub will send order-scoped metadata to detail which attributes are changing. In this scenario, please update the relevant attributes on the providers cart before submitting the order.

In scenarios where the OV and OS are handled entirely separately (i.e. an OV redoes an OS) this should happen naturally.

In scenarios where you take advantage of a server-side cart and echo that token back to us, you either need to: