Développeurs
Certificats, passeports et preuves on-chain sont servis par des endpoints REST simples, publics pour la plupart, parce qu'une preuve que vous ne pouvez pas vérifier vous-même n'est pas une preuve. Clés à portée limitée, webhooks signés et SDK typé couvrent le reste.
https://api.sealtrust.io
La surface de vérification n'exige ni compte ni clé API. Récupérez un certificat, un passeport ou la preuve Merkle d'un produit et contrôlez notre ancrage vous-même sur Base L2 (basescan.org). La preuve est publique et vérifiable en toute indépendance.
# Public endpoints — no API key required
curl https://api.sealtrust.io/certificate/{identifier}
# The passport as JSON-LD (Schema.org / GS1 vocabulary)
curl "https://api.sealtrust.io/passport/{identifier}?format=jsonld"
# The public Merkle proof — verify our anchoring yourself on Base L2
curl https://api.sealtrust.io/verify/merkle/{identifier}Tout ce qui suit est en production, sans authentification (limites de débit applicables). L'identifiant peut être un uid_hash (0x + 64 hex), un token_id ou un numéro de certificat.
| Endpoint | Ce qu'il fait |
|---|---|
| GET/sdm/verify-url | Vérifie un scan NTAG 424 DNA (SDM) : déchiffre et valide le code à usage unique de la puce. |
| GET/certificate/{identifier} | Certificat d'authenticité public (par uid_hash, token_id ou numéro de certificat). |
| GET/certificate/{identifier}/download | Le même certificat au format PDF. |
| GET/passport/{identifier} | Passeport Numérique de Produit, filtré par le profil d'accès demandé. Ajoutez ?format=jsonld pour du JSON-LD (Schema.org/GS1). |
| GET/passport/{identifier}/vc | Le passeport sous forme de credential vérifiable SD-JWT-VC, filtré par niveau d'accès. |
| GET/passport/{identifier}/vc/verify | Vérifie le SD-JWT-VC stocké contre la clé de signature de la marque. |
| GET/brand/{brand_id}/did.json | DID Document de la marque (did:web) : clés publiques de signature en JsonWebKey2020. |
| GET/p/{serial} | L'identifiant unique de produit (EN 18219). C'est ce que porte le QR imprimé sur un produit, et le seul identifiant qu'une personne peut lire sur un objet. Redirige vers la page produit ; ajoutez ?linkType=dpp pour le passeport lui-même. |
| GET/01/{gtin}/21/{serial} | Résolveur GS1 Digital Link : la même unité que /p/{serial}, sous la forme porteuse GS1. |
| GET/resolve/{identifier} | Résolveur universel : produit + certificat + passeport + événements de cycle de vie + médias en une réponse. |
| GET/passport/{identifier}/proof | Faisceau de preuves du passeport : hash SHA-256 des données, copie IPFS, ancrage Base L2 et statut SD-JWT-VC. |
| GET/timeline/{identifier} | Historique combiné : vérifications et transferts de propriété. Limité à 30 requêtes par 60 secondes et par IP. |
| GET/verify/merkle/{identifier} | Preuve publique d'ancrage Merkle d'un produit, recalculable par vous-même contre Base L2. |
| GET/qr/product/{identifier} | QR code (PNG) pointant vers la page de vérification du produit. |
Les opérations d'écriture utilisent des clés API (préfixe st_live_) envoyées en Authorization: Bearer. Le secret complet n'est affiché qu'une seule fois à la création ; seul son hachage SHA-256 est stocké. Chaque clé est rattachée à une marque, soumise à un quota quotidien et à une limite de débit, et porte des scopes explicites :
mint:batchFrappe par lot via /partner/mint/batchsellout:writeDéclarer une sortie de stock via /partner/selloutwebhooks:readLire vos abonnements aux webhookswebhooks:writeCréer, modifier et supprimer un abonnement aux webhooksmint:singleAccordable, mais aucun point d'entrée ne l'exige encoreproducts:readAccordable, mais aucun point d'entrée ne l'exige encoreproducts:statusAccordable, mais aucun point d'entrée ne l'exige encoretransfers:createAccordable, mais aucun point d'entrée ne l'exige encorePOST /partner/mint/batch accepte du JSON (une liste d'objets) ou un fichier CSV, applique l'isolation par marque et les quotas, gère un en-tête Idempotency-Key pour des relances sûres, et renvoie un job interrogeable.
curl -X POST https://api.sealtrust.io/partner/mint/batch \
-H "Authorization: Bearer st_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2027-0042" \
-d '[
{
"product_name": "Sneaker #001",
"brand_id": 1,
"category_id": 3,
"metadata_uri": "https://metadata.sealtrust.io/001.json"
}
]'
# → { "job_id": "abc123...", "status": "queued", "items_count": 1, "brand_id": 1 }
# Poll: GET /partner/mint/batch/status/{job_id} (max 500 items per batch)Abonnez une URL par marque et recevez les événements en POST JSON. Chaque livraison est signée avec votre secret de webhook : l'en-tête X-Webhook-Signature porte t=<horodatage Unix>,v1=<hexadécimal>, où v1 est le HMAC-SHA256 de "{horodatage}.{corps brut}" calculé sur les octets exacts que nous envoyons. Vérifiez sur le corps brut, jamais sur une copie re-sérialisée, et contrôlez l'horodatage avec une tolérance que vous choisissez. Chaque livraison porte aussi X-Webhook-Timestamp et X-Webhook-Id, le SHA-256 du corps, identique à chaque nouvelle tentative d'un même événement pour vous permettre de dédupliquer :
import hashlib
import hmac
import time
def verify_webhook(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
"""Verify X-Webhook-Signature: t=<unix_seconds>,v1=<hmac_sha256_hex>."""
parts = {}
for item in header.split(","):
key, _, value = item.strip().partition("=")
if value:
parts[key] = value
ts, sig = parts.get("t"), parts.get("v1")
if not ts or not sig or not ts.isdigit():
return False
if abs(time.time() - int(ts)) > tolerance: # tolerance is yours to choose
return False
signed = ts.encode() + b"." + raw_body # the signed message, not the body alone
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)
# FastAPI example
# raw = await request.body() # the exact bytes, never a re-serialised dict
# sig = request.headers["X-Webhook-Signature"]
# assert verify_webhook(raw, sig, WEBHOOK_SECRET)product.mintedUn NFT produit a été créé on-chainproduct.transferredLa propriété du produit a été transféréeproduct.burnedUn NFT produit a été détruitproduct.status_changedLe statut du produit a changébatch.completedUn job de mint en masse s'est terminé avec succèsbatch.failedUn job de mint en masse a échouécertificate.issuedUn certificat d'authenticité a été émis@sealtrust-io/sdk est un client typé, en fetch natif et sans dépendance (Node.js ≥ 18). Les requêtes POST et PUT portent automatiquement un en-tête X-Idempotency-Key ; vous pouvez fournir le vôtre pour des relances sûres.
import { SealTrustClient } from "@sealtrust-io/sdk";
const sealtrust = new SealTrustClient({
apiKey: "st_live_...",
baseUrl: "https://api.sealtrust.io", // optional, this is the default
});
// Read a product's history. The printed serial is the identifier you actually
// have: it is what the QR code on the product carries, and the only one a
// human can read off an object. A token id or a 0x uid hash work too.
const history = await sealtrust.verify.timeline("Y5T2VGGF2NP9");
console.log(history.product_name);
console.log(history.timeline.length); // verifications + ownership transfers
// Mint a batch, then poll the job
const job = await sealtrust.products.mint([
{ product_name: "Sneaker #001", brand_id: 1, category_id: 3, metadata_uri: "https://metadata.sealtrust.io/001.json" },
]);
const status = await sealtrust.products.getBatchStatus(job.job_id);
console.log(status.status); // "queued" | "started" | "finished" | "failed"
// Subscribe to webhooks
await sealtrust.webhooks.create({
url: "https://example.com/webhooks/sealtrust",
events: ["product.minted", "product.transferred"],
secret: "whsec_...",
});Chaque identité produit est adressable via la syntaxe GS1 Digital Link vers laquelle converge l'écosystème ESPR : /01/{gtin}/21/{serial} résout un GTIN + numéro de série directement vers le Passeport Numérique de Produit de l'article : le même support fonctionne pour les distributeurs, les douanes et les recycleurs, sans intégration sur mesure.
# One GS1 Digital Link per item — GTIN + serial → passport
curl https://api.sealtrust.io/01/{gtin}/21/{serial}
# The same identity also resolves certificates and events
curl https://api.sealtrust.io/resolve/{identifier}@sealtrust-io/mcp-server expose la surface publique de vérification sous forme de serveur Model Context Protocol (MCP) : sept outils en lecture seule que tout client MCP (Claude Desktop, Claude Code et les autres) peut appeler pour vérifier un produit, lire son Passeport Numérique de Produit et contrôler les preuves qui le soutiennent. Il tourne en local sur stdio, n'exige ni compte ni clé API, et n'atteint que les endpoints publics listés plus haut.
{
"mcpServers": {
"sealtrust": {
"command": "npx",
"args": ["-y", "@sealtrust-io/mcp-server"]
}
}
}# Claude Code
claude mcp add sealtrust -- npx -y @sealtrust-io/mcp-server
# Optional: point it at another environment (default: https://api.sealtrust.io)
claude mcp add sealtrust --env SEALTRUST_API_URL=https://api.sealtrust.io -- npx -y @sealtrust-io/mcp-serververify_productStatut d'authenticité d'un produit (authentique, révoqué ou inconnu) avec les infos produit publiques.get_passportLe Passeport Numérique de Produit publié, niveau public uniquement (JSON ou JSON-LD).get_passport_proofFaisceau de preuves : hash SHA-256 des données, copie IPFS, ancrage Base L2, statut SD-JWT-VC.get_certificateLe certificat d'authenticité public (statut, dates, émetteur).resolve_gs1Résout un GS1 Digital Link (GTIN + numéro de série) vers le passeport de l'article.verify_credentialVérifie le SD-JWT-VC du passeport contre la clé de signature did:web de la marque.get_product_historyLa chronologie de l'article : vérifications et transferts de propriété, du plus ancien au plus récent.Lecture seule par construction : le serveur ne peut que consulter des données publiques. Rien de ce qu'il fait ne peut minter, transférer ou modifier un produit.
Besoin d'une clé de test ou d'une revue d'intégration avec notre équipe ?
Parlez-nous