Back to blog

Génération QR en Masse : Automatiser CSV vers API

Automatisez la génération QR en masse via un endpoint bulk : transformez un simple CSV en centaines de QR codes en quelques secondes, sans clics répétitifs.

Admin
8 min read

Génération QR en Masse : Automatiser CSV vers API

J'ai passé trois heures, un mardi soir de 2024, à cliquer sur "Créer un QR code" dans une interface web. Un par un. Mon client, une chaîne de 340 restaurants, avait besoin d'un QR par succursale pour son menu digital. J'ai fini à minuit avec les yeux secs et une haine profonde pour les boutons "Suivant".

Je n'ai plus jamais refait cette erreur. Aujourd'hui, la même tâche prend 40 secondes et un fichier CSV. Ce guide explique comment j'ai construit ce pipeline, colonne par colonne, requête par requête, pour que tu n'aies jamais à cliquer 340 fois sur rien.

Rows of colorful data on a computer screen representing a CSV spreadsheet - Unsplash

Pourquoi le CSV bat l'interface

L'interface manuelle a une limite dure : ton temps. Chaque QR code créé à la main coûte entre 30 secondes et 2 minutes selon le niveau de personnalisation. À 500 codes, ça fait entre 4 et 16 heures de clics répétitifs.

Un endpoint bulk génération QR élimine cette limite. Tu prépares les données une fois, tu envoies une requête, et le serveur fait le travail répétitif à ta place. Chez QR Code Agency, notre endpoint /api/v1/generate/bulk/ accepte jusqu'à 5 000 items en une seule requête HTTP, selon ton plan (50 sur le tier gratuit, 1 000 sur Starter, 5 000 sur Agency).

La vraie économie n'est pas juste le temps de création. C'est la reproductibilité. Si un client change 15 URLs sur 340, tu ne retournes pas cliquer 15 fois dans une interface, tu relances ton script avec un CSV mis à jour. J'ai des clients qui font tourner ce pipeline chaque trimestre sans jamais rouvrir de navigateur.

Le raisonnement derrière la génération QR en lot ressemble à celui de n'importe quel pipeline de données : entrée structurée, transformation, sortie structurée. Rien de magique, mais il faut respecter certaines règles avant d'envoyer quoi que ce soit.

Developer typing code on a laptop with terminal windows open - Unsplash

Structurer ton CSV correctement

La première fois que j'ai automatisé un lot, j'ai envoyé un CSV avec des URLs contenant des espaces non encodés. Résultat : 220 échecs sur 340, et l'API a tout rejeté parce que notre système fonctionne en mode tout-ou-rien. Un item invalide, et la requête entière retourne une erreur 422 sans consommer ton quota. C'est frustrant sur le coup, mais ça t'évite de payer pour un lot à moitié cassé.

Voici les colonnes minimales pour un CSV qui passe du premier coup :

  • destination_url : encodée en UTF-8, sans espaces bruts (remplace-les par %20 ou utilise une fonction d'encodage URL avant l'export)
  • label : identifiant unique par ligne, utile pour retracer chaque code dans le manifest.json retourné
  • logo_url : lien HTTPS vers un logo hébergé, jamais un chemin local (l'API fait un fetch protégé contre le SSRF)
  • frame_label : texte optionnel affiché sous le QR, 24 caractères maximum
  • color_fg / color_bg : codes hexadécimaux si tu personnalises les couleurs par ligne

Le point qui casse le plus de pipelines : les doublons. Si deux lignes ont le même label, ton système de tracking va mélanger les statistiques de scan entre deux codes différents. J'utilise toujours une passe de déduplication en Python avant l'export, avec pandas.drop_duplicates(subset='label'). Ça prend trois lignes de code et ça t'évite des semaines de données de scan inutilisables.

import pandas as pd

df = pd.read_csv("qr_batch.csv", encoding="utf-8")
df = df.drop_duplicates(subset="label")
df["destination_url"] = df["destination_url"].apply(lambda u: u.strip().replace(" ", "%20"))
df.to_csv("qr_batch_clean.csv", index=False)

Une fois le fichier propre, je le transforme en payload JSON. L'endpoint bulk n'accepte pas directement un CSV brut, il attend un tableau d'objets. Ce script fait le pont :

import csv, json

with open("qr_batch_clean.csv", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    items = [row for row in reader]

payload = {"items": items, "output_format": "png"}

with open("payload.json", "w") as f:
    json.dump(payload, f)

C'est basique, mais c'est exactement ce niveau de simplicité qui rend le pipeline fiable. J'ai vu des équipes construire des transformateurs CSV bien trop complexes, avec des règles conditionnelles imbriquées. Plus ton script de transformation est compliqué, plus il va casser silencieusement quand quelqu'un ajoute une colonne inattendue dans le CSV source.

Close-up of colorful QR codes printed on labels or stickers - Unsplash

Personnaliser chaque code du lot

C'est ici que la génération QR en masse CSV devient intéressante pour un développeur. L'endpoint bulk ne force pas un style uniforme sur tous les codes. Chaque item du tableau JSON peut porter ses propres paramètres de style, appliqués individuellement dans une seule requête.

J'ai un client, une agence immobilière avec 60 agents, qui voulait un QR par agent avec le logo de l'agence mais une couleur d'accent différente selon la région (bleu pour Montréal, vert pour Québec, orange pour Gatineau). Trois designs, 60 codes, une seule requête bulk. Voici comment le payload gère ça :

{
  "items": [
    {
      "label": "agent-jsmith-mtl",
      "destination_url": "https://agence.ca/agents/jsmith",
      "color_fg": "#1E3A8A",
      "logo_url": "https://assets.agence.ca/logo.png",
      "logo_size_ratio": 0.22,
      "pattern": "rounded"
    },
    {
      "label": "agent-mtremblay-qc",
      "destination_url": "https://agence.ca/agents/mtremblay",
      "color_fg": "#166534",
      "logo_url": "https://assets.agence.ca/logo.png",
      "logo_size_ratio": 0.22,
      "pattern": "rounded"
    }
  ],
  "output_format": "svg"
}

Le logo_size_ratio est plafonné à 0.30 chez nous, avec un défaut à 0.24. J'ai appris à la dure qu'un logo trop gros (au-dessus de 0.28) commence à manger dans la zone de correction d'erreur du QR, ce qui rend le code illisible sur certains téléphones plus vieux. Si ton client insiste pour un logo massif, active le logo_clear_zone pour carver une zone transparente propre derrière le logo, ça règle le problème neuf fois sur dix.

Pour la gestion des couleurs et des formes en lot, le principe reste le même : chaque objet JSON dans items est indépendant. Tu peux mélanger un pattern botanical pour une ligne de produits bio et un pattern classique pour le reste du catalogue, dans le même appel API. C'est ce genre de flexibilité qui manque cruellement aux interfaces web où tu appliques un style global à tout le lot.

J'ai écrit un article plus détaillé sur les erreurs coûteuses qu'on voit revenir sur les QR codes dynamiques, et la personnalisation en lot mal validée en fait partie. Un logo qui casse la lisibilité sur 200 stickers imprimés, ça ne se corrige pas avec un "oups", ça se corrige avec un nouveau tirage.

Printing press or large format printer producing labeled stickers - Unsplash

Gérer les formats et le volume

L'endpoint bulk retourne une archive ZIP contenant tous tes fichiers, plus un manifest.json qui mappe chaque label à son fichier de sortie. Trois formats sont disponibles : PNG (pour le web et les réseaux sociaux), SVG (pour l'impression vectorielle sans perte de qualité), PDF (pour les mises en page prêtes à imprimer directement).

Mon conseil, presque toujours contre-intuitif pour les gens qui débutent : génère en SVG par défaut, même si tu penses avoir besoin de PNG. Un SVG se convertit facilement en PNG haute résolution après coup, mais l'inverse est impossible sans perte. J'ai dû refaire un lot de 800 codes parce que le client voulait imprimer en grand format et que le PNG initial pixelisait à partir de 20 cm. Le SVG n'a jamais ce problème.

Sur le volume, voici la limite qui compte vraiment : la taille maximale du ZIP retourné est de 100 Mo. Si tu génères 5 000 codes en PDF avec des logos haute résolution, tu risques de frapper ce plafond avant même d'atteindre la limite de 5 000 items. Dans ce cas, je découpe le lot en plusieurs requêtes de 1 000 à 1 500 items, ce qui reste largement sous la barre des 100 Mo tout en gardant le nombre d'appels API raisonnable.

Pour les très gros volumes, la vraie question devient le traitement asynchrone. Une requête bulk avec 5 000 items complexes (logos, patterns personnalisés, frames) peut prendre plusieurs secondes à générer. Si ton pipeline attend une réponse synchrone avec un timeout HTTP standard de 30 secondes, tu vas te faire couper avant la fin du traitement. Ma pratique : je découpe systématiquement en batches de 500 à 1 000 items maximum, envoyés en séquence avec un léger délai entre chaque appel pour respecter les limites de rate-limiting de l'API.

import requests, json, time

def send_batch(items, batch_size=500):
    for i in range(0, len(items), batch_size):
        chunk = items[i:i+batch_size]
        payload = {"items": chunk, "output_format": "svg"}
        r = requests.post(
            "https://api.qrstudio.agency/api/v1/generate/bulk/",
            json=payload,
            headers={"Authorization": "Bearer TON_API_KEY"}
        )
        if r.status_code == 200:
            with open(f"batch_{i}.zip", "wb") as f:
                f.write(r.content)
        else:
            print(f"Batch {i} a échoué: {r.text}")
        time.sleep(1)

Ce découpage résout aussi un problème pratique : si un batch échoue à cause d'une ligne invalide, tu ne perds que 500 items à corriger, pas 5 000. C'est le genre de leçon que j'aurais aimé apprendre en lisant un article plutôt qu'en la vivant à 23h un jeudi soir, avec un client qui attendait sa livraison le lendemain matin.

Si tu construis ce pipeline sur des QR codes dynamiques plutôt que statiques (ce qui est presque toujours le bon choix pour un usage professionnel), tu vas vouloir comprendre la structure de coûts derrière chaque scan et chaque redirection. J'en parle en détail dans notre analyse du vrai coût selon les volumes, particulièrement utile quand tu passes de 500 à 5 000 codes actifs et que tu dois justifier le choix de plan à ton équipe finance.

Ce que j'aurais fait différemment

Si je recommençais ce projet du restaurant à 340 succursales aujourd'hui, je passerais 20 minutes à écrire le script de validation CSV avant même de toucher l'API. Pas parce que c'est compliqué, mais parce que c'est la partie qu'on saute toujours en pensant gagner du temps, et qui finit par en coûter dix fois plus.

La discipline qui fonctionne : valide localement (encodage, doublons, URLs bien formées), découpe en batches raisonnables, génère en SVG par défaut, et garde le manifest.json de chaque run pour retracer quel code correspond à quelle ligne. Ce n'est pas glamour, mais c'est ce qui sépare un pipeline qui tourne en production pendant deux ans d'un script qu'on abandonne après le premier bug silencieux.

Prépare ton CSV nettoyé, découpe-le en lots de 500, et lance ta première requête bulk cette semaine sur QR Code Agency plutôt que d'ouvrir une interface web une centième fois.


A lire aussi

Keep reading

Productivite & Outils

UTM sur QR codes : structurer vos campagnes dans GA4

Un paramètre UTM mal tagué sur un QR code imprimé se paie jusqu'à la fin du tirage. Voici une nomenclature fiable pour structurer vos campagnes print et garder des données GA4 propres.

8 min read
Productivite & Outils

Taille minimale d'un QR code imprimé : la règle des 10 % expliquée

La règle des 10 % relie la taille d'un QR code à sa distance de scan : un code lu à 1 mètre doit mesurer au moins 10 cm de côté. Voici comment appliquer ce calcul selon le support, les facteurs qui forcent à voir plus grand, et les erreurs qui coûtent un tirage complet.

8 min read
Productivite & Outils

QR code statique ou dynamique : lequel choisir selon votre usage

Un QR statique fige sa destination pour toujours ; un dynamique la laisse modifiable après impression, avec des statistiques de scan en prime. Voici la différence concrète, les cas où chaque format gagne, et la question à se poser avant d'imprimer quoi que ce soit.

6 min read