SteveSteve

Product Matching

How Steve matches receipt lines to your product catalog and what the matchedItems list holds.

A receipt has about twenty lines and only a few of them are your products. When a workflow has product matching turned on, Steve compares every line with your company's product catalog and puts your catalog SKU on the lines it recognises. The same SKUs go to Open Loyalty, to webhooks and to the submissions API.

Matching is set per workflow. Workflows without it keep sending the receipt data as read, and their matchedItems list is always empty.

Where matches appear

WhereField
GET /api/v1/submissionsdata[].matchedItems
GET /api/v1/submissions/{submissionId}matchedItems
GET /api/v1/jobs/{sessionId}result.matchedItems
Webhook events about a submissionresult.matchedItems

The matchedItems entry

{
  "field": "items",
  "index": 1,
  "text": "MLK UHT 3.2% MD 1L x2",
  "sku": "MD-MLK-032-1L",
  "name": "Mleko UHT 3,2% 1 l",
  "category": "Dairy",
  "maker": "Mleczna Dolina",
  "quantity": 2,
  "amount": 9.98,
  "discount": -4.99,
  "netAmount": 4.99,
  "matchedBy": "exact_alias",
  "confidence": 1
}
  • field and index address the line in extractedData: extractedData[field][index]. The index is 0-based and counts every line, including the ones that are not yours.
  • text is the line as Steve read it from the receipt.
  • sku, name, category and maker come from your catalog.
  • amount is the line total as read. discount is the sum of the discount lines Steve linked to this line, as a negative number, or null when there are none. netAmount is amount plus discount. A discount that applies to the whole receipt is not attributed to any line here.
  • matchedBy says how the line was matched: exact_alias (a known receipt spelling or the EAN), fuzzy (a similar name the workflow accepts on its own), llm (an AI choice from a short list of your products) or reviewer (a person chose the product).
  • confidence is between 0 and 1, or null.

Which lines are listed

Only lines matched to one of your products appear. Lines that belong to other brands, discount lines, deposits and returns never do.

Steve does not guess. When it is unsure, the line waits for a reviewer, and the submission stays in review until every such line is decided. Before approval, matchedItems lists only the lines that are already matched, so a session.review_required event can list fewer lines than the later submission.approved event.

Once a submission is approved, its matched products are fixed. Renaming or archiving a catalog product afterwards does not change what the submission reports or what Open Loyalty received.

Open Loyalty

By default Open Loyalty gets the whole receipt as transaction items, with your catalog SKU, name, category and maker on the matched lines. Discounts linked to a line are netted into that line's value. A workflow can instead send only the matched lines. That changes the basket total, and therefore the rewards, so it is a separate setting on the Open Loyalty target.

On this page