Changelog
Changelog
Points forts sélectionnés des dernières versions. Pour les versions complètes de l’API et la politique de rupture de compatibilité, consultez la Politique de versioning de l’API & LTS.
Modifications détaillées des différents points de terminaison : Spécification OpenAPI et référence API interactive.
2026-08 · Curseur keyset désormais sur tous les endpoints de liste
- Correctif : Le correctif de curseur pour
GET /v1/codesetGET /v1/dpp(voir ci-dessous) est désormais déployé sur toutes les autres listes paginées par curseur :GET /v1/qr-codes/:id/comments,/v1/workspaces,/v1/gs1/identifiers,/v1/members,/v1/audit-logs,/v1/admin/orgs,/v1/admin/userset/v1/webhooks/:id/deliveries. Toutes paginaient uniquement viacreated_at; les lignes ayant un horodatage identique (entrées d’audit d’une opération par lot, tentatives de webhook, importations de membres) pouvaient être perdues sur la page suivante. La clé de tri est désormais partout le tuple(created_at, id). - Modification de l’API : Sur ces listes,
meta.pagination.next_cursorest désormais également une valeur opaque (base64url) au lieu d’un simple horodatage ; les curseurs illisibles renvoient400, les anciens curseurs d’horodatage continuent d’être acceptés de manière transitoire. Exception pourGET /v1/webhooks/:id/deliveries: ici,next_cursorreste l’ID de la dernière livraison (ID inconnu → première page). Les clients qui renvoientnext_cursorsans modification — Tableau de bord, CLI, SDKs, MCP — n’ont rien à changer. - Impact : Aucune migration requise. Si vous avez manqué des entrées lors de la navigation dans l’une de ces listes (par exemple, le journal d’audit ou le journal de livraison dans le Tableau de bord) : elles n’ont jamais disparu — les listes les affichent désormais de manière complète.
2026-08 · Les horodatages après modification et suppression sont à nouveau conformes à OpenAPI
- Correctif : Après
PATCH /v1/codes/{id},updated_atétait renvoyé au format SQLite sans fuseau horaire (2026-08-17 09:00:00), bien que la spécification OpenAPI prometteformat: date-timeet que la création (POST) fournisse l’horodatage ISO (2026-08-17T09:00:00.000Z). Il en allait de même pourdeleted_at/updated_atlors de la suppression logique (soft-delete) ainsi que pour les chemins de modification/suppression des clés API, organisations, workspaces, membres, commentaires et webhooks, ainsi que pourlast_used_atdes clés API etlast_triggered_atdes webhooks. Tous les chemins d’écriture horodatent désormais en ISO 8601 (UTC,TetZ). - Impact : Les clients qui analysent
updated_atavecnew Date(...)(SDKs, CLI, Tableau de bord) lisaient le format avec espace comme l’heure locale — la CLI affichait l’heure décalée de l’offset local pour les codes modifiés une fois (Vienne : −2 h). Ce problème est résolu. De plus, une migration de données normalise les valeurs déjà enregistrées dans l’ancien format vers le format ISO, afin que le tri et les comparaisons soient corrects dans les bases de données mixtes. Aucun changement au niveau des noms de champs ou de la structure des réponses. - Contexte : Même classe d’erreur que les deux corrections ci-dessous (expiration des clés API, limite de re-scan) : le
datetime('now')de SQLite écritYYYY-MM-DD HH:MM:SS, tandis que tous les autres chemins d’écriture utilisent l’ISO 8601. Un test de garde dans le code source empêchera de nouvelles occurrences à l’avenir.
2026-08 · La pagination des listes ne perd plus de codes batch
- Correctif :
GET /v1/codesetGET /v1/dpppaginaient uniquement viacreated_at. Cependant, les codes issus dePOST /v1/codes/batch,POST /v1/dpp/batchet de l’importation CSV/XLSX partagent un seul horodatage — dès qu’un lot était plus grand quelimit(par défaut 20), la deuxième page ne renvoyait plus les lignes restantes de ce même horodatage. Les codes existaient et étaient accessibles viaGET /v1/codes/:id, mais n’apparaissaient jamais dans la liste (Tableau de bord, CLIqr3 list, SDKs, MCP). Le curseur est désormais un Keyset sur(created_at, id). - Modification de l’API :
meta.pagination.next_cursorest désormais une valeur opaque (base64url) au lieu d’un simple horodatage. Ceux qui renvoient le curseur inchangé sous la forme?cursor=— comme le font le Tableau de bord, la CLI, tous les SDKs et le serveur MCP — n’ont rien à modifier. Les anciens curseurs d’horodatage continueront d’être acceptés à titre transitoire ; les curseurs illisibles renvoient désormais400au lieu de renvoyer silencieusement la première page. - Impact : Si vous voyiez moins de codes dans la liste après un import par lot que ce qui avait été créé : les codes n’ont jamais disparu — la liste les affiche désormais en totalité. Aucune migration n’est nécessaire.
2026-08 · Les re-scans de sécurité sont à nouveau exécutés toutes les 24 heures
- Correctif : Le re-scan périodique des URL cibles et des liens de pages de destination (Google Web Risk) ignorait les codes dont la dernière analyse avait eu lieu le même jour civil que le seuil de 24 heures — selon l’heure, le re-scan était retardé jusqu’à un jour supplémentaire. Le seuil est désormais calculé dans le même format ISO que celui dans lequel les horodatages d’analyse sont stockés.
- Impact : Une URL cible classée comme non sécurisée après la dernière analyse entraîne à nouveau la mise en pause automatique du code dans la fenêtre documentée de 24 heures. Aucune modification de l’API ou du format de réponse.
2026-08 · Les clés API expirent à l’instant d’expiration
- Correctif : Une clé API dont le
expires_attombait le même jour continuait d’être acceptée jusqu’à minuit UTC. L’expiration est désormais comparée sous forme d’horodatage plutôt que de chaîne de caractères — une clé expirée renvoie immédiatement401. - Contexte :
expires_atest stocké sous forme d’horodatage ISO (2026-08-14T09:00:00Z), tandis que le côté comparaison fournissait le format avec espace (2026-08-14 09:00:00). La comparaison brute de chaînes de caractères n’était donc correcte que tant que la date elle-même différait. - Impact : Aucune migration n’est nécessaire, le format de réponse de
GET /v1/api-keysreste inchangé. Les valeurs d’expiration illisibles sont désormais considérées comme expirées plutôt que valides.
2026-08 · Référence API : Gestion des tenants documentée
- OpenAPI : La spécification — et donc la référence interactive — documente désormais les organisations (y compris
GET /v1/organizations/usage), les workspaces, les membres & rôles et les journaux d’audit. - Facturation : L’aperçu des tarifs (
GET /v1/billing/plans) est public ; le paiement (POST /v1/billing/checkout) et le portail client Stripe (GET /v1/billing/portal) sont répertoriés comme des points de terminaison pour les administrateurs d’organisation. - Exportation des scans : Les statistiques de scan (
GET /v1/codes/{id}/scans) et l’exportation des données brutes (…/scans.csv,…/scans.xlsx) sont entièrement documentées — y compris la mention RGPD : leip_hashn’est jamais inclus dans l’exportation. - Gestion des erreurs : La réponse
400de la validation de requête est également nouvellement documentée : le corps est l’erreur Zod brute, et non un document de problème RFC-7807 — elle est néanmoins fournie avec le Content-Typeapplication/problem+json.
2026-08 · Copier les liens publics des fichiers
- Tableau de bord : les fichiers publics sur la page de détails d’un code disposent désormais d’un bouton qui copie leur lien public dans le presse-papiers — directement utilisable comme URL cible d’un code QR lorsqu’un scan doit ouvrir un document précis plutôt que la page de destination et sa liste de fichiers.
- API : les endpoints de fichiers (
/v1/files) renvoient en pluspublic_url. Le champ n’est défini que pour les fichiers avecvisibility: public— les fichiers privés n’ont pas d’adresse publique. - Comportement : le lien ne nécessite aucune connexion et ouvre le fichier directement dans le navigateur. Remplacer le fichier laisse le lien inchangé ; un code imprimé avec cette adresse reste donc valide. Détails : Fichiers & Fiches techniques.
2026-07 · Rôles d’équipe : Contributeur sans suppression & facturation admin
- Nouveau : rôle de membre Contributeur (sans suppression) — crée et modifie les codes QR, les fichiers et les Digital Product Passports, mais ne peut rien supprimer ni créer de clés API. Tous les endpoints destructifs vérifient le rôle côté serveur (
403). - Facturation : les mises à niveau de forfait et le portail client Stripe (
POST /v1/billing/checkout,GET /v1/billing/portal) sont désormais réservés aux Administrateurs d’organisation — tous les autres rôles voient un aperçu du forfait en lecture seule. - Dashboard : les actions non autorisées par le rôle de l’utilisateur sont masquées : un Lecteur ne voit par exemple aucun bouton pour créer, modifier ou supprimer ; les listes, téléchargements et statistiques restent visibles. Détails : Équipe & Rôles.
2026-06 · Liens externes sur la page de destination du code
- Page de destination : La page de destination hébergée par qr3 d’un code peut désormais lister des liens externes auto-hébergés (
{ label, url }) en plus ou à la place des fichiers téléversés – par exemple pour des fiches techniques hébergées sur votre propre site. - API :
POST/PATCH /v1/codesacceptent un tableaulinks(0–20 entrées,http(s), ≤ 2048 caractères). Chaque URL est vérifiée avec Google Web Risk ; une URL non sécurisée renvoie422. Un tableau vide supprime tous les liens. - Tableau de bord : Ajoutez, réordonnez et supprimez des liens sur la page de détails du code.
- Sécurité : Les liens rendus restent protégés contre les XSS (échappés,
http(s)uniquement) et la page conserve son en-têtenoindex.
2026-04 · Analyses du tableau de bord par code QR
- Tableau de bord : Le bouton d’analyses dans la liste des codes QR ouvre désormais la page de statistiques du code QR correspondant sous
/dashboard/codes/{id}. - Routage : L’alias
/dashboard/codesredirige toujours vers/dashboard, mais n’intercepte plus les routes détaillées comme/dashboard/codes/{id}. - API : La page de détails charge le code QR directement via
GET /v1/codes/:id; elle ne dépend donc plus des limites de pagination de la liste. - Tests : Les tests de régression couvrent la redirection d’alias et le chargement direct du code.
2026-04 · Boîte de dialogue de suppression des codes QR sur le tableau de bord
- Tableau de bord : L’icône de corbeille dans la liste des codes QR ouvre désormais une boîte de dialogue React dédiée au lieu d’une fenêtre contextuelle native du navigateur.
- Retour d’information : Après la suppression, une notification toast apparaît pour indiquer le succès ou l’échec.
- Tests :
packages/dashboard/tests/dashboard.test.tsempêche les régressions surconfirm()dans le flux de suppression de code QR.
2026-04 · Test de lien court sur le tableau de bord pour les codes QR dynamiques
- Tableau de bord : Les codes courts dans la liste des codes QR sont désormais directement cliquables en tant que liens de redirection externes. L’icône de lien externe à côté de par ex.
wu3qaaouvrehttps://qr3.app/{shortCode}dans un nouvel onglet. - i18n : Ajout des textes d’infobulle pour l’allemand et l’anglais.
- Tests :
packages/dashboard/tests/dashboard.test.tsprotège le href du lien, le comportement du nouvel onglet,noopener noreferreret l’icône contre les régressions.
2026-04 · Route du Worker de redirection pour les codes QR dynamiques
- Correctif : Les codes QR dynamiques sous
https://qr3.app/{shortCode}sont à nouveau traités par le Worker de redirection. La route de production utilise désormaisqr3.app/*car les routes de Cloudflare Workers ne prennent pas en charge les paramètres de chemin:code. - Renforcement : Les chemins non correspondants sont transmis à l’origine de la page d’atterrissage afin que les pages normales comme
/de/pricingne soient pas bloquées par le Worker de redirection. - Tests :
packages/redirect/tests/unit/redirect.test.tsvérifie la route générique, le traitement du code court et le passage à l’origine.
2026-04 · Aperçu des scans DPP de l’espace de travail (Q3.4.2)
- Nouveau :
GET /v1/workspace/stats/dpp?days=30— agrège tous lesdpp_scansde l’espace de travail de la clé API (active_dpps,scans_by_day,top_dppsavec nom de produit/catégorie). - Tableau de bord : Carte sur la page d’accueil (
/dashboard) avec un graphique à barres sur 30 jours + listes des tops — en parallèle des cartes de codes QR. - Public : Lien court marketing
GET /dpp/dpp_<id>(un segment) pour les démos en direct, en parallèle de/dpp/{gtin}/{serial}.
2026-04 · Analyses des scans DPP (Q3.4.1)
- Nouveau :
GET /v1/dpp/:id/stats?days=30— scans agrégés du résolveur public GS1 par DPP. Champs :total_scans,period_scans,scans_by_day,top_countries,top_devices,top_representations. - Nouveau : Table
dpp_scans(migration0011) — séparée descans(Worker de redirection). Les adresses IP sont hachées avec un sel rotatif quotidien, les IP brutes n’atteignent jamais D1. - Tableau de bord : Carte mini-graphique (SVG, sans bibliothèque de graphiques) sur
/dashboard/dpp/:dppIdavec barres sur 30 jours + ventilations du top 3. État vide dès qu’un DPP est en ligne mais n’a pas encore eu de scans.
2026-04 · Simulateur de conformité UE en direct (Q3.3.7)
- Nouveau :
POST /v1/dpp/:id/validate-update— simule des mises à jour partielles sans état (statut, liste de marchés, …) sans persistance. La réponse contienteu_compliance+preview.changed_fields. - Tableau de bord : Carte de simulateur dans les détails du DPP (
/dashboard/dpp/:dppId) — puces pourDE/AT/FR/IT/ES/NL+ personnalisé, menu déroulant de statut, Preview EU impact / Save changes / Reset. Non bloquant via RemixuseFetcher. - Renforcement : Assistants de simulation externalisés (
readUpdatePatchFromForm,marketCountriesKey) + 18 nouveaux tests unitaires ; correction de bug : une entrée non-ISO isolée ne supprime plus la liste des marchés.
2026-04 · Aperçu de la conformité UE en direct dans le formulaire de création (Q3.3.6)
- Modifié :
POST /v1/dpp/validatefournit en pluseu_compliance— le même validateur queGET /v1/dpp/:id/eu-compliance, sans état avant l’enregistrement. - Tableau de bord : Aperçu sous le panneau de validation existant + nouvelle bannière de protection de sauvegarde avant les boutons de soumission si des erreurs/avertissements sont en suspens (pluralisation i18n DE/EN).
2026-04 · Validateur UE + UI Textile (Q3.3.4 + Q3.3.5)
- Nouveau : Validateur de conformité UE avec 5 règles textiles (
TEXTILE_AGEC_REQUIRED,TEXTILE_MICROPLASTICS_CONSISTENCY,TEXTILE_SVHC_THRESHOLD,TEXTILE_GREENWASHING,TEXTILE_ESPR_READY). - Nouveau :
GET /v1/dpp/:id/eu-complianceaveccompliant/espr_ready/issues[]/summary. - Tableau de bord : Section de conformité UE dans les détails du DPP (tuiles de résumé, cartes de problèmes groupées, badge ESPR-Ready dans l’en-tête).
2026-04 · Schéma DPP Textile (Q3.3.1–Q3.3.3)
- Nouveau : Catégorie
textileavec chaîne d’obligation AGEC (tissage/tricotage → teinture/impression → confection), par fibreorigin_country+recycled_pct,svhc_substances[], opt-in ESPR (PEF, durée de vie, recyclabilité). - Nouveau : Champ de base
market_countries: string[](ISO 3166-1 alpha-2) sur toutes les catégories de DPP — contrôle les règles AGEC spécifiques à la France et la notice obligatoire pour les consommateurs français. - Nouveau : Modèle HTML consommateur avec boîte d’avertissement sur les microplastiques AGEC, chaîne d’origine à 3 étapes (badges de drapeaux), liste SVHC, sections durabilité et recyclabilité.
- Migration :
0010_dpp_market_countries(D1).
2026-04 · Importation en lot de DPP (Q3.2.1–Q3.2.5)
- Nouveau :
POST /v1/dpp/importaccepte CSV et XLSX (compatible Worker via SheetJSxlsx, bundle gzip d’environ 283 Ko). - Mise à l’échelle : Limite basée sur le forfait (Free 100 → Enterprise 10k) +
db.batch()fragmenté par 100 + limite de corps de 5 Mo. - Nouveau : Rapport d’erreurs au format CSV dans le champ
errors_csvde la réponse 201 ;GET /v1/dpp/import/templates/:category?format=csv|xlsxfournit des modèles prêts à l’emploi pour les batteries et le textile. - Tableau de bord : Téléchargement par glisser-déposer sous
/dashboard/dpp/importavec proxy de modèle et téléchargement CSV en ligne.
Sans rupture — Extensions LTS
Toutes les modifications mentionnées ci-dessus sont additives :
- Les clients existants de
POST /v1/dpp/validateignorent le nouveau champeu_compliancesans modification. - Les flux
batteryexistants restent inchangés. market_countriesest facultatif et a pour valeur par défaut[].
Consultez le Versioning de l’API pour la politique de rupture de compatibilité.