Upload Sales

This is the part where it gets interesting!

Sales are uploaded via the Upload Sales Data endpoint, and this too needs to be done for each location by specifying a location ID. It is possible, but not recommended to upload sales data for multiple locations at the same time.

Use this endpoint to send a list of tickets generated at the POS system. Each individual receipt generated at the till should be represented by one ticket. Each ticket should represent an individual receipt. You reference the products and modifiers sold using their PLUs.

Prices and Taxes

Price fields are flexible and can be specified in different ways. You can specify a product's unit price, or a ticket line's total price.

  • If you specify the unit price, then the gross total revenue of a ticket line will be the (unit price * quantity) + (modifier prices * modifier quantities). Discounts and taxes are subtracted at the end.
  • If you specify the total price, then the gross total revenue of a ticket line will be just that. When specifying a total price, it is assumed that modifier prices are already included in this value. Discounts and taxes are subtracted at the end.
  • In jurisdictions where sales taxes are added on top of a transaction (such as the United States), it is recommended to set the VAT percentage field of ticket sales to 0.

A practical example

To illustrate how price and tax fields work in practice, let's see how this ticket would be represented in the Generic POS API:

This example illustrates a customer order that includes two plates of Spaghetti Bolognese, one with an extra cheese option, and two large drinks. The Spaghetti order received a discount, and each product has a different tax rate. The total price paid by the customer was €13,00, comprising €5 for each Spaghetti, €1 for the Extra Cheese option, a discount of -€2, and another €4 for the drinks, including taxes.

We can represent this ticket line using the unit_price attribute like so:

{
  "location_id": "POS_ANTWERPEN",
  "pos_id": "TKT00001",
  "created_on": "2020-06-01T12:30:00",
  "closed_on": "2020-06-01T13:00:00",
  "items": [
    {
      "product_plu": "SPAG_BOL",
      "product_name": "Spaghetti Bolognese",
      "quantity": 2,
      "unit_price": 5,
      "vat_percentage": 8,
      "total_discount": 2,
      "modifiers": [
        {
          "product_plu": "CHEESE1",
          "product_name": "Extra Cheese",
          "quantity": 1,
          "total_price": 1
        }
      ]
    },
    {
      "product_plu": "COLA_001",
      "product_name": "Cola Large",
      "quantity": 2,
      "unit_price": 2,
      "vat_percentage": 21,
      "total_discount": 0
    }
  ]
}

Or, alternatively, using total_price:

{
  "location_id": "POS_ANTWERPEN",
  "pos_id": "TKT00001",
  "created_on": "2020-06-01T12:30:00",
  "closed_on": "2020-06-01T13:00:00",
  "items": [
    {
      "product_plu": "SPAG_BOL",
      "product_name": "Spaghetti Bolognese",
      "quantity": 2,
      "total_price": 11,
      "vat_percentage": 8,
      "total_discount": 2,
      "modifiers": [
        {
          "product_plu": "CHEESE1",
          "product_name": "Extra Cheese",
          "quantity": 1,
          "total_price": 1
        }
      ]
    },
    {
      "product_plu": "COLA_001",
      "product_name": "Cola Large",
      "quantity": 2,
      "total_price": 4,
      "vat_percentage": 21,
      "total_discount": 0
    }
  ]
}

When and How

The timing of when to upload tickets depends on the limitations imposed by each POS system's specifications. However, our recommendation is to keep uploads small by performing multiple syncs per day. Ideally, tickets should be uploaded as soon as they are created at the till, without negatively impacting POS functionality, even in the event of errors or delayed responses.

It is possible to perform large end-of-day syncs, but please note that large requests take much longer to be processed. Consider your system's time-out limits and make sure to test with large payloads. Additionally, keep user behavior in mind: what happens if the POS operator forgets to close the till at the end of the day?

We do not recommend any approach that relies on users manually performing some action (like clicking a button) to upload sales data to Apicbase.

❗️

Sales data uploads can not be partially processed.

In case of an error occurring while processing any of the tickets in a payload, such as a duplicate ticket, the entire request will be discarded, and the processing will not continue.

This is why it's recommended to keep requests small and to not upload sales data for multiple locations at the same time: you don't want an error at one location to affect others!

Upload Data Chronologically

Uploading sales data in chronological order is important to ensure that tickets are processed correctly and inventory stock updates are accurate. It's essential to upload tickets in the correct sequence, as doing otherwise could cause issues when processing the data.

When sales data is uploaded to Apicbase, the system sets up an automated routine that runs at specific intervals to process it. If the automated routine has already processed tickets for a given date, it will not look at any dates earlier than that.

❗️

Errors during the sales upload should stop the sync.

If an error occurs during the sales data upload, it is recommended to stop the sync and avoid uploading any tickets generated after the problematic date. This is because if tickets from a later date are uploaded before the issue is resolved, it cannot be ensured that the problematic date will be processed again once the issue is resolved.

In case of doubt, it's always recommended to reach out to API support.

Treating Errors

To ensure proper troubleshooting of any errors in your integration, it's essential to maintain a log of your requests and any corresponding error messages returned by Apicbase. These error messages provide crucial information to identify the nature of the error and the specific entity that caused it. If you require assistance in resolving an error with your integration, be sure to include these details when contacting [email protected].

Errors that occur during sales data uploads as soon as possible should be addressed as soon as possible. If your integration is stuck because of an error, don't hesitate to contact us for support.

Missed Items

To ensure accurate reporting, all products referenced in a sales import should already exist in Apicbase and have their status set as active. If a product is not found, it will be created ad-hoc with the information provided in the ticket line, which is not an ideal outcome. Therefore, it's suggested to keep the product catalogue synchronized with Apicbase.

If a product could not be found in Apicbase during the sales data upload, this will be indicated in the body of the response, but it will still be considered a successful response (200 OK).

Processing Sales Data

Once you've uploaded sales data to Apicbase, we're ready to take it from there. 😉

An automated routine is scheduled to run at least once a day to process POS tickets, update stock, and generate cost analytics. Therefore, updates are not typically reflected immediately after sales are uploaded. It may take some time before the numbers are visible in the main sales and COGS dashboards.

Within the user interface, there is an alternative dashboard that is available to both users and developers. This dashboard is updated with data immediately as it is received by Apicbase, and can be particularly useful for development purposes. To access it, navigate to Sales > Sales Dashboard and click the option "Bring me to the old Sales Dashboard" in the top right corner.