Review and merges
The pairs matching could not decide alone, and the merges it and your people made. Reading a pair's evidence and the AI judge's answer, merging or dismissing it, and undoing any merge.
Pairs of variants that matching scored in the grey zone, or that carry a decisive conflict, wait
for a person. Review them under Catalogue › Match review, or through the matching API.
Reading needs products:read, which every role holds; merging, dismissing and undoing need
products:write (owners and admins).
A review pair
{
"object": "match_pair",
"id": "mpr_034XqBaL2mRLTZPXyRbaUn",
"status": "open",
"probability": 0.87,
"variants": [
{
"id": "var_034XqBaL2mRLTZPXyRbaUc",
"product": "prod_034XqBaL2mRLTZPXyRbaUb"
},
{
"id": "var_034XqBaL2mRLTZPXyRbaUp",
"product": "prod_034XqBaL2mRLTZPXyRbaUq"
}
],
"evidence": [
{
"comparison": "name",
"level": 3,
"weight": 4.2
},
{
"comparison": "dimensions",
"level": 2,
"weight": 2.9
},
{
"comparison": "brand",
"level": null,
"weight": 0
}
],
"conflicts": [],
"judgement": {
"object": "match_judgement",
"id": "mjd_034XqBaL2mRLTZPXyRbaUr",
"model": "gemini-3.8-flash",
"outcome": "offered",
"choice": "var_034XqBaL2mRLTZPXyRbaUp",
"confidence": 0.82,
"reasons": [
{
"field": "dimensions",
"subject_quote": "84 x 38 x 34 in",
"candidate_quote": "84\" W x 38\" D x 34\" H"
}
],
"note": "below the merge confidence",
"judged_at": "2026-10-06T06:12:03Z"
},
"merge": null,
"created_at": "2026-10-06T06:02:44Z",
"updated_at": "2026-10-06T06:12:03Z"
}
| Property | Meaning |
|---|---|
status | open (waiting), merged, dismissed (a person said they are different items) or stale (answered by a later merge or change). |
probability | The match probability the model scored. |
variants | The two variants, each with the product it belongs to now. |
evidence | Each comparison's agreement level and weight in bits: why it scored so. A null level means one side lacks the field. |
conflicts | Decisive disagreements (another finish, another size). A pair with one is never merged unseen. |
judgement | The AI judge's answer, when it looked: its choice, confidence, quoted reasons, and why its answer was not used. |
merge | The merge a person made from this pair, to undo there. |
GET /v1/match-pairs lists open pairs by default,
most probable first; status picks the others.
Decide
- Merge (
POST /v1/match-pairs/{id}/merge) joins the two as one item. The merge is recorded as decided by a person, named. - Dismiss pair (
POST /v1/match-pairs/{id}/dismiss) says they are different items.
In the dashboard, a pair opens with the two variants side by side, the signals behind the score and the judge's choice, then Merge or Dismiss pair.
Each decision is one step with its audit log entry. Your people's decisions also teach the model: they refine its weights and calibrate its thresholds.
Merges
Every merge, whoever decided it, is listed with how it was decided:
{
"object": "merge",
"id": "mrg_034XqBaL2mRLTZPXyRbaUt",
"survivor": "prod_034XqBaL2mRLTZPXyRbaUb",
"merged": "prod_034XqBaL2mRLTZPXyRbaUq",
"variants": [{ "merged": "var_034XqBaL2mRLTZPXyRbaUp", "into": "var_034XqBaL2mRLTZPXyRbaUc" }],
"decided_by": { "method": "deterministic", "rule": "gtin" },
"created_at": "2026-10-06T06:02:44Z",
"undone_at": null,
"undone_by": null
}decided_by.method | Decided by |
|---|---|
deterministic | A shared identifier; rule names it (gtin, brand_part). |
probabilistic | The model, above the merge threshold; score is the probability. |
ai | The AI judge; actor is the model, with score and confidence. |
human | A person; actor names them. |
GET /v1/merges lists merges newest first, filtered to
those still in force or undone (status) or to one product, either side (product). In the
dashboard they are under Merges on the Match review page.
Undo a merge
POST /v1/merges/{id}/undo, or Undo merge, undoes any
merge, whatever decided it. Each product and variant is its own again under its original ID, with
its fields and offers back, and product.unmerged and variant.unmerged are published.
The pairs of an undone merge are offered for review again, and never merged again unseen: not by an identifier, the model or the judge. Only a person can join them again.
How matching works
How FurniOps decides that two sources' records are the same item. Deterministic identifiers first, then a trained probabilistic model with embeddings, then an AI judge that must quote its evidence, and people for everything in doubt.
AI agents
FurniOps' AI agents file categories, repair mappings, draft new sources and explain failed runs. They never change your catalogue themselves. What each agent does, autonomy from off to applying low-risk changes, daily budgets, and the shadow record.