SealTrustSealTrustSealTrust
Home
How it worksVerifyDemo
Sign inSign up
SealTrust
HomeHow it worksVerifyDemo

Product

Digital Product PassportFeaturesPricingSolutionsRegulation radarUse casesIntegrations

Company

AboutCareersPressContact

Resources

BlogDocumentationAPI DocsDevelopersSecurityTrust CenterAll resources
Sign inCreate an account

© 2026 SealTrust

SealTrust

Product authentication through NFC and blockchain. Protect your brand against counterfeiting.

Product

  • How it works
  • Features
  • Pricing
  • Solutions
  • Regulation radar
  • Use cases
  • Integrations
  • Documentation

Company

  • About
  • Contact
  • Careers
  • Press

Legal

  • Terms of Use
  • Terms of Sale
  • Privacy Policy
  • Legal notices
  • GDPR
  • Cookie Policy
  • Return & warranty

Resources

  • All resources
  • Technical documentation
  • Blog
  • Digital Product Passport
  • DPP 2027 Guide
  • Developers
  • Verification badge
  • Security
  • Trust Center
  • API Docs
  • Help
  • Support

EN 18219 · EN 18220 · ESPR-ready · GDPR

© 2026 SealTrust. All rights reserved.

Follow us on LinkedInMade with trust in France

Trust Center

Why believe what SealTrust claims?

One page for a buyer or an auditor in a hurry. Every statement below is either recomputable from a public endpoint or bounded by a constant in our code. Where we cannot prove something, we say that too.

How far the anchor actually goes

This is the most widely misunderstood distinction in the industry, and the one we are most often asked to clarify in audits. A unit belongs to a batch whose Merkle root is published on Base. That unit's Merkle leaf is built from three values, and the passport's fingerprint is not one of them.

The Merkle leaf, exactly as our code and the contract compute it

keccak256(abi.encode(tokenId, keccak256(uid), keccak256(metadata_uri)))

What the anchor establishes

  • This unit's membership of the anchored batch: anyone can recompute the inclusion proof against the root published on-chain.
  • The unit's on-chain identity: its token id, the fingerprint of its chip UID and the fingerprint of its ERC-721 metadata URI.
  • The timestamp and immutability of that publication: the anchoring transaction is dated and can no longer be altered.

What the anchor does not establish

  • That this unit's batch anchor covers the passport content: the passport's SHA-256 fingerprint is not an input to that leaf. A published passport version is dated by an anchor of its own, reported under passport_anchor by the proof endpoint once that version has been anchored.
  • That the data the brand declared is accurate. We prove the integrity and origin of a declaration, not its truthfulness.
  • That a physical object is genuine by virtue of the anchor alone: that proof comes from the chip's cryptographic verification, on every scan.

A unit whose batch was never anchored falls back to its own mint transaction, which only proves the token exists. Our pages then read "on-chain registration", and reserve the word "anchored" for batches that really were: the scope of each reference is decided server-side, so no client has to infer it from a field name, which is how a client ends up overstating it.

The cryptographic chain, link by link

Four independent links. Each one is verifiable on its own, and a failure in one does not hide the others.

1

SHA-256 fingerprint of the passport

The passport content is serialised to canonical JSON (sorted keys) then hashed with SHA-256. The fingerprint covers the full record, every access tier included, so only a holder of the complete passport can reproduce it: at public tier it is published as a value to compare against, not one to recompute.

2

IPFS copy of the public projection

On publication only the passport's public projection gets pinned to IPFS. The IPFS link is only surfaced publicly once the pinned content has been fetched back and matched against the current public projection's fingerprint, and it is withheld on any mismatch. Not every passport is pinned: when the copy is missing, the API omits it rather than inventing one.

3

Merkle anchoring on Base

Units are grouped into batches, the batch's Merkle root is published on-chain on Base (chain id 8453), and the contract stores the root, the leaf count and a batch identity fingerprint. Each unit's inclusion proof is served publicly.

4

SD-JWT-VC credential signed in KMS

The passport is also issued as an SD-JWT-VC verifiable credential, signed with ES256 by a key belonging to the brand, generated inside AWS KMS and never exported. The matching public key is published in a did:web DID document, so the signature verifies without us.

Verify with no account, no key, and no request to us

These endpoints are public and unauthenticated. An auditor, a customer or a marketplace can call them directly.

EndpointWhat it returns
GET /passport/{id}The published digital product passport, filtered by the access profile requested (public by default).
GET /passport/{id}/proofThe proof block: SHA-256 fingerprint, IPFS copy when pinned, on-chain reference with its scope, credential status.
GET /passport/{id}/verifyThe integrity check: stored fingerprint against recomputed fingerprint against the IPFS copy.
GET /passport/{id}/vc/verifyVerification of the SD-JWT-VC signature against the brand's published key.
GET /verify/merkle/{id}The Merkle inclusion proof: leaf, index, sibling nodes, anchored root and a BaseScan link.
GET /certificate/{id}The public certificate of authenticity, also available as a PDF.
GET /resolve/{id}The consolidated view: product, certificate, passport, events and anchor.
GET /01/{gtin}/21/{serial}The GS1 Digital Link resolver: from a GTIN and a serial to the passport.
GET /brand/{id}/did.jsonThe brand's DID document (did:web): the public signing keys as JsonWebKey2020.

Public API base: api.sealtrust.io. The same routes also exist under the /v1 prefix.

A real, anchored example you can follow end to end

Rather than a diagram, here is a unit genuinely minted and genuinely anchored on Base mainnet. Follow every link: nothing here asks you to take our word for it.

Read this before drawing any conclusion

The token, the batch and the anchoring transaction are real. The passport content is a demonstration: the brand is a fictional workshop and the production site does not exist. This unit illustrates the proof mechanics. It is not on sale.

Chain

Base mainnet · 8453

Leaves in batch

3

Merkle root

0x64ee41e6800f397208e0f319af87bf1db25eae99a8be594b7886aa980f4374d0

Anchoring transaction

0x0e74e132bc7c281a196fe5f9c24dd6673ee00a1068a01e0dafea748978b7ab6b

Contract

0x9d55ad8b11bc883c454bdf16e9fe39b79620ce62

UID fingerprint (= token id)

0x9b724603fac23a6990fc86edda52af205c2785e85a62235632cc7e218fcb0f36

The check we invite you to redo

Call the proof endpoint: it returns this unit's leaf, its index and two sibling nodes. Hash them pairwise with keccak-256, sorted pairs, the OpenZeppelin way. You must land exactly on the root above, the one carried by the on-chain transaction. For this unit, the token id is also identical to the chip's UID fingerprint.

Open the passport→See the raw proofSee the transaction

Data retention: the periods actually enforced

These are not intentions. They are the constants read by our scheduled jobs, which run continuously inside the application.

DataAfterTreatment
IP addresses in scan and audit logs30 daysAnonymised: the last IPv4 octet is zeroed, or the last 80 bits in IPv6. The job runs twice a day.
User agents in logs30 daysErased.
Scan geolocation coordinates90 daysCoarsened to one decimal, roughly an 11 km grid: the city survives, the precise point does not.
NFC authentication logs365 daysDeleted.
Unlabeled scan data (model training)365 daysDeleted. Only labeled rows are kept for the model, and their geolocation is coarsened.
Partner API key usage logs365 daysDeleted.
Administrator audit logs730 daysDeleted after 24 months.

Export and erasure: routes, not a promise

Data export (Article 15) and erasure (Article 17) are two authenticated endpoints. Erasure runs immediately, with no grace period, and propagates anonymisation across a dozen tables: account, transfers, products, wallet, scan logs, newsletter, returns, buybacks, theft reports. Live session tokens are revoked in the same pass.

What survives an erasure, and why

Accounting records are kept for ten years under the legal obligation carved out by Article 17(3)(b). On-chain history cannot be erased by nature. The custodial wallet key is retained so the assets it holds are not orphaned. Only the link to your identity is severed. A product's lifecycle events stay attached to the product, no longer to you.

Security posture

The points an audit asks about first, stated with their real parameters, apart from the security thresholds we do not publish.

Passwords hashed with Argon2id

Parameters in force: time cost 3, 64 MiB of memory, parallelism 4. Legacy bcrypt digests are transparently rehashed to Argon2id on the first successful login. An unknown address triggers a dummy verification so response time does not give it away.

Token rotation with replay detection

Every refresh mints a new token and invalidates the one just presented. If an already-consumed token comes back, that is the signature of a theft: the session is not merely refused, every token on the account is revoked at once. Access tokens last 60 minutes, refresh tokens 7 days.

Signing keys held in KMS

The platform's blockchain signing key and each brand's credential-signing key are generated inside AWS KMS and never leave it: signing happens on the KMS side. In production the code refuses to sign when the KMS key id is missing. NFC master keys are held KMS-encrypted, never in plaintext at rest.

Brute-force limits and second factor

A temporary lock after a small number of failed attempts, keyed on the address/IP pair, plus a separate per-account ceiling across all IPs to cut off distributed attacks. The exact values are not published. TOTP two-factor is available, with single-use backup codes.

Headers and rate limiting

One-year HSTS with includeSubDomains and preload, a content security policy whose scripts are nonce-restricted with no 'unsafe-inline'. Inline styles are still allowed. Anti-framing protection, nosniff. Rate limiting applies per IP address to sign-in, verification and password reset. A refusal by that counter returns 429 and names in plain words the ceiling and the window it applies to, and the ceilings of the public verification paths are listed in our API documentation.

Checks in continuous integration

Every change passes a secret scan over the full git history. Container images are scanned for vulnerabilities on every released version, and Python and Node dependencies are audited whenever a manifest changes and nightly. Third-party actions are pinned to an exact commit.

Does a claim on this page look thin to you, or were you expecting one we did not make? That is exactly the conversation we want to have.

Talk to the team→See the security model