| Previous Topic | Next Topic | |
|---|---|---|
| POS Module 8a: Receipt Details - Example Scenarios | POS Module 8b: Updating/Voiding Transactions - Example Scenarios |
POS API Certification Tutorial - Module 8b: Updating/Voiding Transactions - Concepts
Goal
Update the details of a transaction or cancel the transaction.
Prerequisites
-
You must have read the Module 7: Check-in, Module 8a: Receipt Details and Module 6c: Voiding Redemptions tutorials.
-
You should confirm with your Punchh representative that “Pending Check-ins” is properly configured in the Punchh platform for the brand/business before configuring the POS with the ability to update and void a transaction.
Use Cases and Context
-
After completing a transaction and printing the receipt, the store must give a discount to the guest on an item, resulting in the receipt amount changing from $10 to $8. The POS operator updates the check to reflect the discount on the check, and the POS makes another Receipt Details call with the same transaction. If the guest is a loyalty guest, the loyalty earnings of the guest will change. The Receipt Details call grants the guest points on $8 instead of $10.
-
A loyalty guest asks the POS operator at the convenience store to cancel the transaction after the receipt is printed. When the POS operator cancels the transaction, the POS checks if the pending points window is open as a transaction can be canceled within the pending points window. If the pending points window is not open, the POS cancels the transaction. Any points earned for the transaction by the guest are reversed, and if the guest redeemed any offer, the POS returns the offer to the guest’s account by voiding the redemption.
Applicable API Endpoints
| Endpoint Name/Path | Relevant Request Parameters | Relevant Response Parameters |
| Receipt Details POST {server-name}/receipt_details |
transaction_no amount receipt_datetime subtotal_amount payable status The required parameters under the Menu Items object: - item_name - item_qty - item_amount - menu_item_type - menu_item_id - menu_family - menu_major_group - serial_number |
N/A |
Example Code
Updating Transactions
Please note the later time value for "receipt_datetime" and the price change for "Item 2".
curl --location --request POST 'https://SERVER_NAME_GOES_HERE.punchh.com/receipt_details' \
--header 'Content-Type: application/json' \
--header 'Authorization: Token token=LOCATION_KEY_GOES_HERE, btoken=BUSINESS_KEY_GOES_HERE' \
--header 'User-Agent: Brink/POS/1.0' \
--data-raw '{
"pos_version": "v1",
"sequence_no": "1111",
"transaction_no": "111111111",
"receipt_datetime": "2022-06-30T01:30:00-07:00",
"menu_items": [
{
"item_name": "Cheese Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "M",
"menu_item_id": 1111,
"menu_family": "001",
"menu_major_group": "001",
"serial_number": "1.0"
},
{
"item_name": "BBQ Wings",
"item_qty": 1,
"item_amount": 5.86,
"menu_item_type": "M",
"menu_item_id": 2222,
"menu_family": "002",
"menu_major_group": "002",
"serial_number": "2.0"
},
{
"item_name": "Free Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "D",
"menu_item_id": 3333,
"menu_family": "003",
"menu_major_group": "003",
"serial_number": "3.0"
}
],
"employee_id": "001",
"employee_name": "EMPLOYEE_NAME_GOES_HERE",
"subtotal_amount": 5.86,
"receipt_amount": 5.86,
"cc_last4": "0001",
"punchh_key": "PUNCHH_KEY_GOES_HERE",
"pos_type": "brink",
"external_uid": "EXTERNAL_UID_GOES_HERE",
"process": "true",
"channel": "pos"
}'
let requestBody = {
'pos_version': 'v1',
'sequence_no': '1111',
'transaction_no': '111111111',
'receipt_datetime': '2022-06-30T01:30:00-07:00',
'menu_items': [
{
'item_name': 'Cheese Pizza',
'item_qty': 1,
'item_amount': 2.86,
'menu_item_type': 'M',
'menu_item_id': 1111,
'menu_family': '001',
'menu_major_group': '001',
'serial_number': '1.0'
},
{
'item_name': 'BBQ Wings',
'item_qty': 1,
'item_amount': 5.86,
'menu_item_type': 'M',
'menu_item_id': 2222,
'menu_family': '002',
'menu_major_group': '002',
'serial_number': '2.0'
},
{
'item_name': 'Free Pizza',
'item_qty': 1,
'item_amount': 2.86,
'menu_item_type': 'D',
'menu_item_id': 3333,
'menu_family': '003',
'menu_major_group': '003',
'serial_number': '3.0'
}
],
'employee_id': '001',
'employee_name': 'EMPLOYEE_NAME_GOES_HERE',
'subtotal_amount': 5.86,
'receipt_amount': 5.86,
'cc_last4': '0001',
'punchh_key': 'PUNCHH_KEY_GOES_HERE',
'pos_type': 'brink',
'external_uid': 'EXTERNAL_UID_GOES_HERE',
'process': 'true',
'channel': 'pos'
};
const url = 'https://SERVER_NAME_GOES_HERE.punchh.com/receipt_details';
let headers = {
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
'Authorization': 'Token token=LOCATION_KEY_GOES_HERE, btoken=BUSINESS_KEY_GOES_HERE',
'User-Agent': 'Brink/POS/1.0'
};
let options = {
method: 'POST',
headers: headers,
body: JSON.stringify(requestBody)
};
fetch(url, options)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
# You will need to install the Requests package before this code will work.
# To do so, see the installation instructions here: https://requests.readthedocs.io/en/latest/user/install/#install
import requests
import json
url = "https://SERVER_NAME_GOES_HERE.punchh.com/receipt_details"
payload = json.dumps({
"pos_version": "v1",
"sequence_no": "1111",
"transaction_no": "111111111",
"receipt_datetime": "2022-06-30T01:30:00-07:00",
"menu_items": [
{
"item_name": "Cheese Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "M",
"menu_item_id": 1111,
"menu_family": "001",
"menu_major_group": "001",
"serial_number": "1.0"
},
{
"item_name": "BBQ Wings",
"item_qty": 1,
"item_amount": 5.86,
"menu_item_type": "M",
"menu_item_id": 2222,
"menu_family": "002",
"menu_major_group": "002",
"serial_number": "2.0"
},
{
"item_name": "Free Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "D",
"menu_item_id": 3333,
"menu_family": "003",
"menu_major_group": "003",
"serial_number": "3.0"
}
],
"employee_id": "001",
"employee_name": "EMPLOYEE_NAME_GOES_HERE",
"subtotal_amount": 5.86,
"receipt_amount": 5.86,
"cc_last4": "0001",
"punchh_key": "PUNCHH_KEY_GOES_HERE",
"pos_type": "brink",
"external_uid": "EXTERNAL_UID_GOES_HERE",
"process": "true",
"channel": "pos"
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'Token token=LOCATION_KEY_GOES_HERE, btoken=BUSINESS_KEY_GOES_HERE',
'User-Agent': 'Brink/POS/1.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(f"{response.status_code} {response.text}")
Voiding Transactions
curl --location --request POST 'https://SERVER_NAME_GOES_HERE.punchh.com/receipt_details' \
--header 'Content-Type: application/json' \
--header 'Authorization: Token token=LOCATION_KEY_GOES_HERE, btoken=BUSINESS_KEY_GOES_HERE' \
--header 'User-Agent: Brink/POS/1.0' \
--data-raw '{
"status": "void",
"pos_version": "v1",
"sequence_no": "1111",
"transaction_no": "111111111",
"receipt_datetime": "2022-06-30T01:30:00-07:00",
"menu_items": [
{
"item_name": "Cheese Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "M",
"menu_item_id": 1111,
"menu_family": "001",
"menu_major_group": "001",
"serial_number": "1.0"
},
{
"item_name": "BBQ Wings",
"item_qty": 1,
"item_amount": 5.86,
"menu_item_type": "M",
"menu_item_id": 2222,
"menu_family": "002",
"menu_major_group": "002",
"serial_number": "2.0"
},
{
"item_name": "Free Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "D",
"menu_item_id": 3333,
"menu_family": "003",
"menu_major_group": "003",
"serial_number": "3.0"
}
],
"employee_id": "001",
"employee_name": "EMPLOYEE_NAME_GOES_HERE",
"subtotal_amount": 5.86,
"receipt_amount": 5.86,
"cc_last4": "0001",
"punchh_key": "PUNCHH_KEY_GOES_HERE",
"pos_type": "brink",
"external_uid": "EXTERNAL_UID_GOES_HERE",
"process": "true",
"channel": "pos"
}'
let requestBody = {
'status': 'void',
'pos_version': 'v1',
'sequence_no': '1111',
'transaction_no': '111111111',
'receipt_datetime': '2022-06-30T01:30:00-07:00',
'menu_items': [
{
'item_name': 'Cheese Pizza',
'item_qty': 1,
'item_amount': 2.86,
'menu_item_type': 'M',
'menu_item_id': 1111,
'menu_family': '001',
'menu_major_group': '001',
'serial_number': '1.0'
},
{
'item_name': 'BBQ Wings',
'item_qty': 1,
'item_amount': 5.86,
'menu_item_type': 'M',
'menu_item_id': 2222,
'menu_family': '002',
'menu_major_group': '002',
'serial_number': '2.0'
},
{
'item_name': 'Free Pizza',
'item_qty': 1,
'item_amount': 2.86,
'menu_item_type': 'D',
'menu_item_id': 3333,
'menu_family': '003',
'menu_major_group': '003',
'serial_number': '3.0'
}
],
'employee_id': '001',
'employee_name': 'EMPLOYEE_NAME_GOES_HERE',
'subtotal_amount': 5.86,
'receipt_amount': 5.86,
'cc_last4': '0001',
'punchh_key': 'PUNCHH_KEY_GOES_HERE',
'pos_type': 'brink',
'external_uid': 'EXTERNAL_UID_GOES_HERE',
'process': 'true',
'channel': 'pos'
};
const url = 'https://SERVER_NAME_GOES_HERE.punchh.com/receipt_details';
let headers = {
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
'Authorization': 'Token token=LOCATION_KEY_GOES_HERE, btoken=BUSINESS_KEY_GOES_HERE',
'User-Agent': 'Brink/POS/1.0'
};
let options = {
method: 'POST',
headers: headers,
body: JSON.stringify(requestBody)
};
fetch(url, options)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
# You will need to install the Requests package before this code will work.
# To do so, see the installation instructions here: https://requests.readthedocs.io/en/latest/user/install/#install
import requests
import json
url = "https://SERVER_NAME_GOES_HERE.punchh.com/receipt_details"
payload = json.dumps({
"status": "void",
"pos_version": "v1",
"sequence_no": "1111",
"transaction_no": "111111111",
"receipt_datetime": "2022-06-30T01:30:00-07:00",
"menu_items": [
{
"item_name": "Cheese Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "M",
"menu_item_id": 1111,
"menu_family": "001",
"menu_major_group": "001",
"serial_number": "1.0"
},
{
"item_name": "BBQ Wings",
"item_qty": 1,
"item_amount": 5.86,
"menu_item_type": "M",
"menu_item_id": 2222,
"menu_family": "002",
"menu_major_group": "002",
"serial_number": "2.0"
},
{
"item_name": "Free Pizza",
"item_qty": 1,
"item_amount": 2.86,
"menu_item_type": "D",
"menu_item_id": 3333,
"menu_family": "003",
"menu_major_group": "003",
"serial_number": "3.0"
}
],
"employee_id": "001",
"employee_name": "EMPLOYEE_NAME_GOES_HERE",
"subtotal_amount": 5.86,
"receipt_amount": 5.86,
"cc_last4": "0001",
"punchh_key": "PUNCHH_KEY_GOES_HERE",
"pos_type": "brink",
"external_uid": "EXTERNAL_UID_GOES_HERE",
"process": "true",
"channel": "pos"
})
headers = {
'Content-Type': 'application/json',
'Authorization': 'Token token=LOCATION_KEY_GOES_HERE, btoken=BUSINESS_KEY_GOES_HERE',
'User-Agent': 'Brink/POS/1.0'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(f"{response.status_code} {response.text}")
Workflow
The Receipt Details API endpoint lets you update or cancel a transaction.
Updating a Transaction
1. After completing a transaction, and sending its receipt details to Punchh, you can update the receipt details. Doing so adds another receipt to the Punchh database and an additional receipt on the Punchh platform under Diagnostic > Barcode Lookup > Barcode Search.
2. Submit another full Receipt Details API call with the same transactional identifiers such as the same values for Punchh key and transaction_no, but reflecting the latest changes. For example, send an identical Receipt Details API call after the initial call that has an extra menu item and increased taxes and payment. For more information about the Punchh key, see Implement the Punchh Barcode and QR Code Algorithm. The POS needs to send the menu items to Punchh in the format prescribed in How To Send Menu Items to Punchh. API developers are responsible for sending the menu item object exactly how Punchh specifies in How To Send Menu Items to Punchh. There is no flexibility in the way menu items are sent in the Receipt Details API call.
Note:
Punchh allows updating a receipt using the Receipt Details call only if the pending points setting is enabled in the Punchh platform. The start time for each check begins upon the first Receipt Details API call or check-in (Create Check-in API call), whichever occurs first. Contact your Punchh representative to determine if "Pending Checkin Strategy" is activated and to confirm the value of the "Receipt Update Delay Minutes" setting.
Here is an example of updating a transaction. The guest wants to order a dessert at a restaurant after the check is paid and closed, and the Receipt Details call for the transaction is sent to Punchh. If the Pending Points setting is enabled for the business and if the order is placed within the pending points window, the POS will call the Receipt Details API again for the same transaction and send the full check details along with the latest changes. Punchh will store two receipts for the same transaction, one without the dessert and one with the dessert. As long as you use the same transaction number and Punchh key in the Receipt Details call and make the call within the pending points window, Punchh will update the transaction in the system. If the guest is a loyalty guest, the Receipt Details API call will change the loyalty earnings.
At first, the Receipt Details API call does not grant loyalty points for a loyalty guest, but if you make updates to the Receipt Details call within the pending points window, and if the amount on which loyalty is earned is changed after updating the check, then the API call will change the earnings for the guest.
Punchh reserves all of the versions of that same receipt, provided that the time between HTTP requests is 1 second or more. However, if the same receipt is received via multiple HTTP calls at about the same time (less than 1 second), the last one received overwrites the previous version of that receipt.
Reconciling Guest Points After the Pending Points Window Has Expired
If you need to reconcile a guest's points after the pending points window has expired or if the Pending Points feature is not enabled, you can use the platform functions API to add (Support Gifting to a User) or subtract (Force Redeem) points from the guest's account.
Voiding a Transaction
After completing a transaction, and sending its receipt details to Punchh, you can void the transaction using the status: void parameter if the Pending Points setting is enabled. Make another Receipt Details call and send the same information that you sent in the previous Receipt Details call with the status parameter as void. Transactions can be voided only within the pending points window (usually within 24 hours). In the case of loyalty guests, voiding a transaction cancels the check-in. If any loyalty points are deducted through redemption, the points are returned to the guest account by voiding the redemption, and any points earned during the check-in by the guest are reversed.
After voiding a receipt, the receipt will display with a red header within the Punchh platform barcode search (Diagnostic > Barcode Lookup > Barcode Search).
Best Practices
Once a transaction is voided/canceled, you must re-submit the transaction without the “void” status to add a new version of the receipt, or further modify the receipt.
Related Topics
Implement the Punchh Barcode and QR Code Algorithm