Don’t confuse this with Serial Verification (
gs1:verificationService). That’s a public, unauthenticated anti-counterfeit check anyone can run from a consumer scan. This is an authenticated, retailer-scoped returns check — a different question, a different API, a different audience.How a unit becomes verifiable
Verification reads from your organization’s own EPCIS 2.0 event history — there’s no separate “sale record” table, and no state to keep in sync by hand. Get the events in, and the verify call reads them back out.Recording a sale
Two ways to get sale events in, both landing on the same event log: Real-time, per serial — capture it like any other EPCIS event:retail_selling / retail_sold event server-side. Re-uploading a file is safe — rows already captured are reported as skipped, not duplicated, so a replayed nightly export is a no-op. Maximum upload size 10 MiB, maximum 10,000 rows per upload.
Recording a return
Closing the loop uses the same capture endpoint with a different business step:already_returned — which is what stops the same unit being refunded twice.
The verify call
Requires an
X-API-Key for an organization membership with OWNER or MANAGER role — this is a privileged, retailer-side call, not a public scan.
Decision states
recall is populated only when decision is recalled_lot, and carries recall_id, title, severity, and the matched lot.
Why the states catch what they catch
Serialization at the return desk is a targeted defense, not a blanket one — it’s worth being specific about what each pattern trips:- Receipt fraud (a valid receipt paired with a different, unpurchased unit) — the receipt matches a transaction, but the physical serial being returned was never the one sold under it, so it reports
never_soldregardless of how convincing the paperwork looks. - Double returns — the second attempt on an already-processed unit reports
already_returnedinstead of quietly refunding twice. - Cross-retailer arbitrage (bought at one retailer, returned at another for a better refund) — because verification only ever reads your organization’s own events, a unit this store never sold reports
never_soldorunknown_serialhere even though another retailer’s system would show it as legitimately sold. - Counterfeit-swap returns (genuine unit purchased, a counterfeit substituted back into the box before return) — this only works if the serial is scanned off the unit itself at the return desk, not read off the outer packaging. A code that lives only on the box comes back unchanged no matter what’s inside it.
Tenant isolation
Verification answers are computed only from the querying organization’s own events. Two retailers selling the same GTIN + serial (unlikely, but the model doesn’t assume otherwise) hold entirely separate event histories and neither can see the other’s. The one deliberate exception is recall status: a recall is public product-safety information, not one retailer’s private event, so an open recall on a unit is reported regardless of which organization published it or which organization is asking.Performance
The read is a single indexed lookup against denormalized columns cached on the serial’s row — never a walk through the event log. This is what makes it safe to call inline at a return desk rather than as a background check.Errors
Related
- EPCIS 2.0 Events — the event log this reads from
- Serial Verification — the different, unauthenticated anti-counterfeit check; don’t confuse the two