Authentification
Toutes les requêtes doivent inclure un header Authorization avec votre clé API au format Bearer qft_....
Authorization: Bearer qft_VOTRE_CLE_ICI
Créez et gérez vos clés depuis la page API Keys. Les clés sont affichées une seule fois à la création — conservez-les en lieu sûr.
Rate limits
Les limites sont appliquées par clé API, sur une fenêtre glissante de 1 heure.
| Plan | Requêtes / heure |
|---|---|
| Free | 20 |
| Pro | 100 |
Chaque réponse expose les headers suivants :
X-RateLimit-Limit: 20 X-RateLimit-Remaining: 17 X-RateLimit-Reset: 1768680000
Endpoints
POST /api/v1/qrcodes
Crée un nouveau QR code partagé publiquement. Retourne un shareToken et une shareUrl prête à être affichée.
Body JSON
| Champ | Type | Requis | Description |
|---|---|---|---|
name | string | oui | Max 100 caractères. |
content | string | oui | Contenu encodé (URL, texte, payload vCard…). |
type | enum | non | url, text, wifi, vcard, email, phone, sms, whatsapp, geo, social. Défaut : url. |
foregroundColor | hex | non | Format #RRGGBB. Défaut #1a1410. |
backgroundColor | hex | non | Format #RRGGBB. Défaut #ffffff. |
errorCorrection | L / M / Q / H | non | Défaut M. |
size | integer | non | 128 – 2048 pixels. Défaut 512. |
category | string | non | Libellé libre. |
Exemple curl
curl -X POST https://useqraft.com/api/v1/qrcodes \
-H "Authorization: Bearer qft_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Menu",
"content": "https://menu.example.com",
"type": "url"
}'Réponse 201
{
"id": "clx...",
"name": "Menu",
"type": "url",
"content": "https://menu.example.com",
"shareToken": "b5f2e1d8-...",
"shareUrl": "https://useqraft.com/r/b5f2e1d8-...",
"foregroundColor": "#1a1410",
"backgroundColor": "#ffffff",
"size": 512,
"errorCorrection": "M",
"category": null,
"createdAt": "2026-04-16T10:00:00.000Z",
"expiresAt": "2026-05-16T10:00:00.000Z"
}GET /api/v1/qrcodes/:id
Retourne le QR code. 404 si l'ID n'existe pas ou n'appartient pas à l'utilisateur.
curl https://useqraft.com/api/v1/qrcodes/clx... \ -H "Authorization: Bearer qft_xxx"
{
"id": "clx...",
"name": "Menu",
"type": "url",
"content": "https://menu.example.com",
"shareToken": "b5f2e1d8-...",
"shareUrl": "https://useqraft.com/r/b5f2e1d8-...",
"foregroundColor": "#1a1410",
"backgroundColor": "#ffffff",
"size": 512,
"errorCorrection": "M",
"category": null,
"isPublic": true,
"isFavorite": false,
"scanCount": 42,
"createdAt": "2026-04-16T10:00:00.000Z",
"updatedAt": "2026-04-16T10:00:00.000Z",
"expiresAt": "2026-05-16T10:00:00.000Z"
}GET /api/v1/qrcodes/:id/analytics
Statistiques agrégées des scans. Paramètre optionnel days (1 – 365, défaut 30).
curl "https://useqraft.com/api/v1/qrcodes/clx.../analytics?days=7" \ -H "Authorization: Bearer qft_xxx"
{
"totalScans": 123,
"uniqueCountries": 12,
"uniqueCities": 45,
"byDevice": [{ "device": "mobile", "count": 80 }],
"byBrowser": [{ "browser": "Chrome", "count": 90 }],
"byOs": [{ "os": "iOS", "count": 60 }],
"byCountry": [{ "country": "FR", "count": 70 }],
"timeline": [{ "date": "2026-04-10", "scans": 5 }]
}GET /api/v1/qrcodes/:id/scans
Liste des scans bruts, paginée. Paramètres : limit (max 500, défaut 100) et cursor (ID du dernier scan de la page précédente).
curl "https://useqraft.com/api/v1/qrcodes/clx.../scans?limit=50" \ -H "Authorization: Bearer qft_xxx"
{
"data": [
{
"id": "scn_...",
"qrCodeId": "clx...",
"country": "FR",
"city": "Rennes",
"device": "mobile",
"browser": "Chrome",
"os": "iOS",
"latitude": 48.117,
"longitude": -1.677,
"scannedAt": "2026-04-16T09:55:12.000Z"
}
],
"nextCursor": "scn_previous_last_id"
}Codes d'erreur
| Code | Erreur | Signification |
|---|---|---|
| 400 | validation_error | Payload invalide. |
| 401 | invalid_api_key | Clé manquante, révoquée ou mal formée. |
| 404 | not_found | Ressource inexistante ou n'appartenant pas à l'utilisateur. |
| 429 | rate_limited | Quota horaire dépassé. Attendez X-RateLimit-Reset. |
| 500 | internal_error | Erreur serveur. Réessayez plus tard. |