Upload Product Assortments

Automate the import of user assortments.

1. Requirements

Please notice the assortment integration is only possible if you can cover the following requirements:

  1. Small assortment size: Huge assortments with thousands of articles will not provide a good user experience in Apicbase and the customer will have trouble to manage this amount of articles in our platform. So we ask to proceed with the assortment integration only if your assortment has a few hundred articles or if you can provide customer specific assortments with a few hundred articles, often composed by the subset of aritcles the customer normally orders.
  2. Customer specific assortments: If you are using this solution to limit the assortment, you should also be able to offer a way for the customers to add/remove articles from their assortment, for example via an account manager on your side or via an interface in your webshop. Those changes should then be reflected on the assortment data sent to Apicbase.

The assortment file is

2. API Endpoint

Once you make sure you fulfill the requirements above, then we can get more deeply into the assortment integration.

The assortment is composed by the collection of products and its details (such as brand, prices and lead time) to the create assortment file endpoint. This endpoint expects a JSON file with the following structure:

[
    {
        "third_party_id": string, --> required
        "shared_id": string,
        "brand": string,
        "name": string, --> required
        "description": string,
        "package_type": string,
      	"price": decimal, --> required
        "price_type_code": integer, --> required (0: per package; 1: per unit)
        "price_unit": string, --> required if price_type_code=1
        "orderable": boolean, --> defaults to true
        "package_description": { --> required
            "quantity": decimal, --> required
            "gtin":string,
            "package": {
                "quantity": decimal, 
                "unit_name": string, --> required at lower level
                "gtin":string
            }
        },
        "lead_time": string, --> optional, duration in the format: [DD] [HH:[MM:]]ss[.uuuuuu]
        "weighted": boolean --> optional, defaults to false
    },
    {...}
]

The package_description attribute has a recursive nature. Its package can be a nested structure that contains other packages. This is also a viable representation:

