Digital Link & resolution
A Digital Link identifier maps a GS1 01 (GTIN) / 21 (serial) pair to a product, so a scanner in the outside world can resolve the published passport. Registration is deliberate — creating a product does not register it.
Registration
POST /products/{id}/publish-dpp is the step that registers the identifier (dpp_identifiers count 0 → 1). Only after this does the item resolve.
Resolution
HTTP
GET /api/v2/01/{gtin}/21/{serial} → 302 to /p/{productId} (measured 0.16s)
GET /api/v2/01/{gtin}/21/{serial}
Accept: application/linkset+json → GS1 KAV linkset
GET /api/v2/public/passport/{uid} → audience-filtered passport JSON
GET /api/v2/public/passport/{uid}/verify → signature + anchor verificationTyped failures you can branch on
| Condition | Response |
|---|---|
| Unknown-but-valid GTIN | 404 PRODUCT_NOT_FOUND (names gtin/serial/host) |
| Bad check digit | 400 INVALID_GTIN |
| Over-long serial | 400 INVALID_SERIAL |
| Voided item | 410 SERIAL_VOIDED + tombstone |
| Draft / unpublished | 404 "not found or not published" |
Audience tiers
Public reads are audience-filtered. Anonymous callers get the consumer minimum; only a cryptographically verified X-DPP-Access-Token elevates disclosure. Self-declared hints (e.g. ?viewer=) never do. Every public read is logged with its audience.
Two resolver deviations. The resolver currently
401s anonymous scanners that send no Authorization header, and the public passport route is edge-gated though treated as public. Both are documented in Deviations — assert them as-is.