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. A lone comma or dot followed by exactly three digits groups thousands (1.234 → 1234); otherwise it is decimal, and with both separators the last is decimal. 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.

The target also says what happens when no line matched. With "Send nothing", Steve sends that target nothing for the receipt. This also holds when matching was skipped, by an admin or because the product catalog was switched off. Other targets are not affected. It applies when a delivery is first planned: a body Steve already sent, or is retrying, is sent again unchanged, because Open Loyalty may already hold it.

When the product catalog is switched off

The product catalog is a module an organization can switch off and on again. Submissions keep moving while it is off:

  • A submission whose matching is not finished (still running, waiting for a reviewer, or failed) is skipped at the next step that touches it: approval, a reviewer edit, or the matching run itself. Approval is allowed; nobody has to decide lines or skip matching first.
  • Until then, matchedItems shows the lines that are already matched. Once matching is skipped, it is [], so a submission.approved event can list fewer lines than the session.review_required event before it.
  • A submission whose matching was already complete keeps its matches, and they are sent as before.
  • Switching the catalog back on matches new receipts again. A receipt that was skipped while it was off stays skipped, and approved submissions do not change.

On this page