Skip to main content

Digital Product Passport

A Digital Product Passport (DPP) is a signed digital record that follows a physical product across its life — from the factory floor, through publication and on-chain certification, all the way to the moment a consumer takes ownership of the item. Keyban exposes that life as four discrete steps; this page walks through each one so you can map the right API calls to the right phase of your business process.

Pick a granularity first

Every passport sits at one of three levels. The level determines which fields are required, which sibling passports it links to, and whether it can ultimately be claimed by a consumer.

GranularityRepresentsIdentified byClaimable on-chain?
modelA product reference / SKU template, shared across every unit of that referencemodelNumberNo
batchA production lot of the same model — series, dated run, factory runmodelNumber + batchNumberNo
itemAn individual serialized unitmodelNumber + batchNumber + itemNumberYes

The three levels nest: a batch resolves its parent model automatically through modelNumber; an item resolves both its parent batch and model through batchNumber and modelNumber. You can create them in any order — the link is rebuilt server-side on each read.

model and batch carry the public, shareable content (specifications, compliance, marketing). item is the only level that an end consumer can take ownership of, because each item maps one-to-one to an on-chain ERC-721 token.

The four-step lifecycle

  1. Step 1: Build

    Draft the passport in the Keyban database — nothing on-chain yet.

  2. Step 2: Publish & certify

    Public visibility plus on-chain certificate anchored at certifiedPaths.

  3. Step 3: Configure claim

    Email or phone gating, magic token, or both — item passports only.

  4. Step 4: Consumer claims

    ERC-721 minted to the consumer's wallet, mintedTo populated.

A four-step partner-then-consumer lifecycle: build a draft, publish and certify, configure the claim, then the consumer claims the item.

Steps 1 to 3 are partner-side and are driven from your backend with an X-Api-Key. Step 4 is consumer-side and runs through the Keyban front-end SDK; your job at step 3 is to prepare it.

1. Build the draft

You create the passport with POST /v1/dpp/passports (or POST /v1/imports for bulk uploads), picking the granularity. The passport lands in status = draft:

  • It lives only in the Keyban database — nothing on-chain happens at this stage.
  • It is not publicly readable — the public read endpoint returns it only after publication.
  • It is freely editable through PATCH /v1/dpp/passports/{id} until you decide to publish.

Use this phase to assemble whatever the passport must show: identifiers (gtin, serial), images, descriptions, custom data fields, and the list of certifiedPaths you want anchored on-chain at the next step.

2. Publish and certify

POST /v1/dpp/passports/publish flips matching drafts to status = published. This transition is irreversible and triggers two effects at once:

  • Public visibility. The passport is now readable through the unauthenticated GET /v1/dpp/passports/{id}. Anyone with a link or a QR code can verify it.
  • On-chain certification. The server canonicalises the values at certifiedPaths, signs them with your organization's certification key, and anchors the resulting hash (lastCertificateHash) on-chain.

The two effects are bundled because they answer two complementary questions about a public passport: "Can I see it?" and "Can I prove it has not been tampered with?". Re-certification happens automatically and incrementally if you later edit a certified value or change certifiedPaths itself.

At this point you have a public, signed, on-chain-anchored record. For model and batch passports, the lifecycle ends here — they are not meant to be claimed.

3. Configure the claim (item only)

The certificate from step 2 says what the product is. The next step says who can take ownership of an individual unit. This applies only to item passports.

Two mechanisms are available, and you can use either or both:

  • Email or phone gating. Set allowedClaimEmail or allowedClaimPhoneNumber on the item (at create or update time, including via PATCH). The first user that signs into a Keyban-powered front-end with that email or phone is associated with the item.
  • Magic token. Call GET /v1/dpp/passports/{id}/magic-token to mint a JWT bound to the passport. Print it on a QR code, embed it in a one-time URL, or include it in a packing slip. Whoever holds the token can claim the passport. Treat it as a bearer credential.

Both mechanisms converge on the same on-chain mint at step 4. They give you flexibility in how you connect the physical product to a known or anonymous consumer.

4. The consumer claims the item

The end consumer interacts with a Keyban-powered front-end (your e-commerce account area, a dedicated claim page, the Keyban consumer SDK in your mobile app). When the front-end establishes that the consumer matches the gating you configured at step 3, it calls the consumer-only endpoint POST /v1/dpp/claim. The Keyban backend then:

  • Mints the ERC-721 token to the consumer's wallet — this is the on-chain mint of the item.
  • Records the new owner's account UUID in mintedTo. From that point on, mintedTo is non-null and transactionHash is recorded against the mint job.

Your backend has nothing to do during this step. To know whether an item has been claimed, poll GET /v1/dpp/passports/{id} and inspect mintedTo.

What "update" means at each step

The word update refers to slightly different things depending on the phase. To avoid confusion:

When"Update" meansCaller
Draft (step 1)Free-form PATCH on any field except status. No on-chain effect.Partner backend
Published, non-certified field (step 2)PATCH succeeds, no re-certification.Partner backend
Published, certified field or certifiedPaths (step 2)PATCH succeeds and automatically re-certifies — new lastCertificateHash, new on-chain event.Partner backend
Claim (step 4)The consumer takes ownership of the on-chain token. The passport content does not change; only mintedTo does.Consumer (via Keyban SDK)

Source-level immutability: passports created via the Shopify catalogue sync (source = "shopify") have editable = false and reject PATCH with 403. Passports created via POST /v1/imports (source = "import") remain editable through PATCH, but the natural way to update them is to re-upload the row through /v1/imports — the unique tuple (application, granularity, modelNumber, batchNumber, itemNumber) triggers a deterministic upsert.

How passports are created

Three entry points converge on the same passport store. Each tags the resulting record with a source value that drives editable:

  1. Shopify catalogue syncsource = "shopify" · editable = false (read-only)
  2. POST /v1/importssource = "import" · editable = true · async bulk upsert on the unique tuple
  3. Passport storeSingle source of truth, indexed on (application, granularity, modelNumber, batchNumber, itemNumber).
  4. POST /v1/dpp/passportssource = "manual" · editable = true · one passport per call
Three creation entry points converge on the central passport store: Shopify catalogue sync (read-only passports), individual REST creates (fully editable), and bulk imports (editable but typically resynced through the import endpoint).

Where to go next