{
    "package_description": {
        "quantity": decimal, --> required
        "gtin":string,
        "package": { --> required for nested packages
            "quantity": decimal,
            "gtin":string,
            "package": {
                "quantity": decimal, 
                "gtin":string,
                "package: {
                    ....
                    "unit_name": string --> required at the lowest level
                }
            }
        }
    }
}
  • third_party_id: The package's unique identifier (REQUIRED). This will be the same identifier sent back to you in the Ordering integration;
  • shared_id: An ID that identifies the article that the package belongs to (or an identifier shared between packages);
  • brand: The article's brand;
  • name: The name of the article (REQUIRED);
  • description: Any extra information about the package;
  • package_type: The type of package (if it's a box, case or ...)
  • price: The price of the article;
  • price_type_code: If the package is priced based on an specific price_unit (price_type_code=1) or priced for the whole package (price_type_code=0);
  • price_unit: Unit which the package is priced. REQUIRED if price_type_code=1. The units supported are defined here.
  • orderable: True, if the package can be ordered (default). False, otherwise;
  • package_description: The article content. REQUIRED.
  • lead_time: How long it takes to deliver the article. E.g: 24 hours should be represented as "24:00:00".
  • weighted: Whether the article is ordered in a defined unit (liters, kg, oz, lb) or not. In other words, the article can be ordered in decimal amounts, e.g. 2.4 kg. If true, the package description should be defined as 1 time one of the units mentioned (1 l, 1 kg, 1 oz, 1 lb).

2.1. Package Description

The package_description field is critical when sending integrated assortment items. Its completeness will be validated, as we rely on this information to ensure accurate pricing and measurements. For instance, we will not allow items to be sent with no indication of weight, volume, or quantity.

This field can be specified as a nested JSON (using the package_description attribute). Different GTIN can be defined for different package levels:

{
    "package_description": {
        "quantity": 2,
        "gtin": "26989625952452",
        "package": {
            "quantity": 3,
            "gtin": "306995253187",
            "package": {
                "quantity": 100.0, 
                "unit_name": "g"
            }
        }
    }
}

It's very important for us to have the package description as much detailed as possible. Let's take for example the article "Tomato sauce", which is a box containing 4 bottles of 250 ml each. Here are the possible ways of representing it with the package_description field:

  • {"quantity": 4, "unit_name": "piece"}: This meets the minimum requirements but doesn't provide any information about the package structure nor the article unit. This can limit our customer to use other features in our software such as:
    • inventory: it's not possible to count individual bottles of tomato sauce.
    • food cost: if a recipe is created on our platform using 100 ml of tomato sauce, it's not possible for our software to calculate it's food cost since the unit is defined in piece.
  • {"quantity": 4, "package": {"quantity": 1, "unit_name": "piece"}}: There's a small improvement when compared to the last one because the package structure is more clear. However the food cost feature will still not work properly for this article.
  • {"quantity": 4, "package": {"quantity": 250, "unit_name": "g"}}: This is better than the previous options because now the food cost should work. However the article is defined in a mass unit (grams) while it should be clearly a volume unit (ml). This is not a problem for us because there's a conversion ratio configurable per article by the customer, which defaults to 1 kg = 1 liter. But it'd for sure be better to have a more appropriated unit for it.
  • {"quantity": 4, "package": {"quantity": 250, "unit_name": "ml"}}: That's the best representation we can have for this article.

๐Ÿ“˜

The piece unit is fine for non-food articles, e.g. cleaning products, or articles where this unit is fitting, for example a box of eggs with 12 units.

2.2. Pricing

The package pricing is defined by the fields price, price_type_code and price_unit. Please take the following into consideration when defining the package price:

  1. The price is for the package as a whole, e.g. $5 for a Coca-Cola pack (6 x 33cl). Then we have price=5 and price_type_code=0. The field price_unit must not be set.
  2. The price is for the unit, e.g. $10 for the kilogram of steak. Then we'd have price=10, price_type_code=1 and price_unit=kg.

2.3. Package Availability

The availability affects whether the customer can place orders or not for the package. It can be represented in 2 ways:

  1. Explictly: This can be done by setting the field orderable. This is pretty much straightforward: packages with orderable=true are available and packages with orderable=false are not available.
  2. Implicitly: Packages not listed in the latest assortment file from a given customer will not be available for ordering. We always expect to receive the full customer assortment file, so if an article is not available in the latest file received, then we consider it to not be available anymore.

2.4. Supported Units

Mass units:

  • Metric system: kg (kilograms), g (grams), mg (milligrams), ฮผg (micrograms).
  • Imperial system: lb (pounds), oz (ounces).

Volume units:

  • Metric system: l (liters), dl (deciliters), cl (centiliters), ml (milliliters).
  • Imperial system UK: gal (UK) (gallons), qt (UK) (quarts), pt (UK) (pints), cup (UK) (cups), fl oz (UK) (fluid onces), tbsp (UK) (tablespoons).
  • Imperial system US: gal (US) (gallons), qt (US) (quarts), pt (US) (pints), cup (US) (cups), fl oz (US) (fluid onces), tbsp (US) (tablespoons).

Pieces: either piece, pc or st.

๐Ÿšง

Units that cannot be interpreted (not included in this list) will be interpreted as piece.

3. FAQ

  1. How can I determine whether a unit is available or not for individual order? For example, a package that contains a box of wine bottles (750 ml), with 6 bottles in total, how can I define if the bottle unit (750 ml) can be ordered or not?
    We'll explore the package_description field in more detail, assuming that the individual bottle can either be ordered separately or not.

    Bottles ARE individually orderable

    It is possible to order a single bottle.
    Since you have two orderable packages, we need two distinct items in the assortment file. Each item will have the same shared_id but unique third_party_ids:

    [
        {
             "third_party_id": "CS123456",
             "shared_id": "123456",
             "package_description": {
                 "quantity": 6,
                 "package": {
                     "quantity": 750.0, 
                     "unit_name": "ml"
                 },
                 "gtin": "2698962595245"
             },
         },
         {
            "third_party_id": "EA123456",
            "shared_id": "123456",
            "package_description": {
                "quantity": 750.0,
                "unit_name": "ml",
                "gtin": "6820540261525"
            },
       },
    ]
    

    This will generate two orderable packages: one that represents the whole box, and one that represents the bottles. Using the same shared_id is very important for us to know both packages are different representations of the same article.

    Bottles ARE NOT individually orderable

    It is not possible to order a single bottle separately.
    Without nested packages, you should provide only one item:

    [
       {
            "third_party_id": "123456",
            "package_description": {
                "quantity": 6.0,
                "package": {
                    "quantity": 750.0, 
                    "unit_name": "ml"
                },
                "gtin": "2698962595245"
            },
           ...
       }
    ]
    

    There's no need to provide a value for the shared_id attribute, either. This will generate a package for the whole box.

  2. How can I specify that a product is not delivered with an exact weight but is instead weighed at the time of delivery? For instance, if a customer orders 1 kilogram of tomatoes, the delivered quantity might be 1.1 kg, or 0.9 kg. etc.
    You should make sure the following is covered:

    • The package description is defined as the average package weight and is constant, i.e. it's the same value for every assortment file containing this article. The example above could be represented as {"quantity": 1, "unit_name": "kg"}.
    • The price is defined accordingly. This kind of package is often priced per unit, so the delivered package is priced for the weighted amount at delivery time. The example above would have price_type_code=1 and price_unit="kg".
  3. How long is an article or a catalog/assortment valid? How do I handle seasonal products, i.e. articles available for a defined time period?
    As mentioned in the Package Availability section, we always expect to receive the full customer assortment file and we consider the current article/assortment status as the one we get in the latest assortment file received for a given customer. That means an article will be available for a given customer as long as it's listed in the latest customer assortment file we received with the status orderable=true (or with the field orderable omitted).

  4. Is it possible to set different lead times based on the day of the week? For instance, having a lead time of 3 days for orders placed on Mondays and 2 days for orders placed on Tuesdays.

    Unfortunately this feature is not available in our API. However the customer can set this up on our platform per location and define which days it is possible to schedule a delivery for the order and up to when the order should be placed. In the example below, the customer place orders to be delivered only on Mondays and Wednesdays and orders to be delivered on Monday should be placed 2 days before (Saturday up to 6 PM)

    However, please notice we don't support in any way setting the lead times per article based on the day of the week. The lead times described above are applied for all articles in the customer assortment.

  5. How often is the assortment file processed?

    The assortment file is processed once per day for every customer due to limitations on our side. Normally this frequency is enough because the article data often doesn't change much within this time period. However this also means that all the assortment files must be sent before the agreed time, else their processing will be delayed for 1 day. For example, if the agreed time is 4 AM, any file sent after this time will be processed only on the next day at 4 AM.

    Please also notice if multiple files for the same customer are sent in the same day, only the latest file will be processed. For instance, if 3 files are sent for the customer number 123456, then only the last file will be processed, while the other 2 will be ignored.

    At last, assortment files don't need to be sent daily as long as there are no changes when compared to the previous file. However, the customer full assortment must be always sent even if the change is about a single article.

4. Testing

Please check our Sandobx Account guide in order to test your assortment integration.


Whatโ€™s Next