Library OpenApi Overview About these APIs Architecture Authentication Error Responses Locating a Server Sessions Design Guides Guides and Hints Examples Pricing for Websites Accepting Vouchers PreAuth Payment Replication Common Apis The most used APIs Create New Sale Payment Completion Multiple Locations Delivery Addresses Customers Locations Products Staff WebHooks eCommerce Apis These APIs are often used with eCommerce website integrations Get Pricing Card Inquiry Report & Analysis Grouped or analysed report data. Typically used to build reports and dashboards Today Login Access Pinboard ReportRequest Advanced Information More indepth information Caller Handling HTTP Protocol Bulk Data Downloads Document Uploading RetailConfig Under Development Details of APIs that will be available shortly. Documentation provided is for early adopters Get Receipt

Create New Sale API

Stores a complete sale definition into the database. A complete sale is one that is broadly finished processing and not still having items or payments added to it at a checkout. An eCommerce sale is also stored via this API, even if it still has fulfullment processing to complete.

Simple Examples

Storing a sale captured using an external process that you wish to store. This shows the mimimum amount of information required

{
    "ExternalId": "Sale.000001",
    "CompletedDt": "2019-07-01T10:35",
    "Phase": 1,
    "LINE": [{
            "Pid": 12345,
            "Qty": 1,
            "TotalPrice": 9.00
        }],
    "PAYM": [{
            "Type": "cash",
            "Amount": 9.00
        }]
}

Quick Notes

This API is designed so that you can send the same information multiple times and the POS will only process it once. This can simplify sending applications as they can simply resend sales several times over a couple of days as a primitive retry mechanism. The restriction to this is that you must not change the sale, such as adding new items or comments, as once the POS has loaded the sale all further attempts simply return "OK" type response codes. If we have only returned error codes for each call, then you are permitted to change the sale details; as it has not been stored.

The ExternalId field is a unique identifier for a sale. You must ensure this is unique for all time, as if you repeat a new sale with the same ExternalId, the POS will immediately assume it is the same sale. This can be quite a long string and the internal structure is completely for you to decide. We suggest using a value of current date/time concatenated with a GUID which you store against your copy of the sale as well.

You can upload different content-types to this API:

Fieldpine is an extensible retail platform, so if you need to store industry specific information please contact us with details and we will allocate standard field names. Do not use a field for a reason other than its documented purpose, this simply creates headaches elsewhere and makes creating of reports less effective

Error Handling or Queuing Requests

The caller of this API is responsible for ensuring accuracy of the information and the API will reject invalid sales. For example the total price of items must exactly match payments. The system cannot allow invalid transactional data to be stored. As storing sales is critical and can lead to finanical loss if information is not processed, you can provide an indication of your level of error handling ability.

The CallerHandling parameter should preferably be sent in the HTTP Header X-Fieldpine-CallerHandling, rather than the request payload.

"X-Fieldpine-CallerHandling": "full"
Use this option where the sending system is fully able to handle all errors and retry operations after correcting errors. This is recommended during the development phase so as to not clog the POS with invalid attempts
"X-Fieldpine-CallerHandling": "audit"
This option is used when the sending system is capable of handling some errors and resending corrected data, but the POS should keep track of these and alert humans where possible as well the sending application. This is the default if no CallerHandling option is provided. An example might be an eCommerce website that is creating sales and has its own transmission queue. While the eCommerce site will have a report of failed sales, the POS will also maintain a list to ensure human notification as soon as possible
"X-Fieldpine-CallerHandling": "none"
Use this option if the sending application is unable to accept failure conditions. The error will still be returned to the calling application but it will also be stored for human review in the POS. An example might be sales being stored from an automatic vending machine.
"X-Fieldpine-CallerHandling": "queue"
When "queue" is used the server may immediately return a HTTP 202/Accepted response code and store the request data for later processing. You will not immediately receive error responses and need to either poll for the response or process a sale-load web hook. Queue mode provides the highest reliability of request delivery for clients as the server only needs to store the request and not attempt to process it immediately, this means any backend issues or high traffic conditions will not affect your API call.

With Queue mode it is explicitly permitted to queue the same request data multiple times.

"X-Fieldpine-CallerHandling": "developer"
When set to developer mode, the API returns an error response for every little problem, including warnings. This mode should ideally be coupled with "readonly"
"X-Fieldpine-CallerHandling": "readonly"
This API supports the "readonly" attribute.

Note. You need to provide error handling or retry logic for any HTTP status code other than the 2xx response codes. The above error handling does not absolve callers from all responsibility

Refer to CallerHandling.htm for more details on other features and uses of this header. It has some development features to help make your client application more robust

Specifying the Product

Each saleline supplied adds another line to the customers receipt. A saleline must reference a known product in the product list. There are several ways to specify which product you wish to use

Using the Product.Pid Each product has a 32 bit integer called "pid" that uniquely identifies the item for that retailer. This is a good choice for automated systems where each Pids are known, or where the application has uniquely identified a product from a search function. Pid is clear and unambiguous.


"LINE": [ {
    "Pid": 2301,
...
} ]

Using the Product.Plu or SKU Shop staff typically work with PLUs or SKUs. You can specify the product using a Plu instead. A plu is not guaranteed to be unique to a single product in rare cases, so you might occassionally need to handle failures.


"LINE": [ {
    "Plu": "KITTEN-14",
...
} ]

Calculating the Price

In circumstances where the price to be charged to the customer is unknown when you create the sale, you can request the API to price the item(s). As the price is variable, you also supply a single payment record indicating what type of payment is to be used. An example of where you may need this ability is where customers are swiping their id cards to enter an exhibition and the price depends on who the customer is. In general you should avoid asking this API to calculate prices as errors in calculation will not be stopped. A better approach is to call the sale pricing API which returns the price details

{
    "ExternalId": "EntryScanner16.20190701134326.12345",
    "CompletedDt": "2019-07-01T11:43:26",
    "Phase": 1,
    "Customer": "978000124356",
    "CallerHandling": "none",
    "LINE": [
        {
            "Pid": 2301,
            "Qty": 1,
            "TotalPrice": "calculate"
        }
    ],
    "PAYM": [
        {
            "Type": "prepay",
            "Amount": "all"
        }
    ]
}

Pricing Models

Pricing can be represented in two different ways, a "Customer Pricing" model which is what customers expect to see, and "Technical Pricing" which is more useful to accountants and stock controllers. You can send sales in either model but must use only one within a single sale.

"Customer Pricing" and "Technical Pricing" are different and can result in different results due to rounding. If you calculate discounts on the subtotal, as per customer pricing, then this may not equal the total of the discounts calculated on each line. You should decide how you want receipts to appear and ensure that the pricing model matches that; otherwise customers will notice and complain about rounding errors, even 1 cent

Customer Pricing
Price
(123) Carrots5.94
(456) Drink1.44
(882) Beans2.44
Sub total9.82
Less 10% discount0.98
Total8.84
"SALE": {
 "LINE": [
 { "Pid": 123
   "TotalPrice": 5.94
 },
 { "Pid": 456
   "TotalPrice": 1.44
},
 { "Pid": 882
   "TotalPrice": 2.44
 }],
"Discount1": "10%",
"Discount1Amount": 0.98,
"Discount1Rate": 10.00
}
Potential Receipt Layout
(123) Carrots5.94
(456) Drink1.44
(880) Beans2.44
Sub total9.82
Less 10% discount0.98
Total8.84
Technical Pricing
PriceDiscount $Disc TypeEach
(123) Carrots5.350.5910%5.94
(456) Drink1.300.1410%1.44
(882) Beans2.200.2410%2.44
 0.979.82
 
Total8.85
"SALE": {
 "LINE": [
 { "Pid": 123
   "TotalPrice": 5.35,
   "Discount1": "10%",
   "Discount1Amount": 0.59,
   "Discount1Rate": 10.00
 },
 { "Pid": 456
   "TotalPrice": 1.30,
   "Discount1": "10%",
   "Discount1Amount": 0.14,
   "Discount1Rate": 10.00
},
 { "Pid": 880
   "TotalPrice": 2.20,
   "Discount1": "10%",
   "Discount1Amount": 0.24,
   "Discount1Rate": 10.00
 }],
}
Potential Receipt Layout
ItemEachDiscPrice
(123) Carrots5.940.595.35
(456) Drink1.440.141.30
(880) Beans2.440.242.20
Total8.85

Customer Pricing with Non discountable items
PriceDisc Type
(890) Gift Card20.00
(123) Carrots5.9910%
(456) Drink2.0010%
Sub total27.99
Less 10% discount0.80
Total27.19
"SALE": {
 "LINE": [
 { "Pid": 890
   "TotalPrice": 20.00
 },
 { "Pid": 123
   "TotalPrice": 5.99,
   "Discount1": "10%"
 },
 { "Pid": 456
   "TotalPrice": 2.00,
   "Discount1": "10%"
 }],
"Discount1": "10%",
"Discount1Amount": 0.80,
"Discount1Rate": 10.00
}
In this customer pricing example, the Gift card is excluded from discounts. These products are normally marked NoDiscount, but to remove all doubt you should load the "Discount1" field for each product you included in your discount calculation.

Adding Discounts

A discount is an adjustment made to the totalprice of the saleline. A discount is not a payment, financially it is considered to have reduced the earned revenue for this saleline. To add a discount to a saleline, include the "Discount1" field identifying the type of discount, and if required the "Discount1Amount" for the amount of the discount.

The following example applies a discount called "seniors" to the saleline. The final price is derived by calculating the price as normal and then applying the discount to that figure

{
    ...
    "LINE": [
        {
            "Pid": 2301,
            "Qty": 1,
            "TotalPrice": "calculate",
            "Discount1": "seniors"
        }
    ]
}

When discounts and totalprices are specified the following table outlines the logic. The main rules in this table are

  1. If you specify a totalprice, then any discount is already included in that price
  2. If you specify a discount but not the totalprice, then the totalprice is calculated and the discount applied.

UnitPriceQtyDiscount1/AmountTotalPriceCalculation Logic
$5.001fixed $1.50$3.50Stored as provided, no server calculation
Nfixed $1.50calculateTotal price calculated, discount then applied
NseniorcalculateTotal price calculated, then "senior" discount applied
1fixed $2.00$7.00Unitprice calculated as $9.00
Unitprice = (TotalPrice + Discount1) / Qty

This next example shows how to request a 10% discount on a calculated price. The field Discount1Amount contains the actual amount of the discount if known, and Discount1Rate holds the 10%

{
    ...
    "LINE": [
        {
            "Pid": 2301,
            "Qty": 1,
            "TotalPrice": "calculate",
            "Discount1": "percent",
            "Discount1Rate": 10.00
        }
    ]
}

Charging the Sale to an Account

If you wish to charge the sale to an account then send the sale as normal with the following details

{
    "ExternalId": "EntryScanner16.20190701134326.12345",
    "CompletedDt": "2019-07-01T11:43:26",
    "Phase": 1,
    "Customer": "124356",
    "CallerHandling": "none",
    "LINE": [
        {
            "Pid": 2301,
            "Qty": 1,
            "TotalPrice": "calculate"
        }
    ],
    "PAYM": [
        {
            "Type": "Account",
            "Amount": "all",
            "OverridePassword": "SitePasswordHere"
        }
    ]
}

If the sale cannot be charged to the account for some reason then the following applies:

  1. If the account is over credit limit and you have supplied a valid override password, the sale will be recorded without issue. Essentially the password bypasses limit checking
  2. If your API request has specified CallerErrorHandling=full, then you will receive an error response and the sale will not be applied
  3. If your request has a CallerErrorHanding that indicates it cannot handle errors, then:
    • The Sale will be stored and placed in a "Picking" state. This state indicates that human action is required to complete or void this sale.
    • You will receive the normal status expected.

There are several reasons account sales may block:

  1. The account would be over its credit limit if this sale was accepted, AND, credit limits are set to hard blocking
  2. The account is on stop credit
  3. The amount requested exceed the floor limit for this customer or account.

Account Payments

You can send details of a customer paying their account balance via this API. In normal operation the POS records an account payment made at a checkout by the operator selling the "Account Payment" product, which the POS knows how to handle, and the fact that this is not sales revenue.

This API supports the same logic, so you can automate things like recording direct debits seen in your bank account. An example sale sent might be:

{
    "ExternalId": "AccountPayment.20190701.L45",
    "CompletedDt": "2019-07-01T10:35",
    "Phase": 1,
    "Customer": "Bobs building supplies",
    "CallerHandling": "none",
    "LINE": [
        {
            "Pid": 2,           // The productid of "Account payment" product on your system
            "Qty": 1,
            "TotalPrice": 200.00
        }
    ],
    "PAYM": [
        {
            "Type": "directdebit",
            "Amount": 200
        }
    ]
}

Retailer Specific Data

Retailers will frequently have specific data they need to collect and save as part of a sale. Every sale has the basic what product was sold and for how much, but there is often a need for serial#, Vehicle Registration Number, Repair instructions, hire return date and so on.

Where these are known fields, they can simply be included as part of the sale item they relate too

{
    "ExternalId": "1512523526252",
    "CompletedDt": "2019-07-01T10:35",
    "CallerHandling": "none",
    "LINE": [
        {
            "Pid": 1234,
            "Qty": 1,
            "TotalPrice": 19.95,
            "Regno": "ABC123",              // Item Specific fields
            "SerialNo": "82737144",
            "Odometer": 20549,
            "Vin": "AUC12345678J89",
            "Comments", "Caution customer has peanut allergies"
        }
    ],
    "PAYM": [
        {  "Type": "cash",  "Amount": 50 },
        {  "Type": "change",  "Amount": 30.05 }
    ]
}

Redeeming Vouchers and Prepay Cards

Customers may have serialised vouchers or prepay cards with balances they can spend. Card details can be validated with the /CardInquiry API. This API returns details about the card the customer wishes to redeem, as well as a UsageToken that can be sent as part of the payment records. The UsageToken confirms that a card was validated.

When sending a UsageToken you do not need to send the "Type" of payment identifier. The server can deduce this automatically from the card information. Payments made using a UsageToken reduce the cardholders balance immediately, even if the sale is in a picking state waiting to be dispatched. Any difference is adjusted when the sale is finally completed.

{
    "ExternalId": "123414",
    "CompletedDt": "2019-10-06T21:35",
    "CallerHandling": "none",
    "LINE": [
        {
            "Pid": 1234,
            "Qty": 1,
            "TotalPrice": 19.95
        }
    ],
    "PAYM": [
        {  
            "UsageToken": "1|50|ABC|AAABCC|BBBAAA",         // Value returned from Cardinquiry
            "Amount": 19.95
        }
    ]
}

Click and Collect Sales

A click and collect sale can indicate the collecting store by inserting this into the Delivery block. This causes Fieldpine to alert the store that they have a C+C sale waiting. The Sale Location field is not changed as the sale was still created via your website etc. The server has configurations options to ensure stock is reduced in the correct stocking location.

{
    "ExternalId": "123414",
    ...
    "Delivery": {
        "CollectLocation": 301
    }
}

The CollectLocation field can be either the numeric "locationId" assigned in Fieldpine, or the "Location Name". We recommend using the LocationId over the Name, as the name can be changed by users easily which will cause API rejection if values no longer match.

When sales use the CollectLocation functionality, there are specialised functions to make this easier instore to manage their C+C sales

Setting Client App Details

When sending sales it is very helpful for support and reporting to specify which application created the original sale. The field "CreateApp" in the sales header is used to supply this information.

{
    "CreateApp": "70123",
    ...
}
{
    "CreateApp": "iPad-Pos V1",
    ...
}

CreateApp defines the name of the application, a second attribute PosVersion is used to store the current version of your application. This field is uncontrolled in terms of contents, but we highly recommend you store a value that changes on every minor release update. It is very helpful for support purposes.

{
    "CreateApp": "iPad-Pos V1",
    "PosVersion": "Build 22 Jun 2011, 1.13872",
    ...
}

Held Barcodes

Fieldpine allows customers to present vouchers and coupons to influence the sale in various ways. An example might be a promo sent to a customer offering "$5 off your next purchase of ABC this year" The promo typically includes a barcode. Client apps can scan these codes and provide them as a "HeldBarcode" when creating the sale. This permits Fieldpine to correctly process the special offer and apply pricing adjustments.

{
    "ExternalId": "123414",
    "HeldBarcode": "VOUCHER1234",
    ...
}

Delivery Information

If the sale being created is an eCommerce order and you wish to include delivery information then you can supply a Delivery or DELI block with this information. If you have specified a customer for the sale then a delivery block is only required if the details are different to the customers current information. If delivery information is not supplied then the shipping address is taken from the customers definition.

For more information on setting delivery address, see Delivery Addresses for details.

If you are implementing a click+collect sale, see Multiple Locations for details.

{
    "ExternalId": "123414",
    "CompletedDt": "2019-10-06T21:35",
    "CallerHandling": "none",
    "LINE": [
        {
            "Pid": 1234,
            "Qty": 1,
            "TotalPrice": 19.95
        }
    ],
    "PAYM": [
        {  
            "type": "Account",
            "Amount": 19.95
        }
    ],
    "Delivery": {
        "Instructions": "Leave beside BBQ if nobody home",
        "Address": "1a My street|Douglas|Taranaki",
        "Email": "sue@example.com"
    }
}

When supplying a shipping address, you can either provide the address in a single field "address" or split out the component pieces into the Address1, 2 fields.

Multiple Locations

A "location" is the single store where the sale was made. If you are creating an eCommerce website, then typically that website is classifed as a seperate location to physical stores. All your sales refer to that location. Think of this as the primary "revenue reporting" location

A sale may also have a "stock location", which is the location that the stock will be drawn from. It is rare for an eCommerce website to directly specify the Stock Location to be used, generate this decision is a server side one.

If your sale is a click and collect sale, then the Delivey block will include a CollectLocation value, indicating the store the customer will collect this item from. This can influence stock location on the server.

See Multiple Locations for more indepth details.

Credit Card Preauth transactions

eCommerce sales are typically charged using a PreAuth method where an amount is reserved on the customers card and the final amount is charged after product or services have been delivered. To save a sale with a preauth, include a Payment record with the type set to eftpreauth and the amount being the reserved amount

Do not send credit card numbers, only include references to the payment acquirers transaction

{
    "ExternalId": "123414",
    "CompletedDt": "2019-10-06T21:35",
    "Phase": 200,
    "StatusAdvise": "https://myserver/sale/changing",
    "LINE": [
        {
            "Pid": 1234,
            "Qty": 1,
            "TotalPrice": 19.95
        }
    ],
    "PAYM": [
        {  
            "type": "eftpreauth",
            "Ref": "AB19182",
            "Amount": 40.00
        }
    ]
}

In order for you to finalise the credit card charge you need to know when the sale has been completed and the amount to charge, several options:

See also: Payment Completion

Date/Time Handling

The Field "CompletedDt" is used to store the completed date/time of the sale. Fieldpine prefer to receive the localtime of the sale, but this is not always possible.

Understanding the Response

If your sale request is saved or already known you will receive a response packet with the following contents.

{
    "data": {
        "Sid": 12345,
        "Status": 0,
        "StatusText": "Saved",
        "Physkey": "KAPEJEJFJV87SBEFGGTFEF"
    }
}
Sid
This is the allocated Sale Number for the current database. Sids are integers, excluding zero. A sid is not a permanent key to the sale and the Point of Sale may renumber them. If you send a sale to fieldpine.com, we will alllocate a Sid, but when the sale is transferred to the primary database it may need renumbering at that time.
Status & StatusText
Status is a coded number (integer) indicating how the server handled this request, and StatusText is the english description of that value. Possible values are:
ValueStatusTextExplanation
0SavedThis was a new sale and we have stored it to the database.
1Sid KnownA sale was sent including the "Sid" field and we already know this sid.
2ExternalId knownA sale was sent and the "ExternalId" field matches an existing sale.
3 Srcuidkey known A sale was sent from a Fieldpine application and we already know it. The fields used by Fieldpine application are not documented for customer use, so you should not see this status
4Physkey knownA sale was sent with a "Physkey" and a sale already exists with this value
5 Queued We have accepted your sale request and will process it at a future time. This status is only returned if you request queuing and the server wishes to queue it.
32 Saved with Error Your sale was Saved, but had non fatal errors. This is a rare status and will not generally be returned without some form of exception rule existing.
An example is where you send a sale for a Customer, but the customer is not currently known, AND we have a server side rule stating that your application MAY send customer information after a delay.
Physkey
The unique identifier for this sale. This is the value you should record as proof or linkage to the sale. Physkey is a string value up to 44 ascii characters long.

The recommended way to verify a sale was stored is:

  1. Verify the HTTP response code was 2xx
  2. Verify the received JSON is valid
  3. Verify a "data" object exists in the response
  4. Verify a field called "Status" exists in the "data" object
  5. Verify the value of the Status field is acceptable to you