The Goodtill External Sale API allows orders to be sent to the Goodtill POS programmatically. Once an External Sale order is created, it will appear on the relevant Goodtill POS registers within 10 seconds.
If the order is marked as pre-accepted or accepted on the POS, the tickets will be printed and the order will be sent to the Kitchen Display application ready to be prepared, exactly the same as if the order was taken directly on the POS application. The operator can then advance the order state, depending on the type of order (delivery or collection) before marking the order as completed.
If the order is rejected on the POS application, the sale will be voided in Goodtill. The third party system can be notified of the rejection by polling the GetSale endpoint until the order is marked as complete.
External Sales are recorded in the backoffice and are comprised of Goodtill products, the same as standard POS sales, allowing both POS and External Sale data to be included in backoffice reports. The third party application which creates the order must process the payment – Goodtill only records the payment amount and method used for the transaction.
The following flowchart shows an External Sale moving through the system:
Suggested integration path
- Ensure that all products and modifiers from the external system have been created in Goodtill.
- If the integration will be creating sales across multiple outlets (more info here), use the Outlet-GetOutlets endpoint to fetch the outlet list and store them in the external system, including their IDs.
- Use the ExternalSale-GetProducts endpoint to fetch these products and modifiers in the external system, including their IDs. If the store has multiple outlets, you may need to make one request per outlet with the relevant Outlet-Id header.
- Store the Goodtill IDs of the products and modifiers in the external system.
- When a new sale is created in the external system, call ExternalSale-CreateSale to create the sale in Goodtill and send it to the POS. Ensure the correct "Outlet-Id" header is set if creating orders across multiple outlets.
- Optional. Send any changes in order state from the external system to Goodtill via the ExternalSale-UpdateSaleStatus endpoint.
- Optional. Listen for changes to the Goodtill order state in the external system to relay this to the customer. This can be achieved by polling the API or via webhooks.
- Optional. Relay sale cancellations in the external system to Goodtill by calling ExternalSale-UpdateStatus with the REJECTED or CANCELLED statuses, depending on whether the order has already passed the ACCEPTED state.
Handling product availability per outlet
There are two main ways that product availability can be managed per outlet in Goodtill:
- Create products as "shareable", meaning the product is accessible from all outlets. No duplication is required because the products are available across all outlets.
- Create products as "non-shareable", meaning the product is only accessible from the outlet where it is created. The product must be duplicated in each outlet where it is used.
- A combination of #1 and #2, where products that are sold in all outlets are shareable and those that are only sold in specific outlets are non-shareable and duplicated.
Option #2 and #3 are the easiest to handle - to fetch the products available in a given outlet, call ExternalSale-GetProducts with the Outlet-Id header for the relevant outlet. Only products available in this outlet will be returned.
Option #1 is more common as it is easier to maintain, however it is slightly more complex to handle in API integrations. Calling ExternalSale-GetProducts with the relevant Outlet-Id will return all products available in this outlet, however there are likely some products that are shareable but only available in a subset of all the outlets. For example, a shareable product may be sold in outlet A and B but not C. This could lead to products being returned in the response that are not actually available for purchase in the selected outlet.
In this case, we would suggest leveraging the SellingLayout endpoints. Selling Layouts define the products that are available for sale on the POS terminal in a given outlet. By fetching the appropriate selling layout, you can can filter a ExternalSale-GetProducts response to only products where the product ID is also present in the selling layout. If none of the existing selling layouts will contain all of the products available for purchase via your integration, you can request that the store owner maintains a selling layout specifically for managing product availability in your integration.
Shareable product pricing and stock
Even if products are managed using option #1, you may still need to fetch the product list per outlet if:
- Pricing is different per outlet (confirm with the store owner)
- You are using the stock values in the response (these will always differ per outlet)
Ticket and KDS details
The following table lists what is displayed on each printed ticket and the KDS:
|Ticket / Display||Sales items||Order notes||Delivery notes||Customer name|
Delivery receipt is only printed for delivery orders.
If you would like to use the External Sale API in your application, please contact email@example.com with some information about your plans for the integration and we'll provide a Vendor-Id token.
Can the external system product IDs be stored in Goodtill?
Each Goodtill product has 4 custom fields which can be used for storing external data. These fields are included in the ExternalSale-GetProducts data, so this could be used to map the product IDs.
What happens if a product is out of stock?
The CreateSale endpoint does not validate stock availability. The sale will be created regardless of whether stock is available.
What's the benefit to setting product IDs in the CreateSale request?
Setting product IDs for the sales items in the request has the following benefits:
- Sales of the product will be counted in Goodtill reports.
- The VAT rate does not need to be specified, this is instead taken from the product configuration.
Why aren't tickets printed when orders are received?
The POS will only print the tickets when the order reaches the ACCEPTED state. The tickets are printed when the order is updated from CREATED to ACCEPTED from the POS app, or if the order is received in the ACCEPTED state. If the ExternalSale-UpdateSaleStatus endpoint has been used to advance the state past ACCEPTED when the POS fetches the sale, the tickets will not be printed.
How are multiple outlets handled?
The API allows differentiating between outlets using the Outlet-Id header - more details here. See above regarding handling product data per outlet. To place an order in a specific outlet, ensure that the correct Outlet-Id header is set and the user account has permission to access the requested outlet.
Does the POS need to be online to accept orders?
Sales can be created via the API regardless of whether any POS terminals are online. The POS will fetch any incomplete sales within the last 14 days when it next becomes active.
Can the POS be used to take the payment (via cash, card etc) for an external sale?
Yes. If there is an amount due, because the payments total in the request does not match the order value, the POS can be used to take the payment via cash or a connected card machine.
When fetching the outlet list, why are some outlets are missing?
It may be the case the your user account was not granted access to all the required outlets. Please contact the person who provided the account credentials to you or contact Goodtill support.