In-store checkout code scans
Checkout code scans let you block in-store payment until Instacart successfully validates one or more codes sent by your point-of-sale system (POS). Implementing this API ensures your system gets the data it needs to perform specific business operations, such as tax suppression and loyalty program management, and can also help reduce your exposure to fraud.
How it works
After the shopper finishes picking and the fulfillment order moves into a checkout state, Instacart generates a code that contains data needed by your system and stores it for later retrieval. At approximately the same time, Instacart puts a hold on the assigned shopper’s payment card. This hold helps prevent unauthorized use of the card and enforces data collection. It remains in place until your POS scans a barcode in the Instacart Shopper App, extracts the embedded code, passes it in a code scans request, and Instacart successfully validates that the code exists and that the order is in checkout. If those checks pass, we unblock the card and the shopper is authorized to make payment.
However, if the code can’t be validated (perhaps because the shopper attempted to skip the scan and the request was never sent, the code doesn’t exist in Instacart’s databases, the order isn’t in checkout, or network issues resulted in repeated call failures) the block remains on the card and shoppers must contact Instacart’s customer service to be granted an override.
Use cases
Check out code scans have two primary use cases:
| Use case | What the scan does |
|---|---|
| Tax suppression | Provides a signal to your tax management system to not collect sales tax on a transaction |
| Loyalty program management | Provides a signal to your system to manage loyalty benefits, such as applying discounts or earned points |
Tax suppression
Sales tax on an Instacart-fulfilled order is typically collected by the online POS. If your in-store POS taxes the order again, a complex reconciliation process is required. Checkout code scans help solve this double-taxation problem by signaling to your POS that the tax line needs to be removed.
If the scan fails, Instacart uses the receipt photo captured by the shopper to generate an invoice, which we then provide to you after the transaction is finalized.
The following is one example of how an order might successfully move through a tax suppression flow:
- Instacart generates and stores a checkout code and places a hold on payment.
- After picking is complete, the Shopper App displays the checkout code in barcode format.
- Shoppers present the barcode at the checkout register.
- Before payment is tendered, your POS scans the barcode, extracts the embedded code and, in separate calls, provides it to Instacart and your tax management system.
- Before unblocking payment, Instacart verifies that the code exists and the order is in checkout.
- Instacart signals to your POS that the code has been successfully validated.
- The Shopper App prompts shoppers to make payment.
- Your POS sends the finalized transaction record for reconciliation purposes.
Loyalty program management
Many loyalty programs require that information on participating customers be collected in-store by the POS. This lets the program find the correct account and apply discounts or earned benefits.
At checkout, the Shopper App can encode the customer’s loyalty identifier in barcode format for the shopper to present at checkout. However, if the scan is skipped, the customer won’t receive their points or member benefits. And if the shopper scans a different loyalty barcode, the benefits may go to the wrong account.
Checkout code scans can help solve these problems. The code identifies the transaction as an Instacart order and contains the data your loyalty system needs to look up the customer's account. And because the shopper's payment card is blocked until Instacart has validated the POS-submitted code, each Instacart-fulfilled order is forced through your loyalty flow.
The following is one example of how an order might successfully move through a loyalty program management flow:
- Instacart generates and stores a checkout code and places a hold on payment.
- After picking is complete, the Shopper App displays the checkout code in barcode format.
- Shoppers present the barcode at the checkout register.
- Before payment is tendered, your POS scans the barcode, extracts the embedded code and, in separate calls, provides it to Instacart and your loyalty management system.
- Before unblocking payment, Instacart verifies that the code exists and the order is in checkout.
- Instacart signals to your POS that the code has been successfully validated.
- The Shopper App prompts shoppers to make payment.
- Your POS sends the finalized transaction record for reconciliation purposes.
Checkout code considerations
The code embedded in the Shopper App’s barcode must be passed to Instacart verbatim. If you perform any transformations on it, you risk getting an error.
Additionally, the code scans request accepts an array of codes. This lets you implement flows such as tax suppression and loyalty management in parallel. Plus, by sending all the codes in a single request, you avoid unnecessary orchestration at the POS layer.
Who generates the checkout codes, the data they contain, and their format are all configurable. In most cases, Instacart generates them. After an order enters the checkout state, a job runs that creates a code specific to your use case. However, if you need to generate your own code, you do have the option of providing Instacart a retrieval endpoint. The format and the encoded data are also implementation-specific. During onboarding, work with your Instacart development team to add any needed prefixes and encoding schemes.
Understanding Scan Failures
A checkout code scans response whose status code is 200 but whose body holds a status of Error signifies a service-level error. Typically they happen when the code isn’t registered in the appropriate database or it’s associated with an order in a non-checkout state.
{
"status": "Error",
"errors": [
{
"scan_code": "90150ac455ac456b3814b6e247c03c092fe4bc23704e71c505b93b16f0169",
"error_code": "1002",
"error": "Code is not found in the system"
}
]
}
On the other hand, API-level errors, which adhere to the standard Connect format, are always hard failures. They are triggered by missing fields or improperly formatted timestamps.
{
"error": {
"message": "There were issues with your request",
"code": 9999,
"errors": [
{
"error": {
"message": "is not a valid ISO 8601 formatted timestamp",
"code": 1001
},
"meta": {
"key": "code_scans[0].scan_time"
}
},
{
"error": {
"message": "can't be blank",
"code": 1001
},
"meta": {
"key": "store_id"
}
}
]
},
"meta": {}
}
However, both API-level and service-level errors produce the same result: The shopper’s payment card remains blocked.