Skip to main content

Loss Prevention on Lane POS - Integration Guide

Last updated by Sahil Pahuja on March 7th, 2025

Overview

This document provides vendors with insights into the Edgify API endpoints for implementing Loss Prevention on Lane POS. Its purpose is to offer an understanding of the functionality and facilitate the estimation of integration efforts.

Who Should Read This Document?

This document is intended for developers and teams responsible for integrating the Edgify Agent with POS application software. It can also be helpful to non-technical individuals who wish to understand the relationship and flow between the Edgify Agent, hardware, and customers in a store environment.

Solution Description

The Edgify Agent is the active software component in the Edgify solution, with which the POS application will communicate. Outputs prediction objects when called by the application software.

The Edgify Agent can be installed on Microsoft Windows OS, where it will run as a service, or on most modern Linux distros that support Docker, where it runs within a Docker container.

API Flow for Integration by the POS App

POST /events - Session State Management

POST http://localhost:8090/api/v2/events

This endpoint (with various payloads) should be called upon the beginning and end of each shopper session, as well as during meaningful events in the flow. It will notify Edgify upon important events in the POS flow so that Edgify can analyze or ignore certain shopper or attendant interactions throughout the shopper's session.

First interaction: Notifies the beginning of a shopper session.

{
"name": "StartCustomerSession",
"transactionId": "12345"
"shopperId": "<shopper-loyalty-card-id>"
"assistantId": "<assistant-001>"
}

Notes:

  • transactionId is not a mandatory field
  • shopperId or assistantId are not mandatory fields.
  • shopperId is used for hybrid tills on the Lane PoS.

This API should be called when the shopper starts interacting with the POS. This endpoint allows the system to start analyzing the video feed from the Edgify camera. The "transactionId" field is optional in case you want to correlate the POS application's transaction ids with Edgify's session ids. You can also pass this transaction id at a later time during the session (during the subsequent calls below such as the payment or end of the session).

Event: Pay Now: Notifies the shopper wishes to pay

{
"name": "PayNow",
"transactionId": "12345"
}

Should be called when the shopper opts for the “pay now” option. This endpoint allows the system to process a Loss Prevention analysis prior to the payment process. Edgify will be able to understand the context and will know not to trigger motion alerts while the shopper is handling payments. The "transactionId" field is optional in case you want to correlate the POS application's transaction ids with Edgify's session ids. You can pass this transaction id at any time during the session.

Event: Last interaction: Marks the end of a session.

{
"name": "StopCustomerSession",
"transactionId": "12345"
}

This API should be called when the shopper stops interacting with the POS. This endpoint allows the system to stop analyzing the video feed from the Edgify camera and regard the current feed as a single shopper session. It is best to use the “Thank You” screen. Note: If this event is not passed after a configurable time period, the Edgify system will automatically handle a session timeout and close the session. The "transactionId" field is optional in case you want to correlate the POS application's transaction IDs with Edgify's session IDs. You can pass this transaction ID at any time during the session.

Event: Start intervention: Notifies the beginning of a manager intervention

{
"name": "StartIntervention",
"transactionId": "12345"
"assistantId": "<assistant-001>"
}

Should be called when the attendant intervenes with the shopper session. This endpoint allows the system to identify all the following actions as attendant actions and not raise loss prevention issues during the attendant intervention. The "transactionId" field is optional in case you want to correlate the POS application's transaction ids with Edgify's session ids. You can pass this transaction id at any time during the session.

Event: Stop intervention: Marks the end of a manager intervention.

{
"name": "StopIntervention",
"transactionId": "12345"
}

Should be called when the attendant stops the intervention mode with the shopper session. This endpoint allows the system to identify the attendant intervention. The "transactionId" field is optional in case you want to correlate the POS application's transaction ids with Edgify's session ids. You can pass this transaction id at any time during the session.

POST /capture-and-save

Endpoint

POST http://localhost:8090/api/v2/capture-and-save

Description :

This endpoint's primary function is to capture an image from the camera feed and save it with a unique sample ID. It records essential item details, including barcode, category, weight, price, and image source. Upon successful storage, the system returns a unique sample ID.

Request Body Example:

{
"barcode": "ABC1234",
"captureTrigger": "barcode",
"category": "Drinks",
"count": 1,
"family": "Milk",
"groupId": "b932de54-41ca-4f5a-99d5-b9db779f8888",
"imgSource": "ip-camera-SCO-1",
"label": "4201",
"labelTrigger": "RegularMenuSelection",
"name": "Org Milk",
"price": 0.95,
"totalPrice": 0.95,
}

Notes:

  • "groupId" is not a mandatory field

Request Body Parameters

ParameterExplanationValues (Explanation)
barcodeUnique identifier of the productString: (E.g., "ABC1234")
captureTriggerMechanism/flow which prompted the capturemenu: (Triggered via menu selection)
categoryThe category of the itemDrinks: (Indicates Drink items)
countThe number of items capturedInteger: (E.g., 1)
familyThe family classification of the itemFruits: (Belongs to the Milk family)
groupIdUnique identifier for the group the item belongs toString: (E.g., "b932de54-41ca-4f5a-99d5-b9db779f8888")
imgSourceSource of the image captureString: (E.g., "ip-camera-SCO-1")
labelLabel identifier for the productString: (E.g., "4201")
labelTriggerMechanism that triggered the label assignmentRegularMenuSelection: (Label assigned through regular menu selection)
nameName of the itemString: (E.g., "Org Milk")
priceUnit price of the itemFloat: (E.g., 0.95)
totalPriceTotal price after discounts or adjustmentsFloat: (E.g., 0.95)

Response Body Parameters

ParameterExplanation
sampleIdUnique identifier for the stored sample

Response Example

The response is a JSON object containing a unique sampleId.

{
"sampleId": "9c9847e6-591b-4f29-a988-922da9e56484"
}

PATCH /sample - Barcode input

PATCH http://localhost:8090/api/v2/samples/{sample_id}

This endpoint should be called only for existing samples. ANY field can be passed in the body for updating this sample’s data or for adding any additional metadata. Do not call this endpoint for a sample id that doesn't exist.

Calling PATCH sample, will require only the sample id (in the url) and should allow the developer to add or update any field. This PATCH method will not have any match strength response.

Can be called with each barcode scan once the application gets additional metadata it wants to append and pass to Edgify. This endpoint updates the matching sample data using the sample id provided by the previous capture-and-predict response.

Example Request (Barcode):

ANY of the following fields can be passed, all of them are OPTIONAL:

{
"barcode": "53453534535224",
"captureTrigger": "barcode",
"category": "drinks",
"count": 2,
"family": "Drinks",
"image": base64 image
"label": "4245401",
"labelTrigger": "barcode_scanner",
"name": "Coca-Cola 1.5L",
"price": 2.95,
"totalPrice": 2.95,
}

Example Response (Barcoded items):

Success: 200 - Existing sample was changed

Error codes: 400 - Bad request (e.g. bad format in the body fields)

{
"errors": [
"string"
]
}

401 - Unauthorized

"string"

404 - Sample does not exist

{
"errors": [
"string"
]
}

500 - Internal Server Error

{
"errors": [
"string"
]
}

DELETE /sample

DELETE http://localhost:8090/api/v2/samples/{sample_id}

Description : Deletes the passed Sample from the Edgify system. For specialized use cases. Please consult your Customer Success Team.

Webhook APIs for Loss Alerts

To handle alerts, ensure your application is configured to serve the different types of webhook alert endpoints and can accept the body as described below.

As part of the integration, ensure your application can:

  • Accept requests at the relevant endpoint.
  • Parse the incoming JSON payload.
  • Validate the payload structure and data types.
  • Store or process the relevant information as needed by your application.
  • Respond with appropriate HTTP status codes.
  • Log errors for troubleshooting

You can use tools like Postman to simulate webhook requests and test the endpoint.

Webhook - Alert Non-Match

The "Alert Non-Match" webhook is triggered when a discrepancy is detected between the image and the barcode scan. It provides detailed information about the mismatch, including images captured during the event. The image is stored in Base64 format.

POST http://localhost:3050/alert-non-match

Request body example: The webhook will send a JSON payload with the following structure:

{
"issueId": "b613a9b9-ff88-4949-9110-67232af9df93",
"label": "ABC",
"name": "Kool-Aid",
"capturedAt": "2024-05-16T15:04:05.000Z",
"predictedLabel": "XYZ",
"predictedName": "Lego",
"image": "<base64 image>"
}

Webhook - Alert Non-Scan:

The "Alert Non-Scan" webhook is triggered when an expected scan does not occur. It provides information about the non-scan event, including the relevant images captured. The image is stored in Base64 format.

POST http://localhost:3050/alert-non-scan

Request body example: The webhook will send a JSON payload with the following structure:

{
"issueId": "b613a9b9-ff88-4949-9110-67232af9df94",
"capturedAt": "2024-05-16T15:04:05.000Z",
"predictedLabel": "",
"predictedName": "",
"images": ["<base64 image>","<base64 image>"],
"representativeImg": "<base64 image>"
}

Sending a Response Event

Once a user interacts with the alert, the system must send an HTTP POST request to our webhook with the selected response

Response Event Types

Event TypeDescription
Assistant ConfirmedStore assistant confirms the loss event
Assistant RejectedStore assistant rejects the loss event
Shopper ConfirmedShopper confirms the loss event
Shopper RejectedShopper rejects the loss event

Response Payload Format

The system must send the response payload in the following format:

Response from Assistant screens

{
"name": "Assistant Confirmed",
"groupId": "<the groupId received in the alert body>",
"assistantId": "assistant-001",
}

Response from Shopper screens

{
"name": "Shopper Confirmed",
"groupId": "<the groupId received in the alert body>",
"shopperId": "<shopper-loyalty-card-id>",
}

Notes:

  • Ensure your application can handle and process base64 encoded images.
  • assistantId or shopperId are not mandatory fields.
  • Response from Shopper screen is relevant only for hybrid PoS checkout.

The API is controlled through the config.yaml parameters:

Webhooks: enabled: true url: http://localhost:3050