QRFLOW.codes
officielCréez des codes QR, redirigez des codes dynamiques imprimés, nommez des liens sur votre propre domaine et consultez les analyses de scans.
Que pouvez-vous faire avec QRFLOW Codes MCP ?
- Créer des codes QR dynamiques — Demandez de générer un
short_urlimprimable pour n’importe quelle URL, avec la possibilité de modifier la destination à tout moment après l’impression. - Rediriger les codes imprimés — Demandez de mettre à jour le
destination_datad’un code vers une nouvelle URL ; les codes déjà imprimés continuent de fonctionner sans réimpression. - Consulter les analyses de scans — Demandez des ventilations des
Scanspar jour, pays ou appareil pour voir les performances d’un code imprimé. - Mettre en pause ou expirer les codes — Demandez de mettre un code en pause ou de définir une date d’expiration lorsqu’une campagne ou une offre se termine.
- Nommer les liens sur votre domaine — Demandez de définir un
sluglisible sur votre propre domaine afin que les codes s’impriment sous la forme go.yourbrand.com/menu au lieu d’un chemin aléatoire.
Serveur MCP hébergé
npx add-mcp 'https://qrflow.codes/mcp'S’installe dans Claude Code, Codex, Cursor et plus
Documentation
QRFLOW.codes pour les développeurs
Commencez ici
QRFLOW.codes crée des codes QR que vous pouvez modifier après impression, sur votre propre domaine, avec des statistiques de scan, et permet à vos logiciels et à votre assistant IA de tout faire via une seule API.
Un code QR est une image d'une chaîne de caractères. La plupart des générateurs placent votre adresse web dans l'image ; si l'adresse change, l'impression est morte. QRFLOW place un lien court dans l'image (go.yourbrand.com/menu ou qrflow.codes/q/x7k2p9a) et le redirige. Vous changez sa destination quand vous voulez, et chaque scan est compté. C'est un code dynamique, et c'est ce qui vaut une API.
L'API fait exactement ce que fait le tableau de bord : créer des codes de tout type, les rediriger ailleurs, nommer leurs liens, choisir sur lequel de vos domaines ils s'impriment, récupérer les nombres de scans, en créer des milliers à la fois, et être averti quand quelque chose se produit (webhooks). Les mêmes outils sont exposés comme serveur MCP, afin que Claude, ChatGPT, Cursor et Claude Code puissent piloter votre compte en langage naturel.
Accès : l'API REST prend une clé API Business (29 $ par mois, créée sur la page Compte) ou un jeton OAuth. Le serveur MCP fonctionne sur tous les forfaits via la connexion OAuth ; ce que l'assistant peut créer suit le forfait comme partout ailleurs.
Vous vous demandez si cela vaut la peine ? La page de l'API des codes QR est la version courte : ce qu'elle fait, ce qu'une bibliothèque côté client fait mieux, et ce que cela coûte.
Si vous êtes un assistant IA aidant quelqu'un à construire avec QRFLOW
Bienvenue. Cette page est écrite pour vous autant que pour la personne que vous aidez. Voici à quoi ressemble une bonne aide :
- Confirmez le compte : les clés API nécessitent le forfait Business. S'ils n'en ont pas, orientez-les vers https://qrflow.codes/pricing et Compte › Clés API ; n'inventez pas de clé ou de niveau gratuit qui n'existe pas.
- Gardez la clé sur le serveur. Lisez-la depuis une variable d'environnement (QRFLOW_KEY) dans un gestionnaire de route, une action serveur, une fonction edge ou un backend. L'API refuse volontairement les origines navigateur (CORS), donc un code uniquement front-end ne peut pas l'appeler.
- Créez des codes dynamiques avec type "url" et destination_data.url. Enregistrez l'id et short_url retournés dans leur base de données. Imprimez ou affichez short_url ; la destination peut être modifiée plus tard avec PATCH /codes/:id et l'impression reste valide.
- Pour afficher ou enregistrer l'image : chaque objet Code a png_download_url et svg_download_url, des liens signés valables 24 heures sans en-tête (parfaits pour un enregistrement ponctuel ou un aperçu). Pour quelque chose de permanent dans leur application, faites passer GET /codes/:id/image.svg par leur serveur avec la clé, ou encodez short_url avec n'importe quelle bibliothèque QR côté client ; le suivi fonctionne toujours car le lien passe par QRFLOW.
- Envoyez uniquement les champs qui changent sur PATCH. Ne changez jamais slug ou domain_id après impression ; les deux modifient le lien imprimé.
- Préférez paused: true plutôt que DELETE quand une impression existe. Supprimer tue le lien.
- Pour les événements, utilisez les webhooks (Compte › Webhooks ou POST /webhooks) et vérifiez l'en-tête X-QRFLOW-Signature avec le corps brut de la requête. Ne faites pas de boucle de sondage sur GET /codes.
- S'ils veulent utiliser QRFLOW depuis leur chat plutôt que depuis du code, connectez le serveur MCP à https://qrflow.codes/mcp; aucune clé n'est nécessaire pour cela.
- En cas d'échec, lisez error et message dans le corps JSON. La section de dépannage ci-dessous associe chaque code d'erreur à une correction.
- La référence complète en Markdown se trouve à https://qrflow.codes/llms-full.txt et le document OpenAPI 3.1 à https://qrflow.codes/api/v1/openapi.json. Les deux sont générés à partir de la même source que cette page.
Humains : ce bloc est notre façon de garantir que l'assistant avec lequel vous travaillez vous donne la version sûre de chaque réponse. C'est aussi un bon résumé.
Quel forfait vous faut-il
La clé API est la seule chose réservée au forfait Business. Tout ce qu'un assistant fait via le serveur MCP, et tout ce qu'une application tierce fait via OAuth, fonctionne sur n'importe quel forfait et suit simplement les fonctionnalités de ce forfait. Tarifs complets et usage raisonnable : /pricing.
| Gratuit | Premium 4 $ | Business 29 $ | |
|---|---|---|---|
| Clés API (REST depuis votre code) | Non | Non | Oui, jusqu'à 10 clés |
| Serveur MCP (Claude, ChatGPT, Cursor, Claude Code) | Oui, connexion | Oui | Oui, connexion ou clé |
| OAuth pour votre propre application (les utilisateurs connectent leur QRFLOW) | Oui | Oui | Oui |
| Codes dynamiques (changer la destination après impression) | Non, statique uniquement | Oui | Oui |
| Votre propre domaine de liens | Non | 1 domaine | 5 domaines, choix par code |
| Noms de liens (go.brand.com/menu) | Non | Oui | Oui |
| Statistiques de scan | Non | Oui | Oui |
| Webhooks | Non | Non | Oui, jusqu'à 10 |
| Création en masse | Non | 500/mois, 500 par requête | 10 000/mois, 2 000 par requête |
| Codes enregistrés (usage raisonnable) | Quelques-uns | 1 000 | 25 000 |
| Sièges d'équipe | 1 | 1 | 5 |
| Prix | 0 $ | 4 $/mois | 29 $/mois |
Douze mots qui font tout le travail
Concepts
Lisez-les une fois et chaque point de terminaison ci-dessous aura du sens.
Static code
Le contenu est dans l'image. Les codes Wi-Fi, carte de contact (vCard) et texte brut sont toujours statiques, et sur le forfait Gratuit chaque code l'est. Un code statique n'a besoin d'aucun serveur et n'expire jamais, mais il ne peut être ni modifié ni compté.
Dynamic code
L'image contient un lien court que QRFLOW redirige. Les codes url, phone, email, sms et location sont dynamiques sur Premium et Business. Vous pouvez les rediriger, les mettre en pause, les faire expirer, les renommer et les compter sans toucher à l'impression.
short_url
La chaîne exacte encodée dans un code dynamique, et la chose à imprimer. C'est https://qrflow.codes/q/<short_code> jusqu'à ce que vous connectiez un domaine, puis https://<your domain>/<slug or short_code>. Chaque objet Code le porte.
short_code
Sept caractères aléatoires, uniques par code, attribués à la création et jamais modifiés. Le chemin de secours quand un code n'a pas de nom de lien.
slug (link name)
Un chemin lisible sur votre propre domaine : go.example.com/menu. 3 à 40 lettres minuscules, chiffres et tirets, unique dans votre compte, uniquement avec un domaine connecté. Définissez-le avant d'imprimer : le changer modifie le lien imprimé.
Link domain
Un nom d'hôte que vous possédez (go.example.com) pointé vers QRFLOW par un CNAME et vérifié sur la page Compte. Premium en a un ; Business en a cinq et peut choisir par code avec domain_id. Le domaine actif le plus ancien est le défaut.
Kind, type and subtype
type est l'encodage : url, text, wifi, vcard, email, phone, sms, location. Une kind est un nom plus convivial pour ce que les gens veulent (instagram, googlereview, whatsapp, pdf, menu, appstore,...). La plupart des kinds sont des codes url avec destination_data.subtype défini. GET /catalog liste chaque kind avec ses champs ; kind sur un Code vous indique lequel c'est.
destination_data
Les champs pour le type, sous forme de chaînes : { url } pour un site web, { ssid, password, encryption } pour le Wi-Fi, { placeId } pour un avis Google, { handle } pour Instagram. Sur un code dynamique, vous pouvez le remplacer à tout moment.
Scans
Chaque redirection enregistre le type d'appareil, le pays, la ville, le référent, le navigateur, le système d'exploitation et la langue à partir de la requête elle-même, plus un hachage quotidien à sens unique pour compter les visiteurs uniques. Aucun cookie n'est défini et l'adresse IP n'est pas stockée. scans sur un Code est le total cumulé ; GET /codes/:id/scans le détaille.
Source
Chaque code se souvient de ce qui l'a créé : dashboard, api:<key name>, mcp, canva ou bulk. Cela s'affiche dans le tableau de bord et dans les charges utiles des webhooks, afin que vous puissiez distinguer les codes de votre intégration de ceux faits à la main.
Workspace
Un propriétaire Business peut inviter jusqu'à quatre coéquipiers. Les clés et les webhooks appartiennent au compte du propriétaire ; les codes créés par n'importe qui dans l'espace de travail sont visibles par toute l'équipe.
Cinq minutes
Démarrage rapide
Obtenir une clé
- Sur le forfait Business, ouvrez Compte › Clés API.
- Nommez-la d'après ce à quoi elle sert ("Backend boutique", "Reporting") et choisissez ses portées. Les portées ne peuvent pas être modifiées ensuite ; créez une nouvelle clé si vous en avez besoin de plus.
- Copiez-la une fois. Elle ressemble à
qrf_live_…. Placez-la dans une variable d'environnement nomméeQRFLOW_KEY. - Envoyez-la comme
Authorization: Bearer $QRFLOW_KEYsur chaque requête. C'est toute l'histoire de l'authentification.
Les clés sont pour les serveurs. N'en mettez jamais une dans une page web, une application mobile ou un tableur partagé ; révoquez et réémettez si une fuite se produit.
Les mêmes cinq étapes en curl, TypeScript et Python. Chacune crée un code dynamique, télécharge son image, change sa destination et lit ses scans.
export QRFLOW_KEY=qrf_live_... # from Account › API keys
# 1. Who am I, what can this key do?
curl https://qrflow.codes/api/v1/me -H "Authorization: Bearer $QRFLOW_KEY"
# 2. Make a dynamic code. Print what comes back as short_url.
curl -X POST https://qrflow.codes/api/v1/codes \
-H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
-d '{ "type": "url", "destination_data": { "url": "https://example.com/menu" }, "label": "Table tents" }'
# 3. The print-ready image (SVG, with your colors and frame).
curl "https://qrflow.codes/api/v1/codes/$CODE_ID/image.svg?size=1024" \
-H "Authorization: Bearer $QRFLOW_KEY" -o menu.svg
# 4. Fall menu. The printed code keeps working.
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID \
-H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
-d '{ "destination_data": { "url": "https://example.com/menu-fall" } }'
# 5. How did it do?
curl "https://qrflow.codes/api/v1/codes/$CODE_ID/scans?group=day" -H "Authorization: Bearer $QRFLOW_KEY"
TypeScript (Node 18+, Bun, Deno, Workers)
// npm install qrflow (zero dependencies; ESM + CommonJS; full types)
import { QRFlow, QRFlowError } from "qrflow";
const qr = new QRFlow(process.env.QRFLOW_KEY!);
const { code } = await qr.createCode({
type: "url",
destination_data: { url: "https://example.com/menu" },
label: "Table tents",
});
console.log(code.id, code.short_url); // save both; print short_url
await qr.updateCode(code.id, { destination_data: { url: "https://example.com/menu-fall" } });
const stats = await qr.scans(code.id, { group: "day" });
console.log(stats.total, stats.rows); // [{ key: "2026-09-21", scans: 18 }, ...]
try {
await qr.updateCode(code.id, { slug: "menu" });
} catch (e) {
if (e instanceof QRFlowError) console.log(e.status, e.code, e.message); // 400 no_domain: connect a domain first
}
# Download https://qrflow.codes/sdk/qrflow.py next to your code.
import os
from qrflow import QRFlow, QRFlowError
qr = QRFlow(os.environ["QRFLOW_KEY"])
code = qr.create_code(type="url", destination_data={"url": "https://example.com/menu"}, label="Table tents")["code"]
print(code["id"], code["short_url"]) # save both; print short_url
qr.update_code(code["id"], destination_data={"url": "https://example.com/menu-fall"})
stats = qr.scans(code["id"], group="day")
print(stats["total"], stats["rows"])
try:
qr.update_code(code["id"], slug="menu")
except QRFlowError as e:
print(e.status, e.code, e) # 400 no_domain: connect a domain first
Authentification
Clés API (Business)
Jusqu'à 10 par compte, 600 requêtes par minute chacune, stockées hachées, affichées une fois. Une clé porte les portées avec lesquelles elle a été créée :
| Portée | Permet |
|---|---|
| profile | GET /me : forfait, fonctionnalités, limites. Chaque clé l'a. |
| codes:read | Lister et lire les codes, télécharger les images. |
| codes:write | Créer, modifier, rendre dynamique, supprimer, création en masse. |
| analytics:read | GET /codes/:id/scans. |
| domains:read | GET /domains (nécessaire pour utiliser domain_id correctement). |
| webhooks:manage | Lister, créer, tester et supprimer les webhooks. |
OAuth 2.0 (tous forfaits, pour applications et assistants)
Quand les codes doivent appartenir aux comptes de vos utilisateurs plutôt qu'au vôtre, ou quand un assistant de chat est le client, utilisez OAuth. Les clients s'enregistrent eux-mêmes ; PKCE S256 est requis pour les clients publics ; les jetons peuvent être liés au serveur MCP avec resource=. La recette OAuth vous guide pas à pas.
| Point de terminaison | URL | Notes |
|---|---|---|
| Autorisation | https://qrflow.codes/oauth/authorize | Envoyez l'utilisateur ici ; il se connecte et appuie sur Autoriser. |
| Jeton | https://qrflow.codes/api/oauth/token | Subventions authorization_code et refresh_token. Les jetons d'accès durent 1 heure, les jetons d'actualisation 90 jours. |
| Révocation | https://qrflow.codes/api/oauth/revoke | RFC 7009. Les utilisateurs peuvent aussi se déconnecter via Compte › Applications connectées. |
| Enregistrer un client | https://qrflow.codes/api/oauth/register | Enregistrement dynamique RFC 7591, sans compte nécessaire. Les clients publics reçoivent un client_id dyn_ et doivent utiliser PKCE S256. |
| Découverte | https://qrflow.codes/.well-known/oauth-authorization-server | RFC 8414. Le document de ressource MCP est à /.well-known/oauth-protected-resource. |
Les jetons d'accès durent 1 heure, les jetons d'actualisation 90 jours. Les utilisateurs voient les applications connectées sur Compte › Applications connectées et peuvent se déconnecter à tout moment. Un jeton émis pour https://qrflow.codes/mcp est refusé sur /api/v1, et inversement.
Les choses que les gens demandent vraiment
Recettes de construction
Chaque recette est complète et copiée directement de code fonctionnel. Choisissez celle qui correspond à votre pile ; la forme est toujours la même : un appel côté serveur avec la clé, enregistrez id et short_url, affichez l'image.
- Next.js
- Afficher le QR sans proxy
- Express ou tout serveur Node
- Cloudflare Workers, Vercel Edge, Deno Deploy, Supabase Edge Functions
- Python
- Un code QR par commande, table, produit, billet ou événement
- Changer la destination d'un code imprimé
- Imprimer des codes sur votre propre domaine
- Un graphique de scans dans votre propre administration
- Recevoir des webhooks dans Next.js et les vérifier
- Recevoir des webhooks en Python
- Des milliers de codes depuis un CSV
- Laisser vos utilisateurs connecter leur propre compte QRFLOW (OAuth)
- Zapier, Make, n8n
Next.js : une route qui crée un code et une route qui l'affiche
Quand : Vous avez une application Next.js (App Router) et voulez un bouton qui crée un code QR et une page qui l'affiche.
- Placez votre clé dans .env.local comme QRFLOW_KEY. Ne la préfixez jamais avec NEXT_PUBLIC_.
- Ajoutez un gestionnaire de route POST qui crée le code et retourne id et short_url.
- Ajoutez une route GET qui fait passer l'image par proxy afin que le navigateur ne voie jamais la clé.
- Stockez id et short_url sur votre propre enregistrement (commande, table, produit, événement).
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const { url, label } = await req.json();
const r = await fetch("https://qrflow.codes/api/v1/codes", {
method: "POST",
headers: { Authorization: \`Bearer ${process.env.QRFLOW_KEY}\`, "Content-Type": "application/json" },
body: JSON.stringify({ type: "url", destination_data: { url }, label }),
});
const data = await r.json();
if (!r.ok) return NextResponse.json(data, { status: r.status }); // { error, message }
return NextResponse.json({ id: data.code.id, short_url: data.code.short_url });
}
// Proxies the SVG so the key stays on the server. Check that the signed-in
// user owns this id before you serve it, or anyone with an id can fetch it.
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const r = await fetch(\`https://qrflow.codes/api/v1/codes/${id}/image.svg?size=1024\`, {
headers: { Authorization: \`Bearer ${process.env.QRFLOW_KEY}\` },
});
return new Response(r.body, {
status: r.status,
headers: { "Content-Type": "image/svg+xml", "Cache-Control": "private, max-age=3600" },
});
}
<img src={\`/api/qr/${code.id}/image\`} alt={\`QR code for ${code.label}\`} width={256} height={256} />
<a href={code.short_url}>{code.short_url}</a>
- Les Server Actions fonctionnent de la même manière : appelez fetch avec la clé dans l'action.
- Pour Pages Router, le même code va dans pages/api/qr.ts avec req/res.
Afficher le QR sans proxy : rendez short_url vous-même
Quand : Vous voulez l'image dans le navigateur immédiatement et n'avez pas besoin des cadres ou du logo de QRFLOW dessus. Toute bibliothèque de QR fonctionne, car le code EST le lien court
import QRCode from "qrcode"; // npm i qrcode
// short_url came back from POST /codes. Encode it as-is.
const dataUrl = await QRCode.toDataURL(code.short_url, { width: 512, margin: 2 });
// <img src={dataUrl} /> scans go through QRFLOW, so analytics and re-pointing still work.
- C'est le chemin le plus rapide pour un aperçu. Pour l'impression, téléchargez /codes/:id/image.svg : il contient les couleurs, le cadre, les légendes et le logo enregistrés, et c'est un vecteur.
- Si vous changez ensuite le slug ou domain_id, short_url change ; ré-rendez l'image.
Express ou tout serveur Node
Quand : Un backend Node simple.
import express from "express";
const app = express();
app.use(express.json());
const H = { Authorization: \`Bearer ${process.env.QRFLOW_KEY}\`, "Content-Type": "application/json" };
app.post("/qr", async (req, res) => {
const r = await fetch("https://qrflow.codes/api/v1/codes", {
method: "POST", headers: H,
body: JSON.stringify({ type: "url", destination_data: { url: req.body.url }, label: req.body.label }),
});
res.status(r.status).json(await r.json());
});
app.get("/qr/:id.svg", async (req, res) => {
const r = await fetch(\`https://qrflow.codes/api/v1/codes/${req.params.id}/image.svg\`, { headers: H });
res.status(r.status).type("image/svg+xml").send(await r.text());
});
app.listen(3000);
Cloudflare Workers, Vercel Edge, Deno Deploy, Supabase Edge Functions
Quand : Un runtime fetch-only sans built-ins Node.
export default {
async fetch(req: Request, env: { QRFLOW_KEY: string }) {
const { url, label } = await req.json();
const r = await fetch("https://qrflow.codes/api/v1/codes", {
method: "POST",
headers: { Authorization: \`Bearer ${env.QRFLOW_KEY}\`, "Content-Type": "application/json" },
body: JSON.stringify({ type: "url", destination_data: { url }, label }),
});
return new Response(r.body, { status: r.status, headers: { "Content-Type": "application/json" } });
},
};
Deno.serve(async (req) => {
const { url, label } = await req.json();
const r = await fetch("https://qrflow.codes/api/v1/codes", {
method: "POST",
headers: { Authorization: \`Bearer ${Deno.env.get("QRFLOW_KEY")}\`, "Content-Type": "application/json" },
body: JSON.stringify({ type: "url", destination_data: { url }, label }),
});
return new Response(await r.text(), { status: r.status, headers: { "Content-Type": "application/json" } });
});
// supabase secrets set QRFLOW_KEY=qrf_live_...
- Le package npm
qrflow\n'utilise que fetch et WebCrypto, donc il fonctionne dans tous ces environnements sans modification.
Python : FastAPI, Flask, Django, un script
Quand : Votre backend est en Python.
import os
from fastapi import FastAPI, HTTPException, Response
from qrflow import QRFlow, QRFlowError # https://qrflow.codes/sdk/qrflow.py
app = FastAPI()
qr = QRFlow(os.environ["QRFLOW_KEY"])
@app.post("/qr")
def make_qr(url: str, label: str | None = None):
try:
code = qr.create_code(type="url", destination_data={"url": url}, label=label)["code"]
except QRFlowError as e:
raise HTTPException(e.status, {"error": e.code, "message": str(e)})
return {"id": code["id"], "short_url": code["short_url"]}
@app.get("/qr/{code_id}.svg")
def qr_image(code_id: str):
import urllib.request
req = urllib.request.Request(qr.image_url(code_id), headers={"Authorization": f"Bearer {os.environ['QRFLOW_KEY']}"})
with urllib.request.urlopen(req) as r:
return Response(r.read(), media_type="image/svg+xml")
Un code QR par commande, table, produit, billet ou événement
Quand : Chaque ligne d'une de vos tables a besoin de son propre code, généré automatiquement.
- Ajoutez deux colonnes à votre table : qrflow_code_id (uuid) et qr_short_url (texte).
- Quand une ligne est créée, POST /codes avec l'URL publique de la ligne et un libellé qui nomme la ligne (« Commande 10432 », « Table 7 »). Enregistrez id et short_url.
- Quand la page de la ligne change (nouveau domaine, nouveau chemin), PATCH destination_data. Les codes imprimés continuent de fonctionner.
- Quand la ligne est retirée, PATCH { paused: true } si quelque chose a été imprimé ; DELETE uniquement si rien ne l'a été.
- Besoin de milliers de codes d'un coup (un menu par table pour 300 restaurants) ? Utilisez POST /codes/bulk par lots et mappez les codes retournés à vos lignes par libellé ou par ordre.
const { code } = await qr.createCode({
type: "url",
destination_data: { url: \`https://example.com/orders/${order.id}\` },
label: \`Order ${order.number}\`,
});
await db.orders.update(order.id, { qrflow_code_id: code.id, qr_short_url: code.short_url });
- L'usage raisonnable est de 25 000 codes enregistrés sur Business ; l'API s'arrête au double. Si vous avez besoin d'un code par reçu pour toujours, parlez-nous d'abord : hello@qrflow.codes.
Changer la destination d'un code imprimé
Quand : Une campagne est terminée, une page a déménagé, un PDF a été remplacé, une saison a changé.
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID \
-H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
-d '{ "destination_data": { "url": "https://example.com/spring" } }'
Mettez-le en pause, ou donnez-lui une date de fin
# Scans show a "paused" page instead of redirecting
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID -H "Authorization: Bearer $QRFLOW_KEY" \
-H "Content-Type: application/json" -d '{ "paused": true }'
# Stops working after the date; null clears it
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID -H "Authorization: Bearer $QRFLOW_KEY" \
-H "Content-Type: application/json" -d '{ "expires_at": "2026-12-31T23:59:59Z" }'
- Seuls les codes dynamiques peuvent être redirigés. Un code url créé sur un compte Free, ou un code Wi-Fi/vCard/texte, répond 400 not_dynamic. Pour un code url/téléphone/email/sms/localisation sur un plan payant, POST /codes/:id/dynamic le convertit, et vous devez ré-rendre et ré-imprimer car l'image change.
- Un scanner voit la nouvelle destination à la prochaine analyse. Il n'y a pas de cache à attendre.
Imprimer des codes sur votre propre domaine
Quand : Vous voulez go.example.com/menu dans le code au lieu de qrflow.codes/q/x7k2p9a.
- Sur la page Compte, sous Votre propre domaine de lien, ajoutez go.example.com et créez le CNAME qu'elle vous montre chez votre fournisseur DNS. La vérification se termine généralement en quelques minutes.
- Dès lors, chaque nouveau code dynamique short_url utilise ce domaine. Les codes existants basculent aussi : leur image encodait qrflow.codes/q/..., qui continue de rediriger, donc rien d'imprimé ne casse.
- Donnez aux codes des noms lisibles avec slug : PATCH { "slug": "menu" } crée go.example.com/menu. Faites-le avant d'imprimer.
- Sur Business avec plusieurs domaines, GET /domains les liste avec leurs ids ; passez domain_id sur POST ou PATCH pour choisir par code.
Nommez un lien et choisissez un domaine
curl https://qrflow.codes/api/v1/domains -H "Authorization: Bearer $QRFLOW_KEY"
# { "default_base": "https://go.example.com", "domains": [ { "id": "…", "host": "go.example.com", "is_default": true, … }, { "id": "…", "host": "qr.example.fr", … } ] }
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID -H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
-d '{ "slug": "menu", "domain_id": "<id of qr.example.fr>" }'
# short_url is now https://qr.example.fr/menu
Un graphique de scans dans votre propre admin
Quand : Vous voulez des scans par jour, par pays ou par appareil à côté de vos propres chiffres.
const stats = await qr.scans(code.id, { from: "2026-09-01", to: "2026-09-30", group: "day" });
// stats.total -> 412
// stats.rows -> [{ key: "2026-09-01", scans: 18 }, { key: "2026-09-02", scans: 25 }, ...]
// Feed rows straight into Recharts, Chart.js, or a <table>.
const byCountry = await qr.scans(code.id, { group: "country" }); // [{ key: "US", scans: 300 }, { key: "MX", scans: 41 }]
const byDevice = await qr.scans(code.id, { group: "device" }); // mobile, desktop, tablet
- Une requête couvre jusqu'à 92 jours ; bouclez pour des plages plus longues. Les dates sont en UTC.
- Pour des chiffres en direct sans polling, abonnez un webhook à l'événement scan : vous recevez chaque scan avec ses détails par lots toutes les quelques minutes.
Recevoir des webhooks dans Next.js et les vérifier
Quand : Vous voulez savoir quand un code est scanné ou modifié, dans votre propre base de données, en quasi temps réel.
- Créez le webhook sur Compte › Webhooks ou avec POST /webhooks. Copiez le secret (whsec_...) une fois dans QRFLOW_WEBHOOK_SECRET.
- Lisez le corps brut comme texte avant de l'analyser ; la signature couvre les octets exacts.
- Vérifiez, puis basculez sur l'événement. Répondez 2xx rapidement ; faites le travail lent après avoir répondu ou dans une file d'attente.
- Appuyez sur Test sur le webhook pour recevoir un ping signé et confirmer le câblage.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(raw: string, header: string, secret: string): boolean {
const t = /t=(\d+)/.exec(header)?.[1], v1 = /v1=([a-f0-9]+)/.exec(header)?.[1];
if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac("sha256", secret).update(\`${t}.${raw}\`).digest("hex");
return expected.length === v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
export async function POST(req: Request) {
const raw = await req.text();
if (!verify(raw, req.headers.get("x-qrflow-signature") ?? "", process.env.QRFLOW_WEBHOOK_SECRET!)) {
return new Response("bad signature", { status: 401 });
}
const evt = JSON.parse(raw) as { id: string; event: string; created_at: string; data: any };
// evt.id is stable across retries: store it and skip duplicates.
switch (evt.event) {
case "scan": // evt.data.scans[]: code_id, label, slug, scanned_at, device, country, city, referrer, browser, os, language
break;
case "code.created": // evt.data.code, evt.data.source
case "code.updated": // evt.data.code, evt.data.changed[]
case "code.deleted": // evt.data.code { id, label, short_code, slug }
break;
case "ping": // the Test button
break;
}
return new Response(null, { status: 204 });
}
- Localement, exposez votre serveur de développement avec un tunnel (cloudflared tunnel --url http://localhost:3000, ou ngrok) et utilisez cette URL https pour le webhook pendant que vous construisez.
- Le package npm fait cela pour vous :
import { parseWebhook } from "qrflow"\vérifie et analyse en un seul appel (WebCrypto, donc il fonctionne aussi dans Workers et Deno). Le client Python fournit verify_webhook.
Recevoir des webhooks en Python
Quand : Flask, FastAPI ou Django recevant les mêmes événements.
import os, json
from flask import Flask, request, abort
from qrflow import verify_webhook # https://qrflow.codes/sdk/qrflow.py
app = Flask(__name__)
@app.post("/qrflow")
def hook():
raw = request.get_data() # bytes, before any parsing
if not verify_webhook(raw, request.headers.get("X-QRFLOW-Signature", ""), os.environ["QRFLOW_WEBHOOK_SECRET"]):
abort(401)
evt = json.loads(raw)
if evt["event"] == "scan":
for s in evt["data"]["scans"]:
print(s["code_id"], s["scanned_at"], s["country"], s["device"])
return "", 204
Des milliers de codes depuis un CSV
Quand : Un code par SKU, par siège, par étiquette d'actif, par envoi postal.
import { parse } from "csv-parse/sync";
import { readFileSync } from "node:fs";
const rows = parse(readFileSync("skus.csv"), { columns: true }) as Array<{ sku: string; url: string }>;
const out: Array<{ sku: string; id: string; short_url: string }> = [];
for (let i = 0; i < rows.length; i += 2000) { // Business: 2,000 per request
const chunk = rows.slice(i, i + 2000);
const { codes, rejected, remaining_this_month } = await qr.bulkCreate(
chunk.map((r) => ({ destination: r.url, label: r.sku })),
);
codes.forEach((c, j) => out.push({ sku: chunk[j].sku, id: c.id, short_url: c.short_url }));
if (rejected.length) console.warn(rejected); // rows that were not web addresses
console.log(remaining_this_month, "left this month");
}
- Bulk crée uniquement des codes url dynamiques, tous avec les mêmes couleurs. Les codes reviennent dans l'ordre où vous les avez envoyés, moins les lignes rejetées ; faites correspondre par libellé en cas de doute.
- Les webhooks reçoivent un événement code.created par requête bulk avec codes[] au lieu d'un par code.
Laissez vos utilisateurs connecter leur propre compte QRFLOW (OAuth)
Quand : Vous construisez un produit pour d'autres personnes et voulez que les codes arrivent dans leurs comptes QRFLOW, pas le vôtre.
- Enregistrez un client une fois : POST https://qrflow.codes/api/oauth/register avec client_name et redirect_uris. Vous obtenez un client_id (et un client_secret pour les clients confidentiels).
- Envoyez l'utilisateur vers /oauth/authorize avec response_type=code, client_id, redirect_uri, scope, state, et PKCE (code_challenge, code_challenge_method=S256).
- Échangez le code à /api/oauth/token. Stockez le refresh token ; les access tokens durent une heure.
- Appelez /api/v1 avec Authorization: Bearer <access_token>. Tout fonctionne exactement comme avec une clé, sous le plan de l'utilisateur.
curl -X POST https://qrflow.codes/api/oauth/register -H "Content-Type: application/json" \
-d '{ "client_name": "Acme Menus", "redirect_uris": ["https://app.example.com/oauth/qrflow"], "token_endpoint_auth_method": "none" }'
# { "client_id": "dyn_…", "redirect_uris": [...], "grant_types": ["authorization_code","refresh_token"], … }
https://qrflow.codes/oauth/authorize?response_type=code&client_id=dyn_…&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fqrflow
&scope=profile%20codes%3Aread%20codes%3Awrite%20analytics%3Aread&state=…&code_challenge=…&code_challenge_method=S256
- Les scopes sont les mêmes six que pour les clés API. Demandez le minimum nécessaire ; l'écran de consentement les liste.
- Si votre application est un assistant de chat ou un agent, ajoutez resource=https://qrflow.codes/mcp à la requête d'autorisation et parlez au serveur MCP à la place ; le jeton y sera lié.
Zapier, Make, n8n : aucun code du tout
Quand : Vous voulez que des scans ou de nouveaux codes arrivent dans une feuille, un canal Slack ou un CRM.
- Créez un déclencheur catch-hook (Zapier : Webhooks by Zapier › Catch Hook ; Make : Custom webhook ; n8n : nœud Webhook) et copiez son URL https.
- Sur Compte › Webhooks, ajoutez cette URL et choisissez les événements. Appuyez sur Test ; le ping apparaît dans l'outil et lui donne la forme du payload.
- Mappez data.scans[] (pour scan) ou data.code (pour code.*) vers votre feuille, message ou enregistrement.
- Pour créer des codes depuis ces outils, utilisez leur module HTTP contre POST /codes avec l'en-tête Authorization. Gardez la clé dans le stockage d'identifiants de l'outil.
- Ces outils ne peuvent pas vérifier la signature. L'URL qu'ils vous donnent est impossible à deviner, c'est la protection que vous avez ; ne la publiez nulle part.
Vibe coding
Invites à coller
Les assistants de codage construisent la bonne chose quand on leur donne les règles dès le départ. Ces invites portent les règles. Collez-en une, remplissez le crochet, et l'assistant lira la référence Markdown avant d'écrire une ligne.
Ajouter des codes QR à mon application
Claude, ChatGPT, Cursor, Codex, Windsurf, Copilot Chat : collez dans le chat
Add QR codes to this project using the QRFLOW.codes API.
Read https://qrflow.codes/llms-full.txt before writing code; it is the complete reference.
Rules:
- The API key is in the environment variable QRFLOW_KEY. It must only be used server-side (route handler, server action, edge function). Never expose it to the browser.
- Create dynamic codes: POST https://qrflow.codes/api/v1/codes with { "type": "url", "destination_data": { "url": ... }, "label": ... }.
- Save the returned code.id and code.short_url on my record. short_url is what gets printed or displayed.
- Show the image by proxying GET /codes/:id/image.svg through my server, or by encoding short_url with a QR library on the client.
- Handle errors from the JSON body: { "error", "message" }. Map 402 to "upgrade needed", 429 to a retry with the Retry-After header.
What I want: [describe the feature, e.g. "every event in my events table gets a QR code that opens its public page; show it on the event admin page with a download button"].
Enseignez à votre dépôt QRFLOW
Déposez dans CLAUDE.md, AGENTS.md, .cursorrules ou .github/copilot-instructions.md
## QR codes (QRFLOW.codes)
- Docs: https://qrflow.codes/llms-full.txt (Markdown), https://qrflow.codes/api/v1/openapi.json (OpenAPI 3.1).
- Base URL https://qrflow.codes/api/v1, header Authorization: Bearer $QRFLOW_KEY. Server-side only.
- Codes are created with POST /codes { type: "url", destination_data: { url }, label }. Store code.id and code.short_url.
- Change the destination with PATCH /codes/:id { destination_data: { url } }. Never change slug/domain_id after printing.
- Image: GET /codes/:id/image.svg (needs the key). Prefer paused: true over DELETE when a print exists.
- Webhooks arrive as POST with X-QRFLOW-Signature (t=,v1=HMAC-SHA256 of "t.rawBody"); verify with the raw body.
Dans Lovable, Bolt, v0, Replit et autres constructeurs d'applications
Constructeurs front-end d'abord qui vous donnent un backend (Supabase, fonctions serverless)
Integrate QRFLOW.codes QR codes. The API refuses browser calls, so create a backend function (Supabase Edge Function / serverless function) that holds the secret QRFLOW_KEY and calls POST https://qrflow.codes/api/v1/codes with { "type": "url", "destination_data": { "url": "<the page URL>" }, "label": "<name>" }. Return code.id and code.short_url to the UI and save them in the database. Render the QR in the UI by encoding short_url with a QR library; add a "Download for print" button that fetches /codes/:id/image.svg through the same backend function. Reference: https://qrflow.codes/llms-full.txt
Un GPT personnalisé qui gère mes codes
ChatGPT › Créer un GPT › Actions
Import from URL: https://qrflow.codes/api/v1/openapi.json
Authentication: API Key › Bearer › paste a Business key with the scopes you want the GPT to have.
Then the GPT can list, create, re-point and report on your codes. For a no-setup version, add the MCP connector instead (Developer mode › Plugins › https://qrflow.codes/mcp).
Choses à dire une fois le connecteur installé
Claude, ChatGPT, Claude Code avec le serveur MCP QRFLOW connecté
"Make a QR code for https://example.com/fall-menu, call it Fall menu, frame caption 'Scan for menu'."
"Which of my codes got the most scans this month? Show a breakdown by country for the top one."
"Point the 'Lobby poster' code at https://example.com/events/october."
"Name the 'Business card' code's link 'hi' on my domain."
"Pause every code with 'Summer' in the label."
"Make 40 codes, one per table, going to https://example.com/order?table=1 through 40."
"Show me the PNG of the 'Front door' code."
Serveur MCP
Utilisez-le depuis Claude, ChatGPT, Cursor et Claude Code
QRFLOW est un serveur MCP à https://qrflow.codes/mcp. Connectez-le une fois, connectez-vous, puis dites des choses comme « crée un code QR pour notre page de menu d'automne, nommé menu sur mon domaine », « pointe le code de l'affiche du lobby vers la nouvelle page » ou « combien de scans le dépliant a-t-il eu la semaine dernière, par pays ? ». L'assistant obtient les mêmes outils que cette API offre, sous les mêmes règles, et les codes arrivent dans votre tableau de bord avec mcp comme source.
Pas un développeur ? La version en langage simple, avec les clics exacts pour chaque assistant, est à Créer des codes QR avec votre assistant IA.
Connecter
Personnaliser › Connecteurs › Ajouter un connecteur personnalisé › collez l'adresse, ou appuyez sur Connecter sur la fiche de QRFLOW dans l'annuaire. Claude ouvre une connexion QRFLOW ; appuyez sur Autoriser. Fonctionne sur tous les plans.
https://qrflow.codes/mcp
Paramètres › Sécurité et connexion › Mode développeur activé, puis Paramètres › Plugins › + › collez l'adresse ; connectez-vous quand demandé. Plus, Pro, Team, Enterprise et Edu.
https://qrflow.codes/mcp
Une commande, puis /mcp pour vous connecter. Ajoutez une clé Business comme en-tête pour sauter la connexion.
claude mcp add --transport http qrflow https://qrflow.codes/mcp
# or, with a key:
claude mcp add --transport http qrflow https://qrflow.codes/mcp --header "Authorization: Bearer $QRFLOW_KEY"
Cursor, Windsurf, VS Code, tout client MCP
Ajoutez un serveur HTTP à l'URL. La connexion OAuth se fait dans le navigateur ; ou passez un en-tête Authorization avec une clé.
{
"mcpServers": {
"qrflow": { "type": "http", "url": "https://qrflow.codes/mcp" }
}
}
Votre propre agent (SDK Anthropic ou OpenAI)
Pointez le connecteur MCP ou l'outil vers l'URL avec une clé Business comme bearer ; aucun flux navigateur nécessaire.
// Anthropic Messages API, MCP connector
mcp_servers: [{ type: "url", url: "https://qrflow.codes/mcp", name: "qrflow", authorization_token: process.env.QRFLOW_KEY }]
Ce que l'assistant peut faire
| Outil | Ce qu'il fait | Portée |
|---|---|---|
| list_code_kinds | Chaque type de code avec ses champs et le plan nécessaire. L'assistant l'appelle avant de créer quelque chose d'inhabituel. | profile |
| list_domains | Vos domaines de lien, le défaut, et leurs ids. | domains:read |
| get_qr_image | Un PNG que l'assistant peut afficher ou enregistrer, plus l'URL SVG pour l'impression. | codes:read |
| get_account | Qui est connecté, plan, limites. | profile |
Comment cela reste sûr
- L'assistant ne détient jamais qu'un jeton pour votre compte, émis après que vous avez appuyé sur Autoriser sur une page QRFLOW. Déconnectez-le à tout moment sur Compte › Applications connectées.
- Les jetons sont liés au serveur MCP ; ils ne peuvent pas être rejoués contre l'API REST.
- Chaque écriture passe par la même validation que le tableau de bord : destinations en liste blanche, vérifications de plan, plafonds d'usage raisonnable.
- Les outils destructeurs se décrivent soigneusement :
delete_qr_codedit au modèle de préférer la pause quand une impression existe. - Les documents de découverte vivent à
/.well-known/oauth-authorization-serveret/.well-known/oauth-protected-resource; l'enregistrement est RFC 7591 ; PKCE S256 uniquement.
SDK et spécification OpenAPI
- TypeScript / JavaScript :
npm install qrflow(npm). Zéro dépendance, ESM et CommonJS, types complets ; fonctionne dans Node 18+, Bun, Deno et Workers. Réessaie les 429 pour vous et fournitverifyWebhook/parseWebhook. - Python 3.9+, bibliothèque standard uniquement : qrflow.py.
- OpenAPI 3.1 : /api/v1/openapi.json. Importez dans Postman ou Insomnia, générez un client dans n'importe quel langage, ou attachez-le à une Action ChatGPT.
- Les deux clients lèvent une erreur typée (
QRFlowErroravecstatus,code,message,retryAfter) et fournissent un vérificateur de webhook. La source TypeScript en un seul fichier est toujours à /sdk/qrflow.ts si vous préférez la vendre.
| TypeScript | Python | Appels |
|---|---|---|
| me() | me() | GET /me |
| catalog() | catalog() | GET /catalog |
| listCodes({ limit, q }) | list_codes(limit, q) | GET /codes |
| getCode(id) | get_code(id) | GET /codes/:id |
| createCode(input) | create_code(**fields) | POST /codes |
| updateCode(id, patch) | update_code(id, **patch) | PATCH /codes/:id |
| deleteCode(id) | delete_code(id) | DELETE /codes/:id |
| makeDynamic(id) | make_dynamic(id) | POST /codes/:id/dynamic |
| scans(id, { from, to, group }) | scans(id, from_, to, group) | GET /codes/:id/scans |
| bulkCreate(rows, colors) | bulk_create(rows, **colors) | POST /codes/bulk |
| domains() | domains() | GET /domains |
| listWebhooks() / createWebhook() / testWebhook(id) / deleteWebhook(id) | list_webhooks() / create_webhook() / test_webhook(id) / delete_webhook(id) | /webhooks |
| imageUrl(id, size) | image_url(id, size) | L'adresse de l'image (récupérez-la avec la clé) |
| verifyWebhook(raw, header, secret) | verify_webhook(raw, header, secret) | Vérification de signature pour les livraisons |
Référence des points de terminaison
Base URL https://qrflow.codes/api/v1. Les corps et les réponses sont en JSON. Les dates sont au format ISO 8601 en UTC. N'envoyez que les champs qui changent lors d'un PATCH.
GETprofile
Le plan, les indicateurs de fonctionnalités et les limites applicables à ce compte, ainsi que les portées de la clé.
curl https://qrflow.codes/api/v1/me \
-H "Authorization: Bearer $QRFLOW_KEY"
{ "id": "…", "email": "ops@example.com", "plan": "business", "paid": true,
"features": { "dynamic_codes": true, "custom_domain": true, "link_names": true, "gs1": true, "api_keys": true },
"limits": { "saved_codes": 25000, "bulk_per_month": 10000, "bulk_per_request": 2000, "link_domains": 5, "requests_per_minute": 600 },
"auth": "api_key", "scopes": ["codes:read", "codes:write"] }
GETpublic
Types natifs (url, wifi, vcard, email, phone, sms, text, location) et la cinquantaine de sous-types (Instagram, avis Google, Wi-Fi, app store…), chacun avec les champs dont il a besoin et le plan requis. Aucune clé nécessaire.
curl https://qrflow.codes/api/v1/catalog
GETcodes:read
Les plus récents en premier. ?limit= jusqu'à 100, ?q= recherche dans les libellés.
curl "https://qrflow.codes/api/v1/codes?limit=20&q=menu" \
-H "Authorization: Bearer $QRFLOW_KEY"
POSTcodes:write
Mêmes règles que « Enregistrer » sur le site : les codes url, phone, email, sms et location sont dynamiques sur les plans payants ; Wi-Fi, vCard et text contiennent leur contenu dans le motif. Mettez un identifiant de sous-type dans destination_data.subtype pour créer, par exemple, un code d'avis Google. Un domain_id facultatif choisit avec lequel de vos domaines de liens le code s'imprime (GET /domains les liste).
curl -X POST https://qrflow.codes/api/v1/codes \
-H "Authorization: Bearer $QRFLOW_KEY" \
-H "Content-Type: application/json" \
-d '{ "type": "url", "destination_data": { "url": "https://example.com/menu" }, "label": "Table tents", "frame_style": "caption-below", "frame_caption": "Scan for menu" }'
{ "code": { "id": "…", "label": "Table tents", "kind": "url", "dynamic": true, "short_code": "x7k2p9a",
"short_url": "https://go.example.com/x7k2p9a", "scans": 0, "image_url": "https://qrflow.codes/api/v1/codes/…/image.svg", … } }
GETcodes:read
Le code avec son nombre de scans, son lien court et son adresse d'image.
curl https://qrflow.codes/api/v1/codes/$ID \
-H "Authorization: Bearer $QRFLOW_KEY"
PATCHcodes:write
N'importe lequel de : destination_data (codes dynamiques uniquement, l'impression reste valide), label, paused, expires_at (ISO ou null), slug (un nom de lien sur votre domaine), domain_id (avec lequel de vos domaines de liens ce code s'imprime ; null = le défaut du compte), fg_color, bg_color, frame_style, frame_caption, frame_caption2. N'envoyez que les champs que vous modifiez.
curl -X PATCH https://qrflow.codes/api/v1/codes/$ID \
-H "Authorization: Bearer $QRFLOW_KEY" \
-H "Content-Type: application/json" \
-d '{ "destination_data": { "url": "https://example.com/menu-fall" }, "slug": "menu" }'
DELETEcodes:write
Supprimé définitivement, y compris son historique de scans. Le lien imprimé d'un code dynamique cesse de résoudre. Privilégiez paused: true si l'impression est encore en circulation.
curl -X DELETE https://qrflow.codes/api/v1/codes/$ID \
-H "Authorization: Bearer $QRFLOW_KEY"
204 No Content
POSTcodes:write
Le motif imprimé change (il encode désormais le lien court), donc ré-rendez l'image ensuite.
curl -X POST https://qrflow.codes/api/v1/codes/$ID/dynamic \
-H "Authorization: Bearer $QRFLOW_KEY"
GETcodes:read
SVG prêt à imprimer avec le cadre et les couleurs. ?size= définit la largeur de la grille de modules en px ; le fichier se redimensionne sans perte de toute façon.
curl https://qrflow.codes/api/v1/codes/$ID/image.svg \
-H "Authorization: Bearer $QRFLOW_KEY" -o code.svg
GETanalytics:read
?from= et ?to= (dates ISO, jusqu'à 92 jours, par défaut les 30 derniers) et ?group= day, device, country, city, browser, os ou referrer. Les mêmes chiffres que la page d'analytique.
curl "https://qrflow.codes/api/v1/codes/$ID/scans?from=2026-09-01&to=2026-09-21&group=day" \
-H "Authorization: Bearer $QRFLOW_KEY"
{ "code_id": "…", "from": "…", "to": "…", "group": "day", "total": 412,
"rows": [ { "key": "2026-09-01", "scans": 18 }, { "key": "2026-09-02", "scans": 25 }, … ] }
POSTcodes:write
Jusqu'à 2 000 codes URL en un seul appel, tous dynamiques. Compte dans la même allocation mensuelle en masse que la page Bulk (10 000 sur Business). Les lignes qui ne sont pas des adresses web reviennent dans rejected ; le reste est créé.
curl -X POST https://qrflow.codes/api/v1/codes/bulk \
-H "Authorization: Bearer $QRFLOW_KEY" \
-H "Content-Type: application/json" \
-d '{ "rows": [ { "destination": "https://example.com/t/1", "label": "Table 1" }, { "destination": "https://example.com/t/2", "label": "Table 2" } ] }'
{ "codes": [ … ], "rejected": [], "remaining_this_month": 9998 }
GETdomains:read
Vos domaines connectés, leur statut, et celui avec lequel les codes dynamiques s'impriment par défaut (default_base). Passez l'identifiant d'un domaine comme domain_id sur un code pour l'imprimer avec un autre.
curl https://qrflow.codes/api/v1/domains \
-H "Authorization: Bearer $QRFLOW_KEY"
GETwebhooks:manage
Vos webhooks avec leurs événements, dernier statut et nombre d'échecs.
curl https://qrflow.codes/api/v1/webhooks \
-H "Authorization: Bearer $QRFLOW_KEY"
POSTwebhooks:manage
url doit être en https sur un hôte public ; events est l'un de scan, code.created, code.updated, code.deleted. Le secret de signature est renvoyé une seule fois.
curl -X POST https://qrflow.codes/api/v1/webhooks \
-H "Authorization: Bearer $QRFLOW_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://example.com/hooks/qrflow", "events": ["scan", "code.updated"] }'
{ "webhook": { "id": "…", "url": "…", "events": ["scan", "code.updated"], "active": true, "secret": "whsec_…" } }
POSTwebhooks:manage
Envoie un ping signé maintenant et rapporte la réponse.
curl -X POST https://qrflow.codes/api/v1/webhooks/$WEBHOOK_ID \
-H "Authorization: Bearer $QRFLOW_KEY"
DELETEwebhooks:manage
Arrête toutes les livraisons, y compris les nouvelles tentatives en file d'attente.
curl -X DELETE https://qrflow.codes/api/v1/webhooks/$WEBHOOK_ID \
-H "Authorization: Bearer $QRFLOW_KEY"
204 No Content
GETpublic
Identifiants de cadres et ce dont chacun a besoin (légende, deuxième ligne), groupés comme le personnalisateur. Aucune clé nécessaire.
curl https://qrflow.codes/api/v1/frames
L'objet Code
Chaque endpoint qui touche un code renvoie la même forme. Ignorez les champs que vous ne connaissez pas ; de nouveaux sont ajoutés au fil du temps.
| Champ | Type | Signification |
|---|---|---|
| id | uuid | Identifiant stable. Utilisez-le dans chaque autre appel. |
| label | string | null | Le nom dans le tableau de bord. Jusqu'à 120 caractères. Recherchable avec ?q=. |
| kind | string | L'identifiant du catalogue : url, wifi, instagram, googlereview,... kind_label est le nom lisible. |
| type | string | L'encodage : url, text, wifi, vcard, email, phone, sms, location. |
| destination_data | objet | Les champs que vous avez envoyés (plus subtype pour les kinds). destination est un résumé sur une ligne de celui-ci. |
| dynamic | booléen | Vrai lorsque les scans passent par QRFLOW et que la destination peut changer. dynamic_capable indique si ce type pourrait être dynamique sur un plan payant. |
| short_code | string | Sept caractères, ne change jamais. |
| short_url | string | Ce qu'il faut imprimer pour un code dynamique. Inclut votre domaine et slug lorsqu'ils sont définis. |
| domain_id | uuid | null | Avec quel domaine de liens ce code s'imprime ; null signifie le défaut du compte. |
| fg_color, bg_color | hex | Couleurs des modules et de l'arrière-plan. |
| has_logo | booléen | Un logo a été ajouté dans le tableau de bord ; image.svg l'inclut. |
| frame_style, frame_caption, frame_caption2 | string | null | Identifiant du cadre et légendes, comme dans le personnalisateur. |
| scans | entier | Nombre de scans à vie. |
| created_at, updated_at | ISO 8601 | UTC. |
| manage_url | url | La page du code dans le tableau de bord, pour un lien « Ouvrir dans QRFLOW ». |
| image_url | url | GET /codes/:id/image.svg. Nécessite l'en-tête Authorization ; ce n'est pas une URL d'image publique. |
| svg_download_url, png_download_url | url | Le même SVG (cadre, couleurs, logo) et un PNG simple via des liens signés qui fonctionnent pendant 24 heures sans en-tête : pour les balises <img>, les scripts et les assistants qui enregistrent un fichier. download_expires_at indique quand ils expirent ; toute lecture du code renvoie de nouveaux liens. |
Autres formes : Scans (code_id, from, to, group, total, rows[key, scans]), Domain (id, host, status, active, is_default, verified_at, grace_until), Webhook (id, url, events, active, last_status, last_delivery_at, consecutive_failures, plus secret une fois), Me (id, email, plan, paid, features, limits, auth, scopes) et Error (error, message). Le document OpenAPI a chaque propriété typée.
Business
Webhooks
QRFLOW appelle votre URL https lorsqu'un événement se produit. Créez-en un sur Compte › Webhooks ou avec POST /webhooks ; vous obtenez le secret de signature une seule fois. Jusqu'à 10 par compte.
| Événement | Quand | données |
|---|---|---|
| scan | Par lots : toutes les quelques minutes, tous les nouveaux scans depuis la dernière livraison, jusqu'à 500 par appel. | count, from, to, scans[] avec code_id, label, short_code, slug, scanned_at, device, country, city, referrer, browser, os, language |
| code.created | Immédiatement depuis l'API et les assistants ; en quelques minutes depuis le tableau de bord. Une demande en masse envoie un événement avec bulk: true et codes[]. | code, source |
| code.updated | Même timing. Couvre la destination, le libellé, la pause, l'expiration, le nom de lien, le domaine, les couleurs, le cadre et la conversion en dynamique. | code, changed[] (les noms des champs qui ont changé) |
| code.deleted | Même timing. | code: { id, label, short_code, slug } |
| ping | Lorsque vous appuyez sur Test. | webhook_id, message |
Ce qui arrive
Chaque charge utile est { id, event, created_at, data }. id est stable entre les nouvelles tentatives d'une même livraison, vous pouvez donc dédupliquer dessus.
{
"id": "9b1c6d2e-…",
"event": "scan",
"created_at": "2026-09-21T18:05:00.000Z",
"data": {
"count": 2,
"from": "2026-09-21T18:00:00.000Z",
"to": "2026-09-21T18:04:12.331Z",
"scans": [
{ "code_id": "…", "label": "Table tents", "short_code": "x7k2p9a", "slug": "menu", "scanned_at": "2026-09-21T18:03:40.101Z",
"device": "mobile", "country": "US", "city": "Las Vegas", "referrer": null, "browser": "Safari", "os": "iOS", "language": "en-US" },
{ "code_id": "…", "label": "Table tents", "short_code": "x7k2p9a", "slug": "menu", "scanned_at": "2026-09-21T18:04:12.331Z",
"device": "mobile", "country": "MX", "city": "Tijuana", "referrer": null, "browser": "Chrome", "os": "Android", "language": "es-MX" }
]
}
}
{
"id": "2f0a…",
"event": "code.updated",
"created_at": "2026-09-21T18:06:00.000Z",
"data": {
"code": { "id": "…", "label": "Table tents", "kind": "url", "dynamic": true, "short_url": "https://go.example.com/menu", "scans": 412, "…": "…" },
"changed": ["destination_data"]
}
}
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: QRFLOW-Webhooks/1.0 (+https://qrflow.codes/developers)
X-QRFLOW-Event: scan
X-QRFLOW-Signature: t=1758477900,v1=5f1c…e9
Vérifier la signature
X-QRFLOW-Signature: t=<unix seconds>,v1=<hex>. Calculez HMAC-SHA256 sur ${t}.${rawBody} avec votre secret et comparez à v1 en temps constant ; rejetez si t a plus de cinq minutes. Utilisez les octets bruts que vous avez reçus, jamais un objet re-sérialisé. Des récepteurs fonctionnels pour Next.js et Python sont dans les recettes, et les deux SDK incluent l'assistant.
Règles de livraison
- Répondez avec n'importe quel 2xx dans les 8 secondes. Faites le travail après avoir répondu.
- Tout le reste est retenté après 1, 5, 15, 60, 240 et 720 minutes.
- Vingt échecs consécutifs désactivent le webhook et envoient un e-mail au propriétaire du compte. Réactivez-le une fois le récepteur corrigé ; les nouvelles tentatives en file d'attente reprennent.
- Les URL doivent être en https sur un hôte public. localhost, les plages privées et qrflow.codes lui-même sont refusés. Utilisez un tunnel pendant le développement.
- Appuyez sur Test pour recevoir un
pingsigné et voir le statut auquel votre serveur a répondu.
Erreurs
Chaque erreur est { "error": "<code>", "message": "<what to do>" } avec le statut ci-dessous. Le message est écrit pour une personne ; affichez-le.
| Statut | error | Signification |
|---|
Symptôme, cause, correctif
Dépannage
401 invalid_token sur chaque appel
PourquoiL'en-tête est incorrect ou la clé n'est pas active.
CorrectifEnvoyez exactement Authorization: Bearer qrf_live_… (un espace, pas deux-points). Vérifiez que la clé n'a pas été révoquée sur Compte › Clés API. Si vous l'avez copiée depuis un chat ou un document, surveillez un point final ou une guillemet intelligente.
401 sur /api/v1 avec un jeton qui fonctionne sur le serveur MCP
PourquoiLes jetons émis pour https://qrflow.codes/mcp y sont liés.
CorrectifUtilisez une clé API pour REST, ou exécutez un second flux OAuth sans resource= pour obtenir un jeton pour l'API REST.
402 upgrade_required lors de la création d'une clé ou d'un webhook
PourquoiLes deux sont des fonctionnalités Business.
CorrectifPassez à un plan supérieur sur /pricing, ou utilisez le serveur MCP, qui fonctionne sur tous les plans via la connexion.
402 sur POST /codes depuis une application OAuth
PourquoiLe plan de l'utilisateur n'inclut pas ce que l'application a demandé (un code dynamique, un domaine).
CorrectifLisez d'abord les fonctionnalités GET /me et adaptez : créez le code quand même (il sera statique sur Free) ou dites à l'utilisateur ce dont le plan a besoin.
403 insufficient_scope
PourquoiLes portées sont fixées lors de la création d'une clé.
CorrectifCréez une nouvelle clé avec les portées dont vous avez besoin et révoquez l'ancienne. Pour OAuth, demandez la portée dans la demande d'autorisation.
400 not_dynamic lorsque je PATCH destination_data
PourquoiLe code est statique : créé sur Free, ou un type Wi-Fi/vCard/text.
CorrectifPour url/phone/email/sms/location sur un plan payant, POST /codes/:id/dynamic, puis re-téléchargez et ré-imprimez (l'image change). Wi-Fi, vCard et text ne peuvent jamais être dynamiques ; créez plutôt un code url qui ouvre une page.
400 no_domain lorsque je définis slug
PourquoiLes noms de liens vivent sur votre domaine.
CorrectifConnectez et vérifiez un domaine sur la page Compte d'abord. Sur qrflow.codes/q, le chemin est toujours le short_code.
409 conflict sur slug
PourquoiUn autre de vos codes a ce nom.
CorrectifGET /codes?q= pour le trouver, ou choisissez un autre nom. Les noms sont par compte, pas globaux.
Erreur CORS dans la console du navigateur
PourquoiL'API n'accepte que les appels serveur-à-serveur (et Canva). C'est délibéré : une clé dans une page web est une clé divulguée.
CorrectifDéplacez l'appel dans un gestionnaire de route, une action serveur, une fonction edge ou un backend et appelez-le depuis la page.
L'image montre un filigrane QRFLOW
PourquoiLe compte est sur le plan Free.
CorrectifLes plans payants le suppriment. Free est destiné au générateur du site lui-même.
short_url indique toujours qrflow.codes/q/… après avoir ajouté mon domaine
PourquoiLe domaine n'est pas encore vérifié, ou son CNAME est incorrect.
CorrectifVérifiez le statut sur la page Compte ou GET /domains (le statut doit être verified). Les codes existants basculent automatiquement une fois qu'il l'est.
image_url donne 401 dans une balise <img>
PourquoiElle nécessite l'en-tête Authorization, qu'une <img> ne peut pas envoyer.
CorrectifUtilisez svg_download_url ou png_download_url du même objet Code : des liens signés qui fonctionnent pendant 24 heures sans en-tête. Pour quelque chose de permanent, proxiez image_url via votre serveur (voir la recette Next.js) ou encodez short_url vous-même.
J'ai besoin d'un PNG, pas d'un SVG
PourquoiLe SVG porte le cadre et le logo ; le PNG est le code simple.
CorrectifGET /codes/:id/image.png (bearer ou le png_download_url signé) renvoie un PNG, de 256 à 2048 px. Pour un PNG avec le cadre, convertissez le SVG avec sharp ou resvg (sharp(svgBuffer).png().toBuffer()).
Mon assistant a dit que l'endpoint d'image l'a refusé et a dessiné le code lui-même
PourquoiIl a récupéré image_url, qui nécessite un bearer.
CorrectifChaque code porte désormais png_download_url et svg_download_url, et get_qr_image les renvoie ; l'assistant peut les récupérer avec curl sans connexion. Un code dessiné localement qui encode le même short_url fonctionne toujours et compte toujours les scans, mais il manque le cadre et le logo.
Le webhook n'arrive jamais
PourquoiRègles d'URL ou récepteur.
CorrectifL'URL doit être en https sur un hôte public (pas de localhost, pas d'IP privées, pas qrflow.codes). Appuyez sur Test sur le webhook : le résultat montre le statut auquel votre serveur a répondu. Les événements de scan sont par lots et peuvent prendre jusqu'à environ cinq minutes ; les événements code.* du tableau de bord sont également mis en file d'attente pendant quelques minutes, tandis que les écritures API et MCP livrent immédiatement.
La signature ne se vérifie jamais
PourquoiVous avez signé un corps re-sérialisé.
FixVerify par rapport aux octets bruts exacts que vous avez reçus, avant l'analyse JSON. Dans Express, utilisez express.raw({ type: 'application/json' }) sur cette route ; dans Next.js App Router, utilisez await req.text() ; dans Flask, request.get_data(). Calculez ensuite HMAC-SHA256 de ${t}.${raw}\.
Le webhook s'est désactivé tout seul
PourquoiVingt échecs consécutifs.
CorrectifCorrigez le récepteur, puis réactivez-le (Compte › Webhooks, ou supprimez et recréez). Vous avez reçu un e-mail lorsque cela s'est produit. Les nouvelles tentatives en file d'attente reprennent.
Livraisons de webhooks en double
PourquoiUn 2xx lent (plus de 8 secondes) compte comme un échec et est retenté.
CorrectifRépondez d'abord, traitez ensuite. Dédupliquez sur l'id du payload, qui est stable entre les nouvelles tentatives.
429 rate_limited pendant une importation
Pourquoi600 requêtes par minute et par clé.
CorrectifUtilisez POST /codes/bulk (2 000 codes en une seule requête) au lieu d'un POST par code, ou attendez Retry-After secondes.
J'ai supprimé un code et l'affiche imprimée affiche maintenant « Code not found »
PourquoiLa suppression est définitive et tue le lien.
CorrectifIl n'y a pas d'annulation. La prochaine fois, utilisez PATCH { paused: true } ; un code en pause affiche une page conviviale et peut être repris.
Ma clé a cessé de fonctionner après ma rétrogradation
PourquoiLes clés continuent de fonctionner 30 jours après avoir quitté Business, puis répondent 402.
CorrectifRéabonnez-vous ; rien n'a été supprimé et les mêmes clés fonctionnent à nouveau.
Quelque chose ne figure pas dans la liste ? hello@qrflow.codes, avec la requête exacte et l'erreur JSON que vous avez reçue. Les comptes Business bénéficient d'une priorité.
Limites et usage raisonnable
| Limite | |
|---|---|
| Requêtes par minute, par clé | 600. 429 avec Retry-After au-delà. |
| Clés par compte | 10 |
| Webhooks par compte | 10 |
| Codes enregistrés (usage raisonnable) | 1 000 Premium, 25 000 Business ; l'API s'arrête au double. |
| En masse | 500/mois (500 par requête) Premium ; 10 000/mois (2 000 par requête) Business. |
| Domaines de liens | 1 Premium, 5 Business |
| Scans | Illimités. Un e-mail de vérification à 100 000 scans par code et par mois sur Premium, 1 000 000 sur Business ; rien n'est limité. |
| Fenêtre d'analyse des scans | 92 jours par requête |
| Taille de page de liste | 100 (?limit=) |
| Libellé / légendes / slug | 120 / 60 / 40 caractères |
| Délai d'expiration et nouvelles tentatives du webhook | 8 secondes ; nouvelles tentatives après 1, 5, 15, 60, 240 et 720 minutes ; arrêt après 20 échecs consécutifs. |
| Après avoir quitté Business | Les clés et les webhooks continuent de fonctionner 30 jours, puis 402. Rien n'est supprimé. |
L'usage raisonnable est ce pour quoi le plan est tarifé. Rien n'est limité au nombre ; l'API s'arrête au double et une personne vous contacte par e-mail en premier. Volumes plus élevés : hello@qrflow.codes.
Sécurité, pour vous et pour les personnes qui scannent
Comment QRFLOW protège votre compte
- Les clés sont affichées une fois et stockées sous forme de hachages SHA-256. Personne chez QRFLOW ne peut relire une clé ; si vous la perdez, créez-en une nouvelle.
- Chaque requête est limitée au compte auquel appartient la clé. Un id de code d'un autre compte est une 404, jamais une fuite.
- Les portées sont fixes par clé, donc une clé pour un tableau de bord de rapport ne peut pas créer ou supprimer des codes.
- 600 requêtes par minute et par clé ; au-delà, c'est un 429 propre, pas un ralentissement pour tout le monde.
- Les destinations sont sur liste blanche : http, https, mailto, tel, sms, geo et une courte liste de schémas d'applications (whatsapp, tg, signal, spotify, magasins d'applications). javascript:, data: et file: sont rejetés à la création, donc une intégration compromise ne peut pas transformer vos codes en attaque.
- Les URL de webhook doivent être en https sur des hôtes publics ; QRFLOW n'appelle jamais les réseaux privés ni lui-même. Chaque livraison est signée et chaque payload a un id stable.
- Les clients OAuth s'enregistrent avec PKCE S256 et les jetons sont liés au serveur pour lequel ils ont été émis ; un jeton pour le serveur MCP ne peut pas être rejoué sur l'API REST.
- N'importe qui peut révoquer une clé ou déconnecter une application sur la page Compte ; l'effet est immédiat.
Ce qu'il faut faire de votre côté
- Variables d'environnement, jamais de code source. Si une clé se retrouve dans un historique git, révoquez-la.
- Côté serveur uniquement. L'API refuse les origines de navigateur, mais vos propres points de terminaison qui l'enveloppent ont aussi besoin d'authentification, sinon n'importe qui peut créer des codes à votre charge.
- Donnez à chaque intégration sa propre clé avec les portées dont elle a besoin, nommée d'après l'intégration. Révoquer une clé n'affecte alors qu'une seule chose.
- Vérifiez les signatures des webhooks et rejetez les horodatages de plus de cinq minutes.
- Si les données de vos utilisateurs vont dans des libellés ou des destinations, rappelez-vous que QRFLOW les stocke ; évitez les données personnelles dans les libellés lorsque c'est possible.
Ce que les scans enregistrent, et ce qu'ils n'enregistrent pas
- Chaque redirection stocke le type d'appareil, le pays, la ville, le référent, le navigateur, le système d'exploitation et la langue, dérivés de la requête, et un hachage à sens unique de code + jour + IP + agent utilisateur pour que le propriétaire puisse compter les visiteurs uniques. Le hachage ne peut pas être reconverti en adresse.
- Aucun cookie n'est défini sur la personne qui scanne et l'adresse IP elle-même n'est pas conservée avec le scan. Les bots connus et les robots d'aperçu de liens sont ignorés.
- La suppression d'un code supprime ses scans. La suppression du compte supprime tout.
- Texte intégral : https://qrflow.codes/privacy et https://qrflow.codes/terms.
Versioning et stabilité
L'API est versionnée dans le chemin : /api/v1. Dans v1, nous ajoutons des champs, des points de terminaison, des types et des événements ; nous ne supprimons ni ne renommons rien, et les champs inconnus dans les réponses doivent être ignorés par votre code.
Si un changement doit un jour casser v1, il est publié en tant que /api/v2 et v1 continue de fonctionner pendant au moins douze mois. Les propriétaires de clés sont informés par e-mail des dépréciations 90 jours à l'avance.
Le serveur MCP suit la même règle pour ses outils : les arguments sont uniquement ajoutés, et chaque outil conserve son nom.
Le document OpenAPI à /api/v1/openapi.json et le Markdown à /llms-full.txt sont générés à partir du code qui sert l'API, ils décrivent donc ce qui est en ligne aujourd'hui.
Questions que se posent les développeurs
Dois-je payer pour utiliser l'API QRFLOW ?
Les clés API sont incluses dans le plan Business, 29 $ par mois, au mois. Le serveur MCP (Claude, ChatGPT, Cursor, Claude Code) et OAuth pour votre propre application fonctionnent sur tous les plans via la connexion, et ce qu'ils peuvent créer suit le plan. GET /catalog, GET /frames et /preview.svg ne nécessitent aucune clé du tout.
Puis-je générer des codes QR gratuitement via l'API ?
Pas avec une clé. Pour une image statique simple, le générateur gratuit à qrflow.codes ou toute bibliothèque QR open source fait le travail. L'API est pour les codes dynamiques, votre propre domaine, les analyses, le volume et les webhooks, ce qui correspond à un compte payant.
Puis-je appeler l'API depuis le navigateur ?
Non. Elle refuse les origines de navigateur afin qu'une clé ne puisse jamais se retrouver dans une page web. Appelez-la depuis un gestionnaire de route, une action serveur, une fonction edge ou un backend, et appelez cela depuis votre page.
Quels formats d'image puis-je obtenir ?
SVG avec vos couleurs, cadre, légendes et logo (GET /codes/:id/image.svg, 256 à 4096 px nominaux) et un PNG simple (GET /codes/:id/image.png, 256 à 2048 px). Les deux acceptent un bearer, ou l'url svg_download_url / png_download_url signée que chaque objet Code porte, qui fonctionnent pendant 24 heures sans en-tête. L'outil MCP get_qr_image renvoie le PNG en ligne plus les deux liens.
Puis-je modifier un code QR après son impression ?
Oui, s'il est dynamique (url, téléphone, e-mail, sms, emplacement sur un plan payant). PATCH /codes/:id avec un nouveau destination_data ; l'image ne change pas, le prochain scan va au nouvel endroit. Les codes Wi-Fi, vCard et texte portent leur contenu dans l'image et ne peuvent pas changer.
Quelle est la différence entre short_url et la destination ?
short_url est le lien dans l'image (go.example.com/menu). La destination est l'endroit où ce lien redirige (https://example.com/menu-fall). Vous imprimez short_url une fois et changez la destination aussi souvent que vous le souhaitez.
Les codes peuvent-ils utiliser mon propre domaine ?
Oui. Premium connecte 1 domaine, Business 5 ; vous ajoutez un CNAME et vérifiez sur la page Compte. Business choisit un domaine par code avec domain_id. Les noms de liens (slug) créent des chemins lisibles dessus.
Qu'enregistre un scan sur la personne qui scanne ?
Type d'appareil, pays, ville, référent, navigateur, système d'exploitation et langue, à partir de la requête, plus un hachage quotidien à sens unique pour les comptages de visiteurs uniques. Pas de cookies, et l'adresse IP n'est pas stockée. Assez pour un graphique, pas assez pour identifier quelqu'un. Détails : https://qrflow.codes/privacy#scans
Existe-t-il un package npm ou PyPI ?
npm : npm install qrflow\ (https://www.npmjs.com/package/qrflow), zéro dépendance, ESM et CommonJS, types TypeScript complets, fonctionne sur Node 18+, Bun, Deno et Workers ; il enveloppe chaque point de terminaison, réessaie les 429, et inclut verifyWebhook/parseWebhook. Python : un client à fichier unique à https://qrflow.codes/sdk/qrflow.py (bibliothèque standard uniquement) avec verify_webhook ; un package PyPI suivra.
Cela fonctionne-t-il avec Claude, ChatGPT, Cursor et Claude Code ?
Oui. QRFLOW est un serveur MCP à https://qrflow.codes/mcp. Ajoutez-le comme connecteur, connectez-vous une fois, et demandez en langage naturel. Onze outils couvrent la création, l'édition, la pause, la nomination, le volume, les analyses, les images et les domaines.
Mes propres utilisateurs peuvent-ils connecter leurs comptes QRFLOW à mon application ?
Oui, avec OAuth 2.0. Enregistrez un client à /api/oauth/register (aucun compte requis), envoyez les utilisateurs à /oauth/authorize avec PKCE, et appelez l'API avec leur jeton. Les codes arrivent dans leur compte sous leur plan.
Comment tester les webhooks sur localhost ?
Exposez votre serveur de développement avec un tunnel (cloudflared ou ngrok) et utilisez son adresse https comme URL de webhook, puis appuyez sur Test dans Compte › Webhooks pour recevoir un ping signé. Les URL de webhook doivent être en https public ; localhost et les adresses privées sont refusées.
Que se passe-t-il pour mon intégration si j'annule Business ?
Les clés et les webhooks continuent de fonctionner pendant 30 jours, puis répondent 402. Les codes, les scans et les domaines restent dans le compte. Le réabonnement réactive tout avec les mêmes clés.
Comment créer un code Google review, Instagram, Wi-Fi ou PDF via l'API ?
GET /catalog liste chaque type avec ses champs. Ensuite, POST /codes avec le type et les champs du type, en ajoutant subtype pour les types : { type: 'url', destination_data: { subtype: 'googlereview', placeId: 'ChIJ…' } }, { type: 'wifi', destination_data: { ssid, password, encryption: 'WPA' } }, { type: 'url', destination_data: { subtype: 'instagram', handle: 'acme' } }.
L'API peut-elle télécharger un logo sur un code ?
Pas encore. Ajoutez le logo dans le tableau de bord ; image.svg l'inclut et has_logo vous indique qu'il est là. Les couleurs, les cadres et les légendes sont tous configurables via l'API.
L'API est-elle stable ?
v1 ne fait qu'ajouter ; elle ne supprime ni ne renomme jamais. Un changement cassant serait publié en v2 avec v1 maintenue pendant au moins douze mois et un préavis de 90 jours par e-mail.
Pour les agents, les outils et les assistants qui lisent ceci
Lisible par machine
Tout sur cette page existe sous une forme que les logiciels peuvent récupérer. Tout est généré à partir du code qui sert l'API, donc ce n'est jamais obsolète.
| URL | Ce que c'est | |
|---|---|---|
| llms-full.txt | https://qrflow.codes/llms-full.txt | L'intégralité de cette référence au format Markdown : concepts, chaque endpoint, chaque outil MCP, recettes, dépannage, FAQ. Générée à partir de la même source que cette page. |
| developers.md | https://qrflow.codes/developers.md | Le même document, pour les outils qui récupèrent un fichier .md. |
| llms.txt | https://qrflow.codes/llms.txt | L'index du site pour les assistants, pointant ici. |
| L'API en une page | https://qrflow.codes/qr-code-api | Ce que fait l'API, quand une bibliothèque côté client est la meilleure réponse, et ce que cela coûte. La version courte de cette référence, pour décider plutôt que pour construire. |
| openapi.json | https://qrflow.codes/api/v1/openapi.json | OpenAPI 3.1. Importez-le dans Postman, Insomnia, un générateur de code ou une Action ChatGPT. |
| Serveur MCP | https://qrflow.codes/mcp | HTTP streamable, OAuth avec enregistrement dynamique ou clé Business comme bearer. |
| server.json | https://qrflow.codes/.well-known/mcp/server.json | Le manifeste du registre MCP. |
| Découverte OAuth | https://qrflow.codes/.well-known/oauth-authorization-server | Métadonnées RFC 8414 ; le document de ressource protégée se trouve à côté. |
| Paquet npm | https://www.npmjs.com/package/qrflow | npm install qrflow. Client typé, zéro dépendance, vérification de webhook. Client Python mono-fichier à https://qrflow.codes/sdk/qrflow.py. |
| GitHub | https://github.com/nativecodeapps/qrflow-sdk | Clients, instantané OpenAPI et exemples exécutables pour les webhooks Next.js, Workers, Express, FastAPI et Flask. Les problèmes et les demandes de tirage sont les bienvenus. |
Questions, idées, un type de code que nous devrions ajouter : hello@qrflow.codes. Conditions : /terms. Confidentialité : /privacy.