Integration Details

Authentication

The Availability API uses oauth2 for authentication. Before making a request you will need to retrieve an access token, this can be done by calling the “Get token” endpoint.

API Documentation: Get a token | Availability API

Example Request:

POST

{
  "grant_type": "client_credentials",
  "client_id": "{{Your client ID}}",
  "client_secret": "{{Your client secret}}",
  "scope": "availability-api",
  "businessId":"{{If omitted, will default to Snappy}}"
}

Each access token is only active for a set amount of time, once it expires a new token will need to be generated using the provided refresh token.

You will be provided with your client IDs and secrets via 1password secure links at the appropriate stages of development, this is normally as follows;

  • Staging - at the start of development
  • Live - once the integration has been verified

Authorisation

When we connect stores to your integration, we use your unique ID to identify the store. This is passed along with each request you make as the “thirdPartySiteId” field.

It is important that this field is included so we can update the correct store, requests sent without this field will be rejected.

Job Management

Each request made to the Availability API is handled asynchronously, a job id will be returned when the initial request is made which you can use to check the status of the job. This can be done by calling the “Import Status” endpoint.

API Documentation:  Check the status of an import job | Availability API

Example Request:

POST

Headers: 
- bearer_token: "{{Your access token}}"

{
  "jobId": "{{Your job ID}}"
}

Flagging Products

In your EPOS system, a way of tagging products and promotions should be provided. This allows retailers to have a granular choice of what products and promotions should be shown on the Snappy platform.

Product Management

When referencing products, please use globally recognised barcode standards where possible.

i.e. EAN-13, EAN-8, UPC

Adding Products

Products can be added using the “Add a product” endpoint or by the "Quick Update" endpoint.  Multiple products can be added at once.

API Documentation:  Add a Product | Availability API

Example Request:

POST

Headers:
- bearer_token: "{{Your access token}}"

{
  "thirdPartySideId": "{{The store's unique ID}}",
  "eans": [
    {
      "ean": "{{The barcode or PLU of the product}}",
      "price": {{The price of the product, decimal}},
      "name": "{{The name of the product}}"
    }
  ]
}

Products can also be added using the “Quick Update” endpoint, the details are below.

Updating Products

Updates to products can be done via the “Quick Update“ endpoint, this is the core endpoint of the integration and allows the updating of all product attributes including;

  • Price
  • Category
  • Availability (stock)
  • Promotions & meal deals
  • Visibility

Multiple products can be updated at once.

API Documentation:  Update a subset of store products | Availability API

Example Request:

POST

Headers:
- bearer_token: "{{Your access token}}"

{
  "thirdPartySideId": "{{The store's unique ID}}",
  "eans": [
    {
      "ean": "{{The barcode or PLU of the product}}",
      "price": {{The price of the product, decimal}},
      "wasPrice": {{Original price, used to reflect if the item's price has been reduced, decimal}},
      "inStorePrice": {{The price the product is sold at in store}},
      "outOfStockToday": {{If set, this will mark the item as out of stock for 1 week}},
      "hidden": false,
      "categories": {
        "category1": "{{Category name}}",
        "category2": "{{Sub-category name}}"
      },
      "stock": {
        "EnableStock": {{Turns on stock control for this item}}
        "CurrentStock": {{The current stock level}}
        "ReserveStock": {{This is a buffer, item will be marked as out of stock when the stock hits this value}}
      },
      "promotions": [
        {
          "id": "{{Your promotion ID}}",
          "description": "{{Your promotion description}}",
          "qtyThreshold": {{The number of products required to trigger the promotion}},
          "fixedPrice": {{The price for the product when the promotion is applied}},
          "discountQty": {{The number of products that should be charged for}},
          "startDate": "{{The date the promotion starts}}",
          "endDate": "{{The date the promotion ends}}"
        }
      ],
      "mealDeal": {
        "id": "{{Your meal deal ID}}",
        "description": "{{Your meal deal description}}",
        "qtyThreshold": {{The number of deal sets required for the deal to apply}},
        "fixedPrice": {{The price of the deal}},
        "sectionName": "{{The product's section name i.e. "Drinks"}}",
        "startDate": "{{The date the deal starts}}",
        "endDate": "{{The date the deal ends}}"
      },
    }
  ]
}

Categories, promotions and meal deals are covered in more detail later in this document.

There are 2 flags that can be used to modify the effects of this endpoint.

fullUpdate - This flag treats the request as the entire menu for a store. If this flag is set to true, any products not included in the request will be marked as hidden automatically. Full updates should not be used frequently, they should be sent as part of a full menu refresh only. 

allowAdd - This flag allows new products to be included in the request alongside other updates without needing to call the “Add a product” endpoint separately.

Product Availability

In addition to products being able to be marked as “out of stock” or “in stock” using the “outOfStockToday“ parameter in the “Quick Update” endpoint, this can also be done through a dedicated endpoint, “Update Product Availability”.

If you do not know when the item will be back in stock, set a generous returnDate. If not included the item will be marked back in to stock tomorrow.

API Documentation:  Update Product Availability | Availability API 

Example Request:

POST

Headers:
- bearer_token: "{{Your access token}}"

{
  "thirdPartySideId": "{{The store's unique ID}}",
  "status": "instock", // "outofstock"
  "eans": [
    {
      "ean": "{{Product barcode}}",
      "returnDate": "{{Expected product return date}}" // optional
      "statusOverride": "{{If this specific item is in or out of stock, overrides the global 'status' value.}}" // optional
    }
  ]
}

Promotions Management

Promotions can be handled against the individual product in the “Quick Update” endpoint or by using the dedicated promotion management endpoint Add or update promotions for a store | Availability API. We do not recommend using both methods in the same integration.

We have 4 promotions types, which are listed below:

  • “n for n” - i.e. 3 for 2
  • “n for price n” - i.e. 3 for £5
  • “percentage off” - i.e. 25% off (Only supported on the promo management endpoint)
  • “amount off” - i.e. £1 off (Only supported on the promo management endpoint)

We have 2 meal deal types, which are listed below:

  • “meal deal” - a number of products from the same group for a fixed price (i.e. 5 freezer items for £5)
  • “multi-section meal deal” - same as meal deal, but the products are split into sections (i.e. a traditional “Main”, “Drink” and “Snack” meal deal). The section names should be representative of the products within.

Promotions

A product can have multiple promotions assigned to it, using the “promotions” array of objects.

Example Promotions Object for the “Quick Update” endpoint:

{
  "id": "{{Your promotion ID}}",
  "description": "{{Your promotion description}}",
  "qtyThreshold": {{The number of products required to trigger the promotion}},
  "fixedPrice": {{The price for the product when the promotion is applied. Used for "n for price n" promotions}},
  "discountQty": {{The number of products that should be charged for. Used for "n for n" promotions}},
  "startDate": "{{The date the promotion starts}}",
  "endDate": "{{The date the promotion ends}}"
}

Each field has a specific meaning depending on the type of promotion, detailed below:

Field Usage
id

Your unique ID for the promotion, used to ensure we update the correct promotion.

Note: meal deal and promotion IDs are considered to be in the same group when determining uniqueness.

description A name of the promotion, this will be displayed on the products in the promotion.
qtyThreshold Used for “n for price n” and “n for n” promotions, indicates the number of items required to trigger the promotion.
fixedPrice Used in “n for price n” promotions, indicates the price for the items when the promotion is applied.
discountQty Used in “n for n” promotions, indicates the number of items that should be charged for when the promotion is applied.
startDate The date the promotion should start showing on the platform.
endDate The date the promotion should finish showing on the platform.

Promotions can also be removed from a product by including the promotion ID in the “Quick Update” request under the “removeFromPromotions” parameter.

Meal Deals

Presently, only 1 meal deal can be provided for a product, this should be supplied in the “mealDeal” object.

Example Meal Deal Object:

{
  "id": {{Your meal deal ID}},
  "description": "{{Your meal deal description}}",
  "qtyThreshold": {{The number of deal sets required to apply the deal}},
  "fixedPrice": {{The price of the meal deal}},
  "sectionName": "{{The name of the section the product should be in}}",
  "startDate": "{{The date the meal deal starts}}",
  "endDate": "{{The date the meal deal ends}}"
}

Each field has a specific meaning depending on the type of meal deal, detailed below:

Field Usage
id Your unique ID for the meal deal, used to ensure we update the correct meal deal. Note: meal deal and promotion IDs are considered to be in the same group when determining uniqueness.
description The name of the meal deal.
qtyThreshold The number of deal sets required for the deal to apply, this is normally set to 1.
fixedPrice The price of the meal deal.
sectionName The name of the section the products fits into on the meal deal i.e. “Drinks”. Note: if the section does not exist in Snappy Group it will be automatically created.
startDate The date the meal deal should start showing on the platform.
endDate The date the meal deal should finish showing on the platform.

Meal deals can also be removed from a product by including the meal deal ID in the “Quick Update” request under the “removeFromMealDeal” parameter.

The following example object is for our dedicated Promotion management endpoint:

{
  "thirdPartySiteId": "{{The store's unique ID}}",
  "promotions": [
    {
      "id": "{{Your promotion ID}}",
      "type": "{{The type of promotion that the entry represents, provided the basis for field validation. EG nforn, nforpricen, percentoff, amountoff}}",
      "description": "{{Your promotion description}}",
      "qtyThreshold": "{{Used for "n for n" and "n for price n" promotions, indicates the number of items required to trigger the promotion. Also used for "percentage off" promotions to indicate the percentage discount.}}",
      "fixedPrice": "{{Used for "n for price n" promotions, indicates the price for the items when the promotion is applied. Also used for "amount off" type promotions, indicating the new price.}}",
      "discountQty": "{{Used for "n for n" type promotions, indicates the number of items that should be charged for when the promotion is applied.}}",
      "startDate": "{{The start date for the promotion, if not provided the promotion will start instantly.}}",
      "endDate": "{{The end date for the promotion, if not provided the promotion will not end.}}",
      "products": [
        "{{Each item in the array should be a string representation of an EAN that exists within the store. Any EANS that do not exist on the store will be ignored and an error message. Any products not included in this list will be removed from the promotion.}}"
      ],
      "disabled": "{{Disable/enable your promo}}"
    }
  ],
  "mealDeals": [
    {
      "id": "{{Your unique id for the meal deal}}",
      "description": "{{The name of the meal deal to be displayed to users.}}",
      "qtyThreshold": "{{The number of deal sets required for the deal to apply, normally set to 1.}}",
      "fixedPrice": "{{The price of the meal deal.}}",
      "sections": [
        {
          "name": "{{The name of the section that should be included in this meal deal.}}",
          "sectionQtyThreshold": "{{The number of items that can be added in this section.}}"
        }
      ],
      "startDate": "2022-11-18",
      "endDate": "2022-11-18",
      "products": [
        {
          "ean": "{{The barcode of the item to include in this section of the meal deal. The barcode must already exist on the store's menu}}",
          "sectionName": "{{The name of the section that the product fits into on the meal deal i.e. "Drinks". If the section name does not exist, it will be created. The section name must be an exact match.}}"
        }
      ],
      "disabled": true
    }
  ],
  "allowAdd": "{{Optional parameter to allow adding of missing promotions/meal deals during the update request.}}",
  "fullUpdate": "{{Treats this request as a full promotion/meal deal update. Any promotions/meals deals for the store not included in the request when this is set will be marked as hidden automatically}}"
}

Category Management

Categories are currently managed through the “Quick Update” endpoint. The current structure allows for a product to be in 2 categories at a time, with 4 levels of subcategories available.

Products can only be placed in the base-level category. As in the fruit example below, products can only be placed in “Exotic Fruit” not “Fruit & Veg”.

An example of moving a product to the following category structure is below. “Fresh Food” → “Fruit & Veg” → “Fruit“ → “Exotic Fruit”.

{
  "categories": {
    "category1": "Fresh Food",
    "category2": "Fruit & Veg",
    "category3": "Fruit",
    "category4": "Exotic Fruit"
  }
}

If we also wanted to include this product in the “Healthy Living” → “Fruit” category as well as the above “Exotic Fruit” category, we would use the following example.

{
  "categories": {
    "category1": "Fresh Food",
    "category2": "Fruit & Veg",
    "category3": "Fruit",
    "category4": "Exotic Fruit",
    "secondary_category1": "Healthy Living",
    "secondary_category2": "Fruit"
  }
}

The category name must match exactly as in the Snappy Group system, if it doesn’t no change will occur. Like energy, categories cannot be created or destroyed using this endpoint.

Get Categories

You can use the “Get Categories” endpoint to return a list of all categories currently available for a store. This list can be displayed against the item on your system allowing to user to assign Snappy categories. By utilising the above categories object via the “Quick Update” endpoint you can then return the selected category against the item.  Gets all categories for a store | Availability API

Future Development

A new endpoint will be created to manage categories and dates, details will be released once development has begun.

Order Data Collection

To get data around the orders made through Snappy Group’s platform, a webhook URL should be provided that we can send data to.

This data will be sent based on a number of triggers, which can be selected on a per-store basis. The possible triggers are listed below:

  • Order placed
  • Items substituted
  • Order delivered
  • Order collected
  • Cash collected
  • Order updated

The format of the data received is available through the following API documentation:  Receive order update | Availability API

In order to verify that the request to your webhook came from Snappy Group, we include an HMAC hash in the header of the request. This is generated using the SHA-512 algorithm and the payload provided to you, using the Client Secret from your oauth credentials as the key.

Tips

  • We recommend accepting the prices that are sent in the order to ensure what's in your POS matches what the customer paid.
  • While Snappy are working to improve this, it is possible for products to be sent without a barcode. This should be handled as much as possible when you receive the order.
  • You'll need to check the pickerStatus against each item in the order and handle it accordingly. This is dependant on which of the triggers you support in the above list. 

Request Frequency

When deciding on the frequency of requests to an endpoint, the minimum amount of time between requests is 5 minutes. This limitation is per store, per endpoint. More than 1 request can be made in a 5-minute period as long as it is for a different store or is to a different endpoint.

Rate limiting is in place to enforce this limit, any requests made over the limit will return a “429: Too Many Requests” response with the thirdPartySideId includes in the body. This is not considered to be an error.

For product and promotion updates, we recommend checking for updates in your system at your chosen frequency (i.e. every 5 minutes) and sending 1 request per store that contains all updates required.

Verification Process

Once your integration has been completed, Snappy Group will verify the integration to ensure it meets our minimum standards. This will be done in addition to any integrator testing, we encourage internal testing of the integration before beginning the verification process.

The verification process will consist of a virtual meeting where you will be asked to demo various aspects of the integration, including;

  • Adding and removing products from the menu
  • Updating a product’s price and attributes
  • Marking a product as out of stock, with and without a return date
  • Adding, updating and removing a promotion
  • Adding, updating and removing a meal deal
  • Retrieving order information

If it has been previously agreed that the integration will be built in phases, only the elements from completed phases will be checked.

Any issues brought up in the verification process will be discussed with the integrator to ensure that they’re resolved in the best way for all parties.

Additional Information

Snappy Group Product Flow

At Snappy Group we have our own way of managing our product library, which we call the “master menu”. This allows us to keep product information up to date using external services such as Brandbank and ensures that products across all of our menus have a high standard of detail.

This means that certain menu operations may require additional input before they apply to a menu. Please see the details below.

Adding Products

When products are added to a menu, the first thing we do is check if it exists in our master menu. Based on the result of that check, a specific add operation is run.

If the product exists in our master menu, the additional information is collected from there and applied to the product. This means that the product will be fully formed and can be added to the store’s menu in real-time.

If the product does not exist in our master menu, it will need to be approved by our menu team before it will appear on the store menu. This approval process involves collecting information and updating the product to meet the high standard expected by our master menu. Once this process has been completed, the product is added to our master menu and the store menu.

The master menu checks only apply to globally recognised barcode standards (EAN-13, EAN-8, UPC).

If PLU codes are used, they will only be added to the store’s menu.

Updating Products

When updating products, the changes will be made in real-time.

Error Handling

In the event of an error (connection failure, credentials rejected etc) the request should be retried. If the request continues to fail it should be stored so it can be retried when the issue has been rectified.

In the event of a catastrophic failure there should be a method of pushing Snappy a full update to get the store’s products & stock back up to date. This should be done by using the quickUpdate endpoint with the fullUpdate field set to true. You should send Snappy all items currently set to show on Snappy. This should be followed by a request to the Availability endpoint to mark products as out of stock. This should also be used when setting up a new integration.