Order Validation

Provider Enablement / Endpoints

Create Order Validation

For a given location, LevelUp will pass 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 a desired ready time in the timezone of the location (ISO8601), a tip amount, user details (name, phone number, email), any stored metadata (which may include other login credentials if an account was created previously), and a discount amount (if applicable). We expect a response with the final amount, applicable taxes, the soonest time at which the order could be available (in the local timezone of the location and ISO8601), which will be presented to the user.

Request Endpoint

POST /locations/:provider_location_id/order_validations

Example Request Body

{
  "order_validation": {
    "desired_ready_time": "2016-03-11T11:44:08",
    "items": [
      {
        "item": {
          "category_id": "11124",
          "category_group_id": "6734384",
      "name": "Turkey Sandwich",
          "provider_id": "1324",
          "quantity": 1,
      "metadata": { "integration_id_needed_for_validation": "1234" },
          "special_instructions": "Hold the mayo!",
          "options": [
            {
              "option": {
                "provider_id": "67478",
                "option_group_id": "585",
                "quantity": 2
              }
            },
            {
              "option": {
                "provider_id": "32791",
                "option_group_id": "596",
                "quantity": 1
              }
            }
          ]
        }
      },
      {
        "item": {
          "category_group_id": "6734384",
          "category_id": "75759",
          "name": "Slice of cake",
          "provider_id": "9876",
    "metadata": { "integration_id_needed_for_validation": "1234" },
          "quantity": 2,
          "options": [
            {
              "option": {
                "provider_id": "62459",
                "option_group_id": "334",
                "quantity": 1
              }
            }
          ]
        }
      }
    ],
    "metadata": {},
    "tip": 100,
    "special_instructions": "please double bag my order",
    "user": {
  "born_at": "1986-03-11T11:44Z",
      "first_name": "joe",
      "gender": "male",
      "last_name": "smith",
      "email": "example@gmail.com",
      "password": "password123",
      "phone": "4445556666"
    }
  }
}

Example Response Body

{
  "order_validation": {
    "available_at": [
      "2016-03-25T15:20:00Z",
      "2016-03-25T15:40:00Z",
      "2016-03-25T16:00:00Z",
      "2016-03-25T16:20:00Z",
      "2016-03-25T16:40:00Z",
      "2016-03-25T17:00:00Z",
      "2016-03-25T17:20:00Z",
      "2016-03-25T17:40:00Z",
      "2016-03-25T18:00:00Z"
    ],
    "tax": 123,
    "total": 978,
    "tip": 100,
    "soonest_available_at": "2016-03-11T11:44",
    "provider_funded_discount": 200,
    "metadata": {
      "authentication_token": "asdf232342453asdTSfs"
    }
  }
}

Payment Methods

There are two methods of LevelUp paying for an order.

  • LevelUp As Tender: In this method, LevelUp will pass in simply “LevelUp” as the tender method, and using our API key for access to your systems, you will demarcate the order as paid for via LevelUp. We will pay the merchant directly via ACH next day.

  • Single Use Credit Card: LevelUp can pay any merchant indirectly, by passing to you a single-use credit card that we generate in real-time, and then charge the consumers card on file out-of-band via our secure vault. To you, that single-use corporate card looks just like a normal user card, but in reality, it’s a unique real-time generated single use token (card) that we pass to you to mirror your existing customer credit card payment flow.

Amounts

All amounts are always in cents.

Handling Nested Options

Please note that LevelUp will return options in a “flattened” fashion in our OV/OS requests. So if you believe that a given ordering provider will require that options be presented in a nested fashion, you will need to encode that nesting logic into your menu response to use, demarcating option ids and their parent option groups using some delimiter such as “:” or “-”. I.E. parent_option_group:option_id so that you can parse it back out as needed.

Handling Time Values

There are three options for how you pass back the date-time:

  • Local Times (preferred): Pass back the datetimes as the time you get back from the provider (after confirming that that is the location’s timezone) and should be formatted YYYY-MM-DDTHH:mm.

  • Named Time Zone: Pass back the datetimes as the time you get back from the provider including the timezone, this is likely in UTC and thus will be appended with a Z and should be formatted YYYY-MM-DDTHH:mmZ. We’ll convert it to the local time on our end.

  • Relative Time: If the provider only gives you back a “N minutes from now” pass that back to us as expectedreadyat + 30 minutes from your server’s timezone, and denote that timezone. This will often be very similar to the case above and should be formatted YYYY-MM-DDTHH:mmZ.

Handling Tips

LevelUp should only be passing in tip values for places that accept tips, as identified on the locations endpoint. However, if LevelUp passes in a tip for a place that does not accept tips, please return the tip attribute to us as null. We’ll interpret that as 0 for the transaction in question, but it will also trigger us to change our settings for that location’s ability to accept tips.

Total, Tax, Tip and Merchant or Provider Funded Discounts

The math behind an order can be a little confusing, so here are how the terms tax, tip and total are to be defined. As a reminder, all values are always in cents.

  • Tax = the sales tax on the order

  • Tip = the tip the user submitted, i.e. what we sent in to you can mostly just be echoed back to us

-If the site doesn’t allow tips, or the tip fails, return null. This is either an integration issue or a config issue as whether or not a location accepts tips should be defined on the menu for the location.

  • Merchant_Funded_Discount: If the merchant is running a discount through the LevelUp Platform, we will post the total discount value here, so it can be used in tax calculations.

  • Provider_Funded_Discount: If you are offering a provider funded discount, please return that here.

  • Total = the amount spent on food and does not include the tax or tip and specifically excludes any provider_funded_discount or merchant_funded_discount

As an example, a $10 sandwich with a $2 tip and $0.70 sales tax and a $1 merchantfundeddiscount would have the following values:

  • Tax = 70 cents

  • Tip = 200 cents

  • Merchant_Funded_Discount = 100 cents

  • Total = 1000 cents

The total the consumer would be charged (which is not expected to be returned in the API to us) would be $11.70.

The total that LevelUp would end up paying to the merchant would be $11.70 since the $1 merchant funded discount is funded by the merchant.

Ready Times & Scheduling of Orders

  • If the desired_ready_time is nil, the order should be validated to be placed ASAP.

-If the desired_ready_time is nil, and the location is closed, please attempt to schedule the order for the soonest available ready_time and return that along with the array of available ready times after that. Please be sure to include the full timestamp (inclusive of days) as this case is likely to span days.

  • When a desired_ready_time is included in the validation request, the order should be validated with a pick up time scheduled to the desired_ready_time.
    • Will always be in the locations time zone
    • In the case when a merchant only allows order scheduling on specific timeslots, the order should be validated to be picked up at the soonest timeslot available after the desiredreadytime and that timeslot should be returned as the soonest_available_at.
    • If the merchant allows scheduling and does not require users to pick specific time slots, and a desiredreadytime is provided, the desiredreadytime should be returned as the soonest_available_at.

Note that when the order is placed to be picked up ASAP (desired_ready_time=nil), we expect the soonest_available_at time to you as a parseable time-stamp in the local time of that location. That’s the most useful time for us to receive and what we’ll show to the user.

If the merchant doesn’t give an actual ready time that can be returned to us as a date-time, please include the ready_at attribute, but have it’s value be nil. We only want the most accurate value if a real time is returned otherwise LevelUp will sub one in based on our best guesstimate. You returning nil will be our key to do that. So, if the merchant just says “ASAP” return nil. If they say “In 10 minutes” or some other bit of text you can’t parse, just return nil.

Available At Times

For merchants that support order scheduling but require orders to be scheduled for particular time slots, an array of available_at times should be returned. Only available time slots after the desired ready time and within 24 hours of the validation time should be returned in the available_at array. If ordering is available for any time after the soonest_available_at time, an available_at value of nil should be returned. The available_at array should also be nil for providers that do not support order scheduling. Available time zones should be returned either as local timestamps (YYYY-MM-DDTHH:mm) or timestamps with a timezone (YYYY-MM-DDTHH:mmZ).

Account Credentials

LevelUp prefers to checkout as a guest when possible. However, if you are creating a user account and returning account credentials that you’d like us to store, please name them as follows: user_[whatever you prefer]. So for example it could be user_username and user_password or user_name and user_auth_key. We simply use the fact that it’s prefaced with “user_” to know to store it in a persistent fashion. This is in comparison to data that should only be stored in the context of a single order (like cart_ids) which are prefixed with order_ and described in more detail below.

Add Ons

LevelUp has it’s own merchant-controlled logic for upsells, so there’s no need to return to us existing upsell logic unless specifically requested by the merchant.

Optional Cart_ID Optimization

If you would like to include a cart_id, or some other identifier that you get back after the validate order call. To make the submit order call faster, you can echo that information back to LevelUp in the metadata response attribute, and we will send it along on the proceeding submit call. For example, if you sent us back the following on the validate call:

{
  "metadata": {
    "order_user_token": "a694d3bc-151b-48b0-bb92-a557106b0019",
    "order_cart_token": "d1e19c7b-e63a-4fb4-8896-912d12e1d15d"
  }
}

You would get it back on the submit call and could use it to pull back up the cart without recreating it from scratch. This might save a lot of time for you on the submit call.

Some things to note if you take this approach:

  • We will always still create a brand new cart on the validate call

  • If the necessary information is not received on the submit order call, (say due a timeout if your order validation call didn’t respond in time) you will need to be ready to still create the cart from scratch on submit.

  • Please always prefix your order-specific metadata with “order_”. This will let us know to clear it out before sending you a new validate order request, but persist it for the following submit order request. Order_ scoped metadata is persisted only for the order while User_ metadata is persisted long-term.