How offers are matched to products
Your 3PL calls the thing in its building an Offer, identified by an item code they chose. You call it a product, identified by a SKU you chose. Nothing guarantees the two strings are the same, and until they are connected, nothing else in the integration works: stock cannot be compared, orders cannot be picked against the right item, and a purchase order cannot be announced.
That connection is the mapping, and SKU.io tries to make it for you.
The ladder
After every catalogue sync, SKU.io walks each unmapped offer down four rungs, in order, stopping at the first one that produces a single unambiguous answer.
| # | Rung | What it compares | Result |
|---|---|---|---|
| 1 | Exact SKU | The VeraCore item code against your SKUs, character for character | Mapped |
| 2 | Normalized SKU | The same comparison after normalising case, spaces, and punctuation | Mapped |
| 3 | UPC | VeraCore's barcode against your product barcodes | Mapped |
| 4 | Exact name | The offer title against your product names | Needs Review |
If none of them produce an answer, the offer stays Unmapped and waits for a person.
Two things that diagram makes plain and prose does not. Ambiguity behaves exactly like no match — a rung that finds two candidates does not pick one, it falls through. And only the fourth rung produces Needs Review; the first three either map confidently or move on.
Rung 1 — Exact SKU
SHAKER-BLK is SHAKER-BLK. Unambiguous by definition, so it is tried first and it is the rung that resolves most catalogues.
Rung 2 — Normalized SKU
The same code typed by three different people over five years becomes three different strings. Normalisation collapses that: the comparison is done in upper case, with leading and trailing whitespace removed, and with hyphens, underscores, full stops, and spaces stripped out entirely.
So SKU-1, sku_1, Sku.1, and SKU 1 all normalise to SKU1 and match each other. This rung is what makes a real-world catalogue map cleanly instead of leaving a long tail of near-misses.
Rung 3 — UPC
Barcodes are strong evidence: two products sharing a UPC is a data problem, not a coincidence. But VeraCore keeps barcodes behind its WMS credentials, which are a separate login, and most 3PL accounts never issue one.
So this rung is skipped, not failed, when WMS credentials are absent. The ladder moves straight from rung 2 to rung 4 and nothing is logged as an error. Adding WMS credentials later simply improves the results of the next sync.
If a meaningful share of your catalogue is sitting at Unmapped or Needs Review, WMS credentials are the cheapest thing that will move the number. Add them on the Authentication settings tab and re-run the catalogue sync.
Rung 4 — Exact name
Two distinct products routinely share a title — "Black Shaker Bottle" could be either of the two you sell. A name match is plausible, but it is not proof, so SKU.io treats it as a suggestion: the offer is linked and flagged Needs Review, and the sync will not rely on it until a person confirms it.
This is the one rung that never produces a trusted mapping on its own.
The rules that keep the ladder honest
Three constraints apply at every rung, and between them they account for most of the cases where you expected a match and did not get one.
One product backs at most one offer
Before a rung considers its candidates, any product already claimed by another offer is removed from the pool. The relationship is one-to-one per connection: if SHAKER-BLK already backs VeraCore item VC-1001, it cannot also back VC-2000. To move it, unmap the first offer.
This is the constraint that most of the import validation errors exist to protect.
Ambiguity is never resolved by guessing
If a rung finds more than one viable product, the match is recorded as ambiguous and the offer is left for a person. SKU.io does not pick the first, the newest, or the closest — a wrong automatic mapping is far more expensive than an unmapped offer, because it silently attributes stock and shipments to the wrong product.
Only unmapped offers are touched
The matcher runs over offers with no mapping. An offer you mapped by hand, or by import, is never re-evaluated and never overwritten by a later sync. Manual intent wins permanently.
Match methods, and why they are recorded
Every mapping records how it was made, and that value is shown next to the mapping state:
| Method | Meaning |
|---|---|
| Exact SKU | Rung 1 |
| Normalized SKU | Rung 2 |
| UPC | Rung 3 |
| Exact Name | Rung 4 — always flagged for review |
| Manual | A person set it, in the table or by import |
| Unmatched | Nothing matched |
Six months later, "why is this VeraCore item pointing at that SKU?" is a real question with a real answer, and it is answerable without re-running anything. That is the entire purpose of storing the method. Colours and labels are in the statuses reference.
Working through what is left
After a sync, the Products tab filter gives you the queue:
| Filter | What it means | What to do |
|---|---|---|
| Needs Review | A name match was found | Confirm it, or replace it with the right product |
| Unmapped | Nothing matched | Map it, or accept that this offer has no SKU.io counterpart |
Work Needs Review first — those are one click each, and they are the ones that will quietly cause trouble if left. Then decide on Unmapped: not every offer needs a mapping (your 3PL may hold items for another client, or packaging materials you do not stock), but every offer you want stock and orders for does.
For a handful, map them from the table — see Map an offer to a product. For hundreds, use the spreadsheet round trip in Product mapping import and export. Mappings applied either way are recorded as manual, so a later sync will not touch them.
If two offers race for the same product during an automatic pass, the losing offer is simply left unmapped for the next run rather than aborting the sync. A partial pass followed by a clean one beats an all-or-nothing pass that fails on row 400 of 500.