API QR-Codes
Aperçu
L’API Codes est au cœur de qr3.app. Elle vous permet de créer, mettre à jour et supprimer des QR-Codes dynamiques et statiques.
URL de base : https://qr3.app/v1/codes
Contrat REST de référence
Le contrat suivant s’applique à tous les clients :
POST /v1/codesaccepte uniquement les typesurl,vcard,wifi,email,smsetlocation. Les champs sont plats :url; au moinsvcard_first_nameouvcard_last_name;wifi_ssid;email_to;sms_phone; oulocation_latetlocation_lng.- Seuls les codes
urlpeuvent être dynamiques. Les requêtes de création peuvent facultativement inclureexpires_atsous la forme d’un horodatage ISO 8601 ;ab_enabled,ab_target_url_betab_weight_a(destinations A/B) sont acceptés pour les codesurldynamiques ;redirect_after_expiryne fait pas partie du contrat de création. GET /v1/codesne prend en charge quelimit,cursoretstatus(live,paused,flagged,draft).POST /v1/codes/batchaccepteurl,vcardetwifi. La limite est de 10 pour Free, 500 pour Pro et 1 000 enregistrements pour Business/Agency/Enterprise par requête. Les analyses d’URL s’exécutent de façon synchrone pour 50 éléments URL au maximum ; au-delà,skip_url_scan: trueest nécessaire.
Créer un QR-Code
POST /v1/codes
curl -X POST https://qr3.app/v1/codes \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "type": "url", "url": "https://example.com", "title": "Mein erster QR-Code", "tags": ["marketing", "q1"], "is_dynamic": true }'const code = await qr3.codes.create({ type: 'url', url: 'https://example.com', title: 'Mein erster QR-Code', tags: ['marketing', 'q1'], is_dynamic: true,});qr3 create https://example.com --title "Mein QR-Code" --tags marketing,q1Réponse (HTTP 201) :
{ "data": { "id": "qr_a1b2c3d4", "short_code": "r7f3Kx", "redirect_url": "https://qr3.app/r7f3Kx", "image_svg_url": "https://qr3.app/v1/codes/r7f3Kx/qr.svg", "image_png_url": "https://qr3.app/v1/codes/r7f3Kx/qr.png", "image_pdf_url": "https://qr3.app/v1/codes/r7f3Kx/qr.pdf", "image_eps_url": "https://qr3.app/v1/codes/r7f3Kx/qr.eps", "type": "url", "target_url": "https://example.com", "is_dynamic": true, "status": "live", "tags": ["marketing", "q1"], "total_scans": 0, "created_at": "2026-03-15T10:00:00.000Z" }, "meta": { "request_id": "req_xyz123" }}Types de QR-Codes
| Type | Description | Champs obligatoires |
|---|---|---|
url | URL de site web (dynamique ou statique) | url |
vcard | Carte de visite (vCard 3.0) | vcard_first_name ou vcard_last_name |
wifi | Configuration Wi-Fi | wifi_ssid |
email | E-mail (mailto:) | email_to |
sms | SMS | sms_phone |
location | Localisation (geo:) | location_lat, location_lng |
Création par lot (Batch)
POST /v1/codes/batch
curl -X POST https://qr3.app/v1/codes/batch \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "items": [ { "type": "url", "url": "https://produkt-1.example.com", "tags": ["batch"] }, { "type": "url", "url": "https://produkt-2.example.com", "tags": ["batch"] }, { "type": "wifi", "wifi_ssid": "GastWLAN", "wifi_password": "geheim123" } ], "skip_url_scan": false }'Réponse (HTTP 201) :
{ "data": { "created": [ { "id": "qr_...", "short_code": "abc123", "redirect_url": "https://qr3.app/abc123" }, { "id": "qr_...", "short_code": "def456", "redirect_url": "https://qr3.app/def456" }, { "id": "qr_...", "short_code": "ghi789", "status": "live" } ], "total": 3, "failed": 0 }}Liste des QR-Codes
GET /v1/codes
curl https://qr3.app/v1/codes?status=live&limit=20 \ -H "Authorization: Bearer qr3_sk_..."Paramètres de requête (Query Parameters) :
| Paramètre | Type | Par défaut | Description |
|---|---|---|---|
cursor | string | — | Curseur pour la pagination |
limit | integer | 20 | Résultats par page (max. 100) |
status | string | — | Filtre : live, paused, flagged, draft |
Récupérer un QR-Code
GET /v1/codes/:id
curl https://qr3.app/v1/codes/qr_a1b2c3d4 \ -H "Authorization: Bearer qr3_sk_..."Mettre à jour un QR-Code
PATCH /v1/codes/:id
Update contract: url may be changed only for an existing type: "url" code, and its value must use http:// or https://. Other code types must not receive url; invalid requests return 422.
Les QR-Codes dynamiques permettent de modifier l’URL de destination à tout moment — sans avoir à réimprimer le QR-Code.
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4 \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "url": "https://neue-zielseite.example.com", "status": "live" }'Page d’atterrissage (Landing page) & liens externes
Pour les codes url dynamiques, vous pouvez définir is_landing_page: true (lors de la création ou via PATCH). Un scan affichera alors une page hébergée par qr3 contenant les fichiers publics et les liens externes du code, au lieu de rediriger. Les liens externes sont transmis sous forme de tableau links :
{ "is_landing_page": true, "links": [ { "label": "Datenblatt", "url": "https://example.com/datenblatt.pdf" }, { "label": "Zertifikat", "url": "https://example.com/zertifikat.pdf" } ]}- 0 à 20 liens par code ;
labeldoit faire entre 1 et 100 caractères ;urldoit être au formathttp(s)(≤ 2048 caractères). - Chaque URL est vérifiée avec Google Web Risk — une URL non sécurisée renvoie une erreur
422. - Si Web Risk n’est pas accessible lors de l’enregistrement, le lien est tout de même accepté, mais marqué pour une nouvelle vérification. Une tâche quotidienne vérifie à nouveau les liens enregistrés (et réévalue régulièrement les liens classés comme sûrs) et suspend automatiquement le code si un lien est ultérieurement détecté comme non sécurisé.
"links": []supprime tous les liens. Voir le guide de la page d’atterrissage.
Supprimer un QR-Code
DELETE /v1/codes/:id
Soft-delete (suppression logique) — le QR-Code est archivé, les données de scan sont conservées.
Un second DELETE sur le même code renvoie 404, même si les deux requêtes arrivent en même temps. Le webhook qr.deleted est envoyé exactement une fois.
curl -X DELETE https://qr3.app/v1/codes/qr_a1b2c3d4 \ -H "Authorization: Bearer qr3_sk_..."Télécharger les images de QR-Codes
Tous les formats d’image sont accessibles publiquement — aucune authentification n’est requise.
| Format | URL | Utilisation |
|---|---|---|
| SVG (vectoriel) | /v1/codes/:code/qr.svg | Web, mise à l’échelle, numérique |
| PNG (matriciel) | /v1/codes/:code/qr.png | E-mail, présentations |
| PDF (vectoriel) | /v1/codes/:code/qr.pdf | Par défaut : carré (uniquement le code) ; ?format=a4 pour une feuille d’impression |
| EPS (vectoriel) | /v1/codes/:code/qr.eps | Flux de travail d’impression professionnels (Adobe, imprimeries) |
Optionnel : ?size=N — Taille du module en pixels (2–20, par défaut : 4) pour SVG, PNG et EPS. Le PDF utilise une taille de module fixe.
Uniquement PDF : ?format=a4|square — Format de page (par défaut : square — uniquement le code + zone de silence, pas de marge blanche A4 ; a4 pour une feuille A4 prête à imprimer)
# SVG für Webcurl https://qr3.app/v1/codes/r7f3Kx/qr.svg
# PNG in hoher Auflösungcurl https://qr3.app/v1/codes/r7f3Kx/qr.png?size=10 -o qr-hires.png
# Kompaktes PDF (nur der Code, Standard)curl https://qr3.app/v1/codes/r7f3Kx/qr.pdf -o qr.pdf
# Druckfertiges A4-Blattcurl "https://qr3.app/v1/codes/r7f3Kx/qr.pdf?format=a4" -o qr-a4.pdfCouleurs et correction d’erreurs
Les quatre routes d’image acceptent trois paramètres optionnels. Ils s’appliquent à cette seule requête et prévalent sur les couleurs enregistrées sur le code (section suivante).
| Paramètre | Valeurs | Par défaut | SVG, PNG | PDF, EPS |
|---|---|---|---|---|
fg | Hex RRGGBB ou RGB | 000000 | est dessiné | est dessiné comme couleur d’impression |
bg | Hex comme fg ou transparent | ffffff | est dessiné | est dessiné comme couleur d’impression |
ecc | L, M, Q, H | M | s’applique | s’applique |
- Casse : La casse n’a pas d’importance, le
#est facultatif. S’il est envoyé, il doit être encodé en%23. - Les valeurs invalides sont considérées comme non définies.
?fg=lilarenvoie la couleur enregistrée sur le code, ou le noir normal si aucune n’est enregistrée, avec un statut200et jamais une erreur. Seul un?fg=000000explicite force le noir. bg=transparentrenvoie un SVG, PDF ou EPS sans arrière-plan et un PNG avec un véritable canal alpha. Le support sur lequel le code est placé doit être clair et laisser une zone de silence de 4 modules tout autour. Un code sombre sur un support sombre n’est pas lisible.- PDF et EPS écrivent le noir et le gris en niveaux de gris (plaque noire uniquement) et toute autre couleur en CMJN en pourcentages entiers, par exemple
1F4E79sous la forme C74 M36 Y0 K53. Dès qu’une couleur est choisie, un fond opaque se trouve derrière le code et sa zone de silence, en blanc ou dans la couleur debg, comme dans le SVG. Sans couleurs, les deux fichiers restent inchangés. Conversion et limites : Couleurs à l’impression. - Lisibilité : La route d’image ne vérifie pas le contraste. Un rapport d’au moins 4:1 et des modules sombres sur fond clair sont recommandés.
#1F4E79sur blanc a un rapport de 8,7:1,#ff6600sur blanc seulement 2,9:1. eccmodifie le motif de points, pas le contenu. Un code imprimé continue de fonctionner, mais les anciens et nouveaux fichiers d’impression ne doivent pas être mélangés.QouHrendent le code plus robuste, par exemple sur du carton ondulé. Un logo impose toujoursH.- Avec logo, la zone derrière le logo reste blanche, même avec un arrière-plan coloré ou transparent.
- Mise en cache : Seule l’image par défaut réelle (noir sur blanc, correction d’erreurs M, sans logo) est livrée comme immuable pendant 24 heures ; tout autre rendu pendant 5 minutes. Pour PDF et EPS, tout arrière-plan indiqué compte comme un écart :
bg=ffffffy dessine un fond blanc que le fichier standard n’a pas. - Disponibilité : Les couleurs et la correction d’erreurs sont disponibles dans tous les forfaits, y compris le forfait gratuit.
# Dark blue code on whitecurl "https://qr3.app/v1/codes/r7f3Kx/qr.svg?fg=1F4E79" -o qr-blue.svg
# Transparent PNG for a layout on a light surfacecurl "https://qr3.app/v1/codes/r7f3Kx/qr.png?size=10&bg=transparent" -o qr-transparent.png
# More robust for corrugated board: error correction Qcurl "https://qr3.app/v1/codes/r7f3Kx/qr.pdf?ecc=Q" -o qr-q.pdf// @qr3/sdk 1.2.0 or later — imageUrl() only builds the URL, it sends no request// Dark blue code on whiteqr3.codes.imageUrl('r7f3Kx', { format: 'svg', fg: '1F4E79' });// → https://qr3.app/v1/codes/r7f3Kx/qr.svg?fg=1F4E79
// Transparent PNG for a layout on a light surfaceqr3.codes.imageUrl('r7f3Kx', { format: 'png', size: 10, bg: 'transparent' });
// More robust for corrugated board: error correction Qqr3.codes.imageUrl('r7f3Kx', { format: 'pdf', ecc: 'Q' });Enregistrer les couleurs sur le code
PATCH /v1/codes/:id enregistre les couleurs sous appearance sur le code. Les routes d’image les dessinent ensuite par défaut, sans paramètre.
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4 \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{"appearance": {"foreground_color": "#1F4E79"}}'// @qr3/sdk 1.2.0 or laterconst code = await qr3.codes.update('qr_a1b2c3d4', { appearance: { foreground_color: '#1F4E79' },});code.appearance; // { foreground_color: '#1F4E79', background_color: null }code.issues; // contrast check findings, absent when there are noneRéponse (HTTP 200, abrégée) :
{ "data": { "id": "qr_a1b2c3d4", "short_code": "r7f3Kx", "appearance": { "foreground_color": "#1F4E79", "background_color": null } }, "meta": { "request_id": "req_xyz", "issues": [] }}- Valeurs :
foreground_colorsous forme de#RRGGBB,background_colorsous forme de#RRGGBBoutransparent. D’autres clés renvoient400. - Fusion : Un champ omis conserve sa valeur enregistrée.
nullréinitialise un champ,"appearance": nullréinitialise les deux. Le noir et le blanc ne sont pas enregistrés ; la réponse les affiche commenull. - Chaque réponse de code contient
appearance, tout comme les webhooksqr.createdetqr.updated. - Ordre dans les routes d’image : d’abord le paramètre, puis la couleur enregistrée, puis la valeur par défaut.
?fg=000000fournit donc le fichier d’impression noir d’un code couleur. - Images intégrées : Une URL d’image suit les couleurs enregistrées, dans la mesure où elle ne les définit pas elle-même avec
fgetbg: une URL sans paramètre pour les deux couleurs,?fg=000000pour l’arrière-plan,?ecc=Qégalement pour les deux. Après un changement de couleur, une page qui intègre une telle URL peut encore afficher l’ancienne image : pendant une durée allant jusqu’à 24 heures si l’URL livrait l’image par défaut jusque-là (noir sur blanc, correction d’erreurs M, sans logo), sinon pendant une durée allant jusqu’à 5 minutes. La solution consiste à ajouter votre propre paramètre à l’URL, qui change à chaque modification de couleur, par exemple?v=2ou leupdated_atdu code comme dans le tableau de bord. Les routes d’image ignorent les paramètres inconnus. - La correction d’erreurs n’est jamais enregistrée. Elle est choisie par téléchargement avec
?ecc=. - Uniquement via
PATCH:POST /v1/codes, le traitement par lots et l’importation rejettentappearanceavec422. - PDF et EPS dessinent les couleurs enregistrées comme des couleurs d’impression, tout comme les paramètres. Comme le blanc n’est jamais enregistré, un code avec une couleur de premier plan enregistrée y obtient un fond blanc, comme dans le SVG.
Vérification du contraste
L’API vérifie la paire résultant de la requête et de la valeur enregistrée :
| Niveau | Quand | Réponse |
|---|---|---|
blocked | Contraste inférieur à 1,5:1 | 422, rien n’est enregistré |
critical | inférieur à 2:1 ou différence de luminosité inférieure à 0,30 ; un avertissement en combinaison avec un logo ; tout arrière-plan transparent | 200 avec meta.issues |
warning | inférieur à 4:1 ou différence de luminosité inférieure à 0,50 ; modules clairs sur fond sombre | 200 avec meta.issues |
| ok | tout le reste | 200, meta.issues est vide |
Chaque entrée dans meta.issues contient code, severity, field, message et facultativement hints comme contrast_ratio — la même forme que les messages de conformité d’un passeport de produit numérique. Un arrière-plan transparent n’est jamais bloqué, car un code clair sur un emballage sombre est un cas d’utilisation réel. Le support nécessite néanmoins un contraste net et une zone de silence libre de 4 modules tout autour.
Le chargement et la suppression d’un logo (POST et DELETE /v1/codes/:id/logo) vérifient également les couleurs enregistrées et renvoient aussi les résultats dans meta.issues : avec un logo, un avertissement devient critical, sans logo, il redevient un avertissement.
Si une autre requête modifie le même code au même moment, l’API applique les modifications à la dernière version en date. Ce n’est que si cela échoue trois fois de suite qu’elle répond par 409 ; le client recharge alors le code et répète la modification.
Logo
POST /v1/codes/:id/logo
Requête multipart, champ file : PNG, JPEG ou WebP, 1 Mo maximum, détecté par les octets magiques. Normalise l’image en un PNG 512×512 transparent et remplace un logo existant.
curl -X POST https://qr3.app/v1/codes/qr_a1b2c3d4/logo \ -H "Authorization: Bearer qr3_sk_..." \Réponse (HTTP 201) : le code mis à jour, avec logo_file_id défini.
DELETE /v1/codes/:id/logo
Supprime le logo et efface l’objet stocké. Idempotent — un appel sans logo existant renvoie toujours 200.
Si une autre requête modifie le logo du même code au même moment (un second téléversement ou une suppression), POST et DELETE /v1/codes/:id/logo renvoient 409 (errors/conflict) et ne modifient rien ; l’image téléversée est supprimée. Rechargez le code et réessayez. Deux appels simultanés de DELETE /v1/codes/:id/logo ne constituent pas un conflit ; les deux renvoient 200.
S’il est défini, les quatre formats — qr.svg, qr.png, qr.pdf et qr.eps — intègrent les pixels du logo et augmentent la correction d’erreurs à H. Le contrat complet — y compris quel changement (ajout/suppression vs remplacement) modifie le motif de points — ainsi que les instructions d’impression se trouvent sous Logo dans le code QR.
Commentaires
Les commentaires permettent des boucles de rétroaction entre les agences et les clients.
GET /v1/codes/:id/comments
POST /v1/codes/:id/comments
PATCH /v1/codes/:id/comments/:commentId
DELETE /v1/codes/:id/comments/:commentId
Les commentaires créés depuis le Tableau de bord sont attribués à l’utilisateur qui les a générés (author_id) ; les commentaires créés via une simple clé API restent non attribués (author_id: null). Un commentaire ne peut être supprimé que par son propre auteur ou par un org_admin/ws_admin — une simple clé API ne peut supprimer que les commentaires non attribués créés par API.
# Kommentar hinzufügencurl -X POST https://qr3.app/v1/codes/qr_a1b2c3d4/comments \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "body": "QR-Code bitte auf grünen Hintergrund abstimmen.", "author_name": "Max Müller" }'
# Offene Kommentare auflistencurl "https://qr3.app/v1/codes/qr_a1b2c3d4/comments?resolved=false" \ -H "Authorization: Bearer qr3_sk_..."
# Kommentar als erledigt markierencurl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4/comments/cmt_xyz \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "resolved": true }'