Library
FD1 Sales Endpoint
This endpoint deals with individual or groups of sales. It only works with whole sales (ie not being slowly added too), or those being picked for shipping. If you are creating a sale capture POS or shopping cart, see the salesbuilder endpoint. The wording save_complete_sale refers to the fact that the sale object in JSON is "complete", as in has all data recorded, well formed and not going to undergo major changes. You can still save sales that are state = "active", "void", "parked" etc
To create custom reports, use fd1.data endpoint. This general purpose endpoint lets you define a "table" or spreadsheet of sales and open that. For example, you can use fd1.data to request "all sales, sold last month, with any "fresh" department items" as JSON, CSV, Excel, etc, or even open a firehose. These custom report definitions can be saved and distributed.
fd1.sales.save_complete_sale
Allows you to upload a complete sale definition. This is the endpoint commonly used if uploading a complete sale from websites or custom sales capture devices. Once uploaded via this API, the sale cannot be changed by sending it again. If you are wishing to save the state of a sale being rung up still, use the salesbuilder endpoint, that allows you to keep altering the sale, while also receiving pricing to apply and other conditions.
The payload for this API is sale.create
Example
{
a: "fd1.sales.save_complete_sale",
rq: "my-first-sale",
v: {
header: {
location: "Crown St Mall, Wollongong",
completeddt: "2026-01-07 14:33"
},
lines: [
{
sku: "ANANA",
totalprice: 9.95
}
],
payments: [
type: "eftpos",
amount: "9.95"
]
}
}
When using this endpoint, the server is very permissive and saves even errant sales. These get flagged for human review, but is more important they are actually saved. That can cause issues though for intelligent clients and while developing, so this endpoint understands the "ro" (request options) from the base protocol
| ro | Description |
| - blank - | Server decides what to do, based on system configuration. Typically this is set to save-always |
| save-always | Always save. if sale is ok, a data{} object is returned. If the sale has issues, a data{} object is return, and errors[] array is also returned |
| no-save-when-errors | If there are no errors, save and return data{}, otherwise return errors[] |
| no-save-check-only | Do not save regardless, return minimal data{} and errors[] if there are issues |
| developer-present | As no-save-when-errors, but server may include additional developer_notes |
| queue | The sale can be lazily stored in the background |
| duplicate-upload | The sale is known to be a repeat upload of a sale already sent. See notes for when/why this might be used |
{
a: "fd1.sales.save_complete_sale",
ro: "no-save-when-errors",
rq: "my-first-sale",
v: {
...
}
}
Responses
When the sale is stored, or would be stored a data{} object is returned. This data object is a short form sale, with key fields such as identifiers. The structure of data is the same as the input structure sale.create
If ro=queue, the response data will contain (To be doc'd)
If the sale is already known, the response will be the original upload details. This is done so that clients can simply send sales multiple times over a few days and not implement error checking.
The presence of data{} indicates the sale was saved (or would be)
An error[] array will be returned if the sale has issues. This can be returned with or without a data{} object. Errors in this array relate to the call itself, such as unrecognised fields or not adding up correctly. Errors are only returned the first time the sale is saved. The error[] is different to the sale.sale_errors[] array which are more human listed errors. If the sale json has multiple errors, then the call level error[] will list each one. However the sale_errors[] will list one "JSON received from <app-name> had structural errors"