Référence API
Endpoints, paramètres, codes de réponse et exemples pour intégrer le protocole de vérification des billets Praticable.
Cette page couvre l'utilisation pratique de l'API. Pour comprendre le fonctionnement du protocole (cryptographie, format de payload, flux de vérification), consultez la spécification du protocole →
Vue d'ensemble
L'API expose trois endpoints pour les applications scanner, servis par chaque instance issuer.
L'URL de base est l'iss du déploiement client (ex :
https://tickets.example.com).
Échange un token d'enrollment contre une clé API
Marque un billet comme utilisé à l'entrée
Consulte l'état courant d'un billet sans le modifier
Un endpoint de découverte public est aussi disponible à
{iss}/.well-known/ticket-issuer.json (sans authentification).
Sa structure est décrite dans la
spécification du protocole.
Authentification
Les endpoints check-in et status nécessitent un Bearer token.
La clé API est obtenue via l'échange d'enrollment (ci-dessous). L'endpoint
d'enrollment lui-même ne requiert pas de Bearer ; il utilise le token d'enrollment
comme credential.
Authorization: Bearer sk_live_01HXXX...long-opaque-key - Chaque clé API est scopée à un événement (et optionnellement une porte).
- Les clés expirent au timestamp
expires_atretourné lors de l'enrollment. - Une clé invalide, expirée ou révoquée retourne
401 UNAUTHORIZED. - Les clés DOIVENT être stockées dans le stockage sécurisé de la plateforme (Keychain, Keystore).
Enroll scanner
Échange un token d'enrollment (provenant d'un QR de setup) contre une clé API longue durée.
Le token est à usage unique : une seconde tentative avec le même token retourne
INVALID_TOKEN.
curl -X POST https://tickets.example.com/api/v1/scanners/enroll \
-H "Content-Type: application/json" \
-d '{
"token": "st_01HXXX...opaque-enrollment-token",
"scanner_id": "550e8400-e29b-41d4-a716-446655440000",
"scanner_name": "iPhone 14 - Entrée Nord",
"scanner_platform": "ios-18.2"
}' Paramètres de requête
Token d'enrollment du QR de setup. Opaque, ≥ 128 bits d'entropie, usage unique.
Identifiant unique et stable généré par l'app scanner (UUID recommandé). Utilisé pour l'identification cross-enrollment et l'audit.
Nom lisible affiché dans l'interface admin (ex : nom de l'appareil).
Informations de plateforme pour le support et le suivi de compatibilité.
Réponse · 200 OK
{
"api_key": "sk_live_01HXXX...long-opaque-key",
"api_key_id": "sck_01HXXX...ULID",
"scope": {
"eid": "evt_01HXXX...ULID",
"event_name": "Gala Concert",
"event_date": "2026-06-15T20:00:00Z",
"gate_id": "north",
"expires_at": "2026-06-16T02:00:00Z"
},
"issuer": {
"name": "Festival des Arts",
"iss": "https://tickets.example.com"
}
} Clé API longue durée. Stocker dans le Keychain/Keystore. Ne jamais logger, inclure dans les rapports de crash ou persister en clair.
Identifiant de clé, sûr à logger. Utilisé pour les pistes d'audit.
Scope de la clé : eid, event_name, event_date, gate_id (optionnel, null si toutes les portes), expires_at.
Informations de l'issuer : name (nom commercial) et iss (URL de base).
Erreurs d'enrollment
Le token est malformé, expiré ou a déjà été utilisé.
Le token a été révoqué par l'organisateur avant utilisation.
L'issuer ne supporte pas la version de protocole demandée.
Trop de tentatives d'enrollment depuis cette IP.
Erreur serveur. Réessayer avec backoff exponentiel.
Check-in
Marque un billet comme utilisé. Idempotent : rejouer la même requête
avec le même idempotency_key retourne le même résultat.
Une seconde requête avec le même tid mais un idempotency_key
différent est traitée comme double-scan et retourne already_used.
Requête
curl -X POST https://tickets.example.com/api/v1/tickets/check-in \
-H "Authorization: Bearer sk_live_01HXXX..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"tid": "01HXXX...ULID",
"eid": "evt_01HXXX...ULID",
"scanned_at": "2026-06-15T19:42:13Z",
"scanner_id": "gate-north-01",
"gate_id": "north",
"idempotency_key": "550e8400-e29b-41d4-a716-446655440000"
}' Identifiant du billet.
Identifiant de l'événement.
Timestamp du scan (ISO 8601 UTC). L'issuer DOIT accepter des timestamps jusqu'à 48h dans le passé pour les scans hors ligne en file d'attente.
ex : 2026-06-15T19:42:13ZIdentifiant unique et stable de l'appareil.
Identifiant de porte, inclus à des fins d'audit.
UUID v4 par tentative de scan. Déduplique les retries. Peut aussi être passé via l'en-tête Idempotency-Key.
Réponse · 200 OK
La réponse est toujours 200 avec un champ status indiquant
le résultat. Cela permet aux scanners de distinguer les différents cas sans parser
les codes HTTP.
{
"status": "valid",
"ticket": {
"tid": "01HXXX...ULID",
"eid": "evt_01HXXX...ULID",
"holder_name": "J. Smith",
"ticket_type": "VIP",
"checked_in_at": "2026-06-15T19:42:13Z"
}
} {
"status": "already_used",
"ticket": {
"tid": "01HXXX...ULID",
"eid": "evt_01HXXX...ULID",
"holder_name": "J. Smith",
"ticket_type": "VIP",
"checked_in_at": "2026-06-15T19:30:00Z"
}
} Valeurs de statut
Billet valide, check-in effectué. Premier scan réussi.
Billet déjà utilisé. La réponse inclut le checked_in_at original.
Billet révoqué (remboursement, fraude, etc.).
Billet valide mais pour un autre événement.
La date d'expiration du billet est passée.
Le scanner signale que la signature n'a pas pu être vérifiée. Loggé pour audit côté issuer.
Statut du billet
Retourne l'état courant d'un billet sans le modifier. Utile pour les pré-vérifications des scanners, les outils admin ou la réconciliation post-événement.
curl https://tickets.example.com/api/v1/tickets/01HXXX...ULID/status \
-H "Authorization: Bearer sk_live_01HXXX..." {
"tid": "01HXXX...ULID",
"eid": "evt_01HXXX...ULID",
"status": "valid",
"holder_name": "J. Smith",
"ticket_type": "VIP",
"issued_at": "2026-05-01T10:00:00Z",
"checked_in_at": null
} Billet émis, non utilisé, non expiré.
Billet déjà utilisé. checked_in_at contient le timestamp.
Billet révoqué (remboursement, fraude).
La date d'expiration est passée.
Si le tid n'existe pas, l'issuer retourne 404 NOT_FOUND.
Idempotence
L'endpoint de check-in utilise une clé d'idempotence pour dédupliquer les retries.
Générez un UUID v4 unique par tentative de scan et passez-le soit dans le body
(idempotency_key), soit dans l'en-tête HTTP (Idempotency-Key).
Retry du même scan. Le serveur retourne le résultat d'origine (idempotent).
Double-scan détecté. Le serveur retourne already_used.
Conflit d'idempotence. Le serveur retourne 409 IDEMPOTENCY_CONFLICT.
En cas d'échec réseau, le scanner met la requête en file d'attente avec son
idempotency_key et accepte le billet de manière optimiste. Quand la
connexion revient, les requêtes en file sont vidées. L'idempotence de l'issuer
garantit l'absence d'incohérence. Voir la
spécification du mode hors ligne.
Codes d'erreur
Toutes les réponses non-2xx utilisent une enveloppe d'erreur standard :
{
"error": {
"code": "UNAUTHORIZED",
"message": "API key is missing, expired, or revoked.",
"details": {}
}
} Retry-After indique le délai. Rate limiting
Les issuers DOIVENT limiter le débit de chaque endpoint par credential scanner.
Quand la limite est atteinte, le serveur retourne 429 RATE_LIMITED
avec un en-tête Retry-After indiquant le nombre de secondes à attendre.
- Endpoint d'enrollment : rate-limit par IP et par token pour prévenir le brute-force.
- Endpoint de check-in : rate-limit par credential scanner.
- Endpoint de statut : rate-limit par credential scanner.
Les scanners DEVRAIENT implémenter un backoff exponentiel sur les réponses 429
et respecter la valeur de Retry-After.