POS Gateway Guide


This page explains how to send in your POS data using the Fourth POS Gateway. Read this in conjunction with the POS Gateway reference, which holds full descriptions for each field and transaction type.


You can find any updates on the Release Notes page for the POS Gateway.

What is the POS Gateway?

The POS Gateway is our standardized and streamline way to deliver POS data to Fourth systems. It acts as a single point-of-entry to all Fourth systems that use POS data. This data in turn drives labor forecasts, inventory movement and business intelligence reporting in Fourth.

Learn how Fourth uses POS data

If you are a POS provider, you must integrate with this gateway, rather than creating a custom integration with Fourth. Doing so makes sure that you only need to integrate once with us, regardless of the Fourth solution you need to communicate with now or in the future.

Get started

To integrate with the POS Gateway, follow these steps:

  1. Contact Fourth, so that we can provide account details and support your business. Your mutual customer can introduce you to their Fourth contact to do this.
  2. Develop your CSV export, using this page and the POS Gateway reference.
  3. Test your integration with our sandbox — we'll also validate your file using our own tools.
  4. Get the customer to provide written sign-off.
  5. Go live!


Before reading further, please download these files:

Having these to hand will help as you read through this guide.

    How is POS data delivered?

    You send your POS data as a CSV file to the POS Gateway, normally once a day per customer location. We call this file the Transaction Dataset. You can send the file using either:

    • POS Transaction API
      The POS Transaction API is our preferred data delivery method. It is a RESTful API that supports HTTPS connections. See the POS Transaction API reference for details.
    • SFTP
      For each customer, you have a separate SFTP folder that only has data from your POS systems. This ensures privacy and security for both the Fourth customers and your business.

    What's inside the Transaction Dataset csv file?

    The Transaction Dataset maps your data to a set of transaction types and data fields that the POS Gateway can consume.

    You must send us the data as a CSV file that uses double quotes and commas. Empty fields MUST be double quoted. For example, this shows the first five columns with some rows of data:


    Transaction types

    Each row of the dataset has a transaction type. This is the action that has occurred during the dining experience. The types are:

    • TAB_OPEN and TAB_CLOSE open and close the check.
    • SALES_ITEM and MODIFIER_ITEM are the food, drink, and other sales orders.
    • DISC_ITEM is used for any discounts applied.
    • VOID_ERROR, VOID_ITEM, VOID_WASTE, and VOID_WASTE2 to VOID_WASTE11 are for voiding any items as required.
    • MAINS_AWAY and PRINT_CHECK enable you to timestamp these events.
    • SERVICE_CHARGE and TENDER take tip and payment information. 

    The transaction types are set in the 15th column of the transaction dataset: "TransactionTypeCode". You MUST set a transaction type for each record, otherwise the record is ignored!

    For example, during an average dining experience, these transactions would happen:

    Action Transaction type
    Customer is ready to order. TAB_OPEN
    Customer orders starter. SALES_ITEM
    Customer orders main meal. SALES_ITEM
    Customer orders drink. SALES_ITEM
    Customer asks for their main meal to not include tomato. MODIFIER_ITEM
    Server sees that the customer has finished their starter. MAINS_AWAY
    Server prints the bill to pass to the customer. PRINT_CHECK
    Service charge is recorded. SERVICE_CHARGE
    Customer pays the bill. TENDER
    Check is closed. TAB_CLOSE

    Read the full description of transaction types


      The fields (columns in the csv file) hold the data you are sending for each transaction type. Some fields are mandatory for all transaction types, such as:

      • "transactionid" is a unique ID for the record.
      • "recordactivitycode" is an incremental number of each transaction for a check.
      • "time" identifies when the transaction occurred.

      Other fields are relevant only to a specific transaction type, such as:

      • "tendertypecode" and "tendertypedesc" are used only for TENDER transactions.
      • "transactionstartend" is used only for TAB_OPEN and TAB_CLOSE transactions.

      You must include ALL columns in the dataset, in the correct order. Each field must include one of:

      • Data; e.g. "pizza funghi" or "12.50"
      • An empty string; e.g. ""
      • Zero; e.g. "0"

      Note that we have a number of fields that are reserved for future use. You just need to include an empty string "" or "0" for these as shown in the mandatory and optional fields Excel download.

      Read the full descriptions for each field

      How should I format the dataset file?

      You must send us the data as a csv file that uses double quotes and commas. Empty strings must be enclosed in double quotes. For example, the value for "unitid" is always an empty string:


      As well, you must:

      • Encode it using UTF-8 standard, without BOM
      • Send it unzipped
      • Ensure the filesize is below 30 MB
      • Ensure fields are below 255 characters

      See the formatting, encoding and other rules that apply to the dataset

      How do I update records?

      You can update records for a past date by sending in a new .csv file. The POS Gateway processes the file and:

      • Updates any existing transactions
      • Adds any new transactions

      To update a transaction, you MUST use exactly the same unique "TransactionId" as was previously sent in. If you send in a file that has new transactionIds for a date (with existing records), then the POS Gateway treats these as new transaction records for that date. Therefore, we highly recommend that you do not ever change the format of your transaction IDs if you generate these on-the-fly.

      You can submit updates to data for up to 2 years in the past. If you need to submit bulk sales data for further back than this, then please contact us.

      How do I delete records?

      If for some reason you sent in transactions that now need to be deleted, then there are two options:

      • Resubmit the transactions (with the same "TransactionId") and set the price columns to "0". If this is not possible, then;
      • Get your customer to raise a support case to resubmit transactions for the dates in question. Ensure that you give the customer the .csv files for the dates that need changing. Your .csv files must contain ALL the transaction sales data for the dates that need resubmitting. Our support team will delete the data from those dates, and then submit the new data for processing.


      Start a tab

      The TAB_OPEN transaction type opens a tab.

      There’s no sales data recorded for this transaction type. Instead, it primarily records the:

      • "time": This is the time the check is first opened; for example, "19:30:31".
        It’s vital for our customers that the start and end times are recorded accurately.

      • "RecordActivityCode": As it’s the first record for a transaction, this is "1".

      • "TransactionStartEnd": This is always "1".

      For mandatory fields around sales, price and tax, just enter "0" or "" as shown in the example.

      01: Example simple open & close tab

      Close a tab

      The TAB_CLOSE transaction type closes a tab. It also records the:

      • "PricePaid", "TenderAmount", and "Tax": these are the totals for the check excluding service charge.

      • "ListPrice": For TAB_CLOSE only, this can be either the total list price of the items before discount, or the price paid.

      • "Time": This is the time the check is closed. It’s vital for our customers that the start and end times are recorded accurately.

      • "RecordActivityCode": This must be the last record for the check.

      • "Covers": e.g. for 4 people, this would be "4".

      • "Qty": The number of items on the bill. We recommend using the number of charged and stock-related items; however, you can deviate from this if necessary. 

      • "TransactionStartEnd": This is always "2".

      01: Example simple open & close tab

      Add food and drinks

      All food and drinks sales are covered by the SALES_ITEM and MODIFIER_ITEM transaction types. These transaction types require the price per item, any discount applied, and the tax on the price paid (not the list price tax).

      As you’d expect, these transaction types require you to send through a lot of data about each sales item. This includes the categorization for the item. Normally, the categorizations for sales items are maintained by Fourth in collaboration with the customer. If, for any reason, the categorizations are changed at the POS end, you must notify Fourth so that we can update the configuration. The categorization fields are:

      • "MajorGroupDesc", for example "Food"

      • "FamilyGroupDesc", for example "Mains"

      • "SubGroupDesc", for example "Burgers"

      Note: For customers using Fourth Inventory for Hotels (Adaco), these must include a two-digit code at the start; e.g. "12-Burgers".

      An additional field, "SalesItemDesc", holds the description for the item, such as "water" or "Lentil goats cheese salad". A common cause of issues — particularly for places serving pizza! — is including a double quote in the description. This causes the data load to fail so we ask partners to avoid using them. However, if you must include double-quotes in your descriptive fields, then you must escape each one with an additional double-quote:

      ...,"10"" pizza",... 

      More double-quote examples

      Calculating price and tax value

      For each sales or modifier item, there a number of fields for including pricing and tax. These are:

      • "ListPrice": The original price per item before any discounts; in the UK this includes VAT.

      • "Qty": The number of items purchased

      • "PricePaid": The price paid for ALL items after any discounts are applied, including VAT.

      • "Tax": The VAT included in the "PricePaid".

      For example, a check that includes two identical pizzas with no discount would look similar to:

      TransactionTypeCode SalesItemDesc Qty ListPrice Tax PricePaid
      SALES_ITEM Pizza Vegetarian 2 10.00 3.33 20.00

      Charged and free modifiers

      For charged modifiers, include the "ListPrice", "PricePaid" and "Tax" for the modifier separately from the related SALES_ITEM. For example:

      TransactionTypeCode SalesItemDesc Qty ListPrice Tax PricePaid
      SALES_ITEM Pizza Vegetarian 2 10.00 3.33 20.00
      MODIFIER_ITEM Olives 1 1.00 .17 1.00

      For free modifiers, use "0" for the "ListPrice", "PricePaid" and "Tax".  All modifiers should also have their own "salesitemPLU", regardless of whether they are charged or free.

      The following example shows one person dining with charged and free modifiers.

      02: Example simple with modifiers

      Discount a sales item or modifier

      The preferred way to discount an item is to use the transaction type DISC_ITEM.

      Important fields for deductions are:

      • "SalesItemPLU" and "SalesItemDesc" identify the item the deduction applies to. You should also include the categorization for the item ("MajorGroupDesc", "FamilyGroupDesc" and "SubGroupDesc").
      • "DeductionCode" and "DeductionDesc" identify the type of deduction.
      • "Qty" is the number of discounts (of the same type) used by the diners.
      • "Deduction" is the value of the deduction, for example "5" for 5 pounds off of the item. This is a positive value. It is also the cumulative total of the discount; that is, the value of the deduction x "Qty".  For example:
      TransactionTypeCode DeductionCode DeductionDesc Qty Deduction
      DISC_ITEM 300 £2 off pizza 2 4
      DISC_ITEM 301 £1 off pasta 1 1

      The original food or drink item must include the deduction in the "PricePaid" column. For example:

      TransactionTypeCode SalesItemDesc Qty ListPrice PricePaid Deduction
      SALES_ITEM Pasta Vegetarian 1 10.00 6.50 0
      DISC_ITEM Pasta Vegetarian 1 0 0 3.50

      03: Example with discounted items

      Add a discount to part or all of the bill

      Where possible, a discount should always be recorded against the sales item that it applied to. However, there are of course situations where a discount is applied across part or all of an entire bill.

      To record a discount that goes against the entire bill, rather than one a specific item, then you MUST have values for these fields:

      • "TransactionTypeCode": Must be "DISC_ITEM"
      • "DeductionCode": For example, "410".
      • "DeductionDesc": For example, "20% off food items".
      • "Qty: Number of this type of deduction.
      • "Deduction": The full amount deducted from the check.
      • "OrderTypeDesc": For example, "EAT IN".

      You do not need values for:

      • "SalesItemPLU"
      • "SalesItemGUID"
      • "SalesItemDesc"
      • "MenuBand"
      • "MajorGroupDesc"
      • "FamilyGroupDesc"
      • "SubGroupDesc"

      For the individual sales items and modifiers, you MUST remove the percentage discount amount from their "PricePaid". The TAB_CLOSE must show the total paid after the discount is applied. For example:

      TransactionTypeCode SalesItemDesc DeductionDesc Qty ListPrice PricePaid Deduction
      SALES_ITEM Pasta Vegetarian   1 10.00 8.00 0
      SALES_ITEM Latte   1 3.50 2.80 0
      DISC_ITEM Discount 20% off Tuesdays 1 0 0 2.70
      TAB_CLOSE     2 13.50 10.80 0

      04: Example with discount applied to across the check

      Calculate UK tax

      The tax field is used for the actual tax paid by the diner after any discounts. For example (where the VAT for all items is set at 20%):

      TransactionTypeCode SalesItemDesc Qty ListPrice Tax PricePaid Deduction
      SALES_ITEM Fanta 1 2.50 0.42 2.50 0
      SALES_ITEM Cola 2 2.50 0.83 5.00 0
      SALES_ITEM Pasta ham 1 10.00 1.67 10.00 0
      SALES_ITEM Pizza Vegetarian 1 10.00 1.08 6.50 0
      DISC_ITEM Pizza Vegetarian 1 0 0 0 3.50
      TAB_CLOSE   5 27.50 4.00 24.00  

      Void an item before any prep

      Use the VOID_ERROR transaction type to void items where no prep has occurred; for example, when a diner changes their order before the kitchen has started on the meal.

      The values for voided items must be negative. For example, if a server adds two colas to a check and then realises it should only be one, the values would be:

      TransactionTypeCode SalesItemDesc Qty ListPrice Tax PricePaid
      SALES_ITEM Cola 2 2.50 0.83 5.00
      VOID_ERROR Cola -1 -2.50 -0.41 -2.50

      Modifiers (MODIFIER_ITEM) are voided in the same way as sales items (SALES_ITEM).

      Voids SHOULD if possible include a description and code for the void. These values are visible to customers in Fourth and help them make decisions about their services. Use the deduction fields for these:

      • "DeductionCode": for example, "500".
      • "DeductionDesc": for example, "void before service"

      However, do not set a value for "Deduction". This should remain "0".

      05: Example voids

      Void an item after prep

      Use these transaction types to void items where prep has occurred.

      • VOID_ITEM — voids an item where prep occured but the item can go back into stock; e.g. an unopened bottle of beer the diner no longer wants.
      • VOID_WASTE, VOID_WASTE2 to VOID_WASTE10  — voids an item where it cannot be resold. Each customer self-determines what they wish VOID_WASTE2 to VOID_WASTE10 to refer to.

      Learn more VOID_WASTE categorization

      The values for voided items must be negative. For example:

      TransactionTypeCode SalesItemDesc Qty ListPrice Tax PricePaid
      SALES_ITEM Pizza 1 10.00 1.67 10.00
      VOID_WASTE Pizza -1 -10.00 -1.67 -10.00

      Modifiers (MODIFIER_ITEM) are voided in the same way as sales items (SALES_ITEM).

      Voids SHOULD if possible include a description and code for the void. These values are visible to customers in Fourth and help them make decisions about their services. Use the deduction fields for these:

      • deductioncode: for example, "600".
      • deductiondesc: for example, "Customer rejected" or "Ingredient contamination".

      However, do not set a value for "deduction". This should remain "0".

      05: Example voids

      Void an item not assigned to a specific check

      Sometimes the restaurant may need to void items that were not assigned to a specific check. For example:

      • A bottle of spirits accidentally knocked over
      • Bread rolls accidentally burnt in the oven

      You can void these items outside of a tab using VOID_WASTE11. When doing so, set the RecordActivityCode to "1", provide the quantity of wastage, and the sales value of the voided items in PricePaid.

      TransactionTypeCode RecordActivityCode SalesItemDesc Qty ListPrice Tax PricePaid
      VOID_WASTE11 1 Bread Roll -12 0 0 -18.00
      VOID_WASTE11 1 House white bottle -1 0 0 -22.00

      Transaction IDs: If you intend to allow customers to void items outside of a transaction, please ensure that you have checked that your transaction IDs cannot accidentally be duplicated. For example, if you are dynamically creating transaction IDs using data from the transaction, you may need to also include your own incremental count, to ensure that multiple voids for the same item type does not end up using the same transaction ID.

      06 Example voids outside tab

      Add a tip or service charge

      Service charges are recorded using the SERVICE_CHARGE transaction type. This allows our mutual customers to review tips and charges via Fourth Analytics.

      The charge is listed in "TenderAmount". Provide only the paid amount for the service charge, not the requested amount. If no service charge was collected, use "0".

      The TENDER transaction type can include or exclude the service charge in its "tenderAmount". If TENDER:

      • Includes the service charge paid, then you MUST include a SERVICE_CHARGE transaction showing the value of the service charge.
      • Doesn't include service charge paid, then it is optional to include SERVICE_CHARGE transactions.

      When integrating, please let us know if your tender includes the service charge, so that we can configure our system to provide the meal-only tender value to our customers.

      For the TAB_CLOSE totals, Do NOT include the service charge. For example, in the following, the diners receive a check for £27.50. However, the "PricePaid "and "TenderAmount" for TAB_CLOSE is £25.00.

      TransactionTypeCode SalesItemDesc Qty ListPrice Tax PricePaid TenderAmount
      SALES_ITEM Pizza 2 10.00 3.34 20.00  
      SALES_ITEM Fanta 2 2.50 0.83 5.00  
      SERVICE_CHARGE           2.50
      TENDER           27.50
      TAB_CLOSE   4 25.00 3.34 25.00 25.00

      07: Example with service charge

      Add mains away and bill printing data

      If possible, include MAINS_AWAY and PRINT_CHECK transactions in your dataset to help your customer better understand their diners' behaviour.

      Use the MAINS_AWAY transaction type to timestamp when the kitchen is instructed to begin prepping the next course of a meal. Use the PRINT_CHECK transaction type to timestamp when the server prints the check (used in conjunction with TENDER or TAB_CLOSE to see how long the customer waited to pay the bill).

      For Fourth and the customer, the primary piece of information we need for each of these events is the "Time". Aside from the fields that are mandatory for all transaction types — such "TransactionId" — there are no additional fields you need to enter.

      08: Example with Mains Away and Print Check

      Add payment details

      Use the TENDER transaction type to add payment details. Specify the received payment with these fields:

      • "TenderTypeCode"
      • "TenderTypeDesc"
      • "TenderAmount"

      You MUST advise us whether you will include the service charge in the tender amount; see Add a tip or service charge above for details.

      Most POS partners do not include the service charge in the tender amount. For example, the full amount these diners paid is £45.00, but the TENDER values exclude the service charge.

      TransactionTypeCode PricePaid TenderTypeCode TenderTypeDesc TenderAmount
      SERVICE_CHARGE       5.00
      TENDER   1 CASH 20.00
      TENDER   2 VISA 20.00
      TAB_CLOSE 40.00      

      09: Example tenders

      Include dine-and-dash or other missed payment events

      The value for "PricePaid" should always show the received payment. This means that If for some reason the diners do not pay all or part of the check, this value will be lower than expected. For example, if the diners leave without paying at all:

      TransactionTypeCode Qty ListPrice Tax PricePaid
      SALES_ITEM 2 10.00 0 0
      SALES_ITEM 2 2.50 0 0
      TAB_CLOSE 4 25.00 0 0

      Troubleshooting & FAQs


      How should we handle accounts left open overnight?

      For the most accurate stock results, we would recommend that all checks are closed off. If not, there will be an impact, as Inventory will only report on what it has been sent. This could cause confusion for your customers / end users if sales received don’t actually apply to the stock period they are reviewing.

      My POS submission has suddenly stopped working, what error may cause this?

      One of the most common updates that may cause an issue is the sudden introduction of double quotes (") in one of the fields. For example, this can happen when new items are added to the menu. To troubleshoot this:

      • Open your .CSV file in notepad to confirm that each field is double-quote separated.
      • Check that NONE of your fields include double quotes as part of the text content. For example, if you have a SalesItemDesc that is 10" pizza this will cause the file corruption. Instead, use a word such as inch instead of " for inches. (This may be easier to check in Excel or similar; however, this will strip out the double-quotes separating the fields.)

      What is the retention period for the submitted CSV files?

      The POS Gateway stores sales data for processing, analytics and other uses for two years. Note that this means you can send updates for sales data for up to two years in the past if necessary.

      What happens if I upload a new sales data file with the same data from a previous day?

      "Say I upload a file salesdata1.csv for today’s data, then after a while find something wrong. So, I upload a file salesdata2.csv for today’s data, then I want to fix yesterday’s data, so then upload a file salesdata3.csv for yesterday’s data. Are all three files processed? Is salesdata2.csv processed after salesdata1.csv?"

      The newly submitted sales data will overwrite any existing data. However, to do this, the transaction IDs MUST match the existing records you are updating. If you submit data for the same day multiple times, and the transaction IDs are different, then instead of overwriting the exisitng records, new records are created.

      Do you support HTTP or only HTTPS for the POS Transaction API?

      The POS Transaction API continues to support HTTP connections until otherwise notified. However, we strongly recommend that existing partners move to using HTTPS. As well, new integrations should only use HTTPS.