Enqre

Publié le 16/08/2026

QR codes dynamiques en PHP : quand une API est nécessaire, et quand non

« Comment générer un QR code en PHP » a deux réponses très différentes, et la mauvaise coûte soit de l'argent, soit une réimpression.

Si le code est statique, faites-le en local

S'il vous faut une image d'une URL — billet, facture, reçu —, installez une bibliothèque et c'est fini. endroid/qr-code dessine PNG et SVG hors ligne : pas de clé, pas de quota, pas de dépendance à la disponibilité d'un tiers, pas de coût.

Cela couvre la majorité de ces questions, et tout article qui saute cette étape pour vous vendre quelque chose vous fait perdre l'après-midi.

Ce que change un code imprimé

Un code statique est sa destination : l'URL est dans le motif. Elle change, et tout l'imprimé est faux, définitivement.

La question n'est donc pas « PHP ou service », mais : après impression, la destination devra-t-elle bouger ? Si oui — et sur un emballage, une plaque, un dépliant, c'est la règle —, le code doit porter une adresse courte que vous contrôlez. C'est la seule chose qu'une bibliothèque ne peut pas faire, car il faut que quelqu'un réponde à cette adresse pendant des années.

En créer un

<?php
$ch = curl_init("https://enqre.com/api/v1/qrcodes");
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("ENQRE_API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "name" => "Order 10432 – delivery note",
        "url"  => "https://shop.example/orders/10432",
    ]),
]);

$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($status !== 201) {
    throw new RuntimeException("enqre: HTTP $status — $body");
}

$code = json_decode($body, true)["data"];
// $code["id"]       — store this against your record
// $code["shortUrl"] — the address the QR image should encode
  • Stockez l'id renvoyé sur votre enregistrement.
  • Mettez votre identifiant dans le nom.

Dessinez shortUrl avec la bibliothèque locale de votre choix : les deux tâches sont distinctes.

Déplacer la destination

<?php
$id = $code["id"];
$ch = curl_init("https://enqre.com/api/v1/qrcodes/$id");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "PATCH",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("ENQRE_API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "url" => "https://shop.example/orders/10432/tracking",
    ]),
]);
curl_exec($ch);
curl_close($ch);
// The printed code is untouched. It now opens the tracking page.

Lire les scans

<?php
$ch = curl_init("https://enqre.com/api/v1/qrcodes/$id/scans");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("ENQRE_API_KEY")],
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);

echo $res["total"];             // every scan ever counted
foreach ($res["data"] as $scan) {
    // createdAt, device, os, browser — and nothing else
}

À savoir avant de concevoir un rapport : un scan contient l'heure, le type d'appareil, le système et le navigateur. Ni identité, ni localisation.

Les erreurs réelles

  • 401 invalid_api_key
  • 400 invalid_body — presque toujours une URL qui n'en est pas une.
  • 402 plan_limit_reached
  • 429 rate_limited — au-delà de 60 requêtes par minute.

Vérifiez CURLINFO_RESPONSE_CODE plutôt que de faire confiance au corps de la réponse.

Deux choses dès le premier jour

Rendez la création idempotente. Deux appels créent deux codes.

N'imprimez rien sans relecture. Une requête après création évite la seule erreur irrécupérable.

Quand ne pas écrire l'intégration

Pour quelques centaines de codes en une fois, l'import CSV est plus rapide que n'importe quel code que vous écririez. Intégrez quand les codes arrivent en continu.

Réponses rapides

  • Meilleure bibliothèque PHP ? endroid/qr-code pour le dessin.
  • Dynamique en pur PHP ? Oui, si vous hébergez la redirection vous-même.
  • Authentification ? Authorization: Bearer enq_….
  • Limite ? 60 requêtes par minute.
  • L'API renvoie-t-elle l'image ? Non, elle renvoie shortUrl.
  • Localisation dans les scans ? Non.

À lire ensuite