Documentatie / API-referentie / v1
ProtocolspecificatieAPI-referentieGidsen
Documentatie / API-referentie / v1
STABLE · SINCE V1

API-referentie

Endpoints, parameters, response-codes en voorbeelden voor de integratie van het Praticable ticketverificatieprotocol.

Protocolspecificatie

Deze pagina behandelt het praktische API-gebruik. Om te begrijpen hoe het protocol werkt (cryptografie, payload-formaat, verificatiestroom), raadpleegt u de protocolspecificatie →

§ 01

Overzicht

De API biedt drie endpoints voor scannerapplicaties, aangeboden door elke issuer-instantie. De basis-URL is de iss van de klantimplementatie (bijv. https://tickets.example.com).

Endpoint Beschrijving
POST /api/v1/scanners/enroll

Wisselt een registratietoken in voor een API key

POST /api/v1/tickets/check-in

Markeert een ticket als gebruikt bij de ingang

GET /api/v1/tickets/{tid}/status

Geeft de huidige status van een ticket terug zonder deze te wijzigen

Er is ook een publiek discovery-endpoint beschikbaar op {iss}/.well-known/ticket-issuer.json (geen authenticatie vereist). De structuur hiervan wordt beschreven in de protocolspecificatie.

§ 02

Authenticatie

De endpoints check-in en status vereisen een Bearer token. De API key wordt verkregen via de registratie-uitwisseling (hieronder). Het registratie-endpoint zelf vereist geen Bearer; het gebruikt het registratietoken als credential.

Authentication header
Authorization: Bearer sk_live_01HXXX...long-opaque-key
  • Elke API key is beperkt tot een evenement (en optioneel een ingang).
  • Keys verlopen op het expires_at-tijdstip dat tijdens de registratie wordt teruggegeven.
  • Een ongeldige, verlopen of ingetrokken key retourneert 401 UNAUTHORIZED.
  • Keys MOETEN worden opgeslagen in de beveiligde opslag van het platform (Keychain, Keystore).
§ 03

Scanner registreren

POST /api/v1/scanners/enroll geen Bearer vereist

Wisselt een registratietoken (uit een setup-QR-code) in voor een langdurige API key. Het token is eenmalig: een tweede poging met hetzelfde token retourneert INVALID_TOKEN.

curl
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 - North Gate",
    "scanner_platform": "ios-18.2"
  }'

Request-parameters

Veld Beschrijving
token
stringrequired

Registratietoken uit de setup-QR-code. Ondoorzichtig, ≥ 128 bits entropie, eenmalig gebruik.

scanner_id
stringrequired

Unieke, stabiele identificatie gegenereerd door de scanner-app (UUID aanbevolen). Gebruikt voor cross-registratie-identificatie en auditing.

scanner_name
stringoptional

Leesbare naam weergegeven in de beheerinterface (bijv. apparaatnaam).

scanner_platform
stringoptional

Platforminformatie voor ondersteuning en compatibiliteitsregistratie.

Response · 200 OK

JSON response
{
  "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"
  }
}
Veld Beschrijving
api_key
string

Langdurige API key. Sla op in Keychain/Keystore. Log deze nooit, neem deze niet op in crashrapporten en sla deze niet op als platte tekst.

api_key_id
string

Key-identificatie, veilig om te loggen. Gebruikt voor audittrails.

scope
object

Key-scope: eid, event_name, event_date, gate_id (optioneel, null bij alle ingangen), expires_at.

issuer
object

Issuer-informatie: name (bedrijfsnaam) en iss (basis-URL).

Registratiefouten

Code Betekenis
INVALID_TOKEN
400

Het token is onjuist gevormd, verlopen of al gebruikt.

TOKEN_REVOKED
403

Het token is door de organisator ingetrokken voor gebruik.

PROTOCOL_VERSION_UNSUPPORTED
400

De issuer ondersteunt de gevraagde protocolversie niet.

RATE_LIMITED
429

Te veel registratiepogingen vanaf dit IP-adres.

INTERNAL
500

Serverfout. Probeer opnieuw met exponential backoff.

§ 04

Check-in

POST /api/v1/tickets/check-in Bearer vereist

Markeert een ticket als gebruikt. Idempotent: het herhalen van hetzelfde request met dezelfde idempotency_key retourneert hetzelfde resultaat. Een tweede request met dezelfde tid maar een andere idempotency_key wordt behandeld als een dubbele scan en retourneert already_used.

Request

curl
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"
  }'
Veld Beschrijving
tid
stringrequired

Ticket-identificatie.

eid
stringrequired

Evenement-identificatie.

scanned_at
stringrequired

Scantijdstip (ISO 8601 UTC). De issuer MOET tijdstempels tot 48 uur in het verleden accepteren voor offline scans in de wachtrij.

bijv. 2026-06-15T19:42:13Z
scanner_id
stringrequired

Unieke, stabiele apparaat-identificatie.

gate_id
stringoptional

Ingang-identificatie, opgenomen voor auditdoeleinden.

idempotency_key
stringrequired

UUID v4 per scanpoging. Dedupliceert herhaalpogingen. Kan ook via de Idempotency-Key header worden meegegeven.

Response · 200 OK

De response is altijd 200 met een status-veld dat het resultaat aangeeft. Dit stelt scanners in staat om verschillende gevallen te onderscheiden zonder HTTP-statuscodes te hoeven parsen.

TOEGELATEN 200 · status: valid
{
  "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"
  }
}
GEWEIGERD 200 · status: already_used
{
  "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"
  }
}

Statuswaarden

Status Betekenis
valid
200

Geldig ticket, check-in uitgevoerd. Eerste succesvolle scan.

already_used
200

Ticket al gebruikt. De response bevat het oorspronkelijke checked_in_at-tijdstip.

revoked
200

Ticket ingetrokken (restitutie, fraude, enz.).

wrong_event
200

Geldig ticket, maar voor een ander evenement.

expired
200

De vervaldatum van het ticket is verstreken.

invalid_signature
400

De scanner meldt dat de handtekening niet kon worden geverifieerd. Wordt gelogd voor audit aan de issuerzijde.

§ 05

Ticketstatus

GET /api/v1/tickets/{tid}/status Bearer vereist

Geeft de huidige status van een ticket terug zonder deze te wijzigen. Nuttig voor voorcontroles door scanners, beheertools of afstemming na afloop van een evenement.

curl
curl https://tickets.example.com/api/v1/tickets/01HXXX...ULID/status \
  -H "Authorization: Bearer sk_live_01HXXX..."
Response · 200 OK
{
  "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
}
Status Betekenis
valid

Ticket uitgegeven, niet gebruikt, niet verlopen.

checked_in

Ticket al gebruikt. checked_in_at bevat het tijdstip.

revoked

Ticket ingetrokken (restitutie, fraude).

expired

De vervaldatum is verstreken.

Als de tid niet bestaat, retourneert de issuer 404 NOT_FOUND.

§ 06

Idempotentie

Het check-in endpoint gebruikt een idempotency key om herhaalpogingen te dedupliceren. Genereer een unieke UUID v4 per scanpoging en geef deze mee in de body (idempotency_key) of in de HTTP header (Idempotency-Key).

Zelfde tid + zelfde key

Herhaalde poging van dezelfde scan. De server retourneert het oorspronkelijke resultaat (idempotent).

Zelfde tid + andere key

Dubbele scan gedetecteerd. De server retourneert already_used.

Zelfde key + andere body

Idempotentieconflict. De server retourneert 409 IDEMPOTENCY_CONFLICT.

Offline-modus

Bij een netwerkstoring plaatst de scanner het request met zijn idempotency_key in de wachtrij en accepteert het ticket optimistisch. Wanneer de verbinding hersteld is, worden de requests in de wachtrij verwerkt. Idempotentie aan de issuerzijde garandeert dat er geen inconsistenties ontstaan. Zie de specificatie voor offline-modus.

§ 07

Foutcodes

Alle niet-2xx responses gebruiken een standaard fout-envelope:

Error envelope
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "API key is missing, expired, or revoked.",
    "details": {}
  }
}
Code Type Beschrijving
400 INVALID_REQUEST Ongeldig payload of ontbrekende verplichte velden.
400 INVALID_TOKEN Registratietoken is onjuist gevormd, verlopen of al gebruikt.
400 PROTOCOL_VERSION_UNSUPPORTED De issuer ondersteunt de protocolversie van de payload niet.
401 UNAUTHORIZED API key ontbreekt, is ongeldig, verlopen of ingetrokken.
403 FORBIDDEN Geldige API key maar zonder toestemming voor deze resource.
403 TOKEN_REVOKED Registratietoken door de organisator ingetrokken voor gebruik.
404 NOT_FOUND De gevraagde resource bestaat niet.
409 IDEMPOTENCY_CONFLICT Dezelfde idempotency key gebruikt met een andere payload.
429 RATE_LIMITED Te veel requests. De Retry-After header geeft de wachttijd aan.
500 INTERNAL Serverfout. Probeer opnieuw met exponential backoff.
§ 08

Rate limiting

Issuers MOETEN elk endpoint per scannercredential rate-limiten. Wanneer de limiet is bereikt, retourneert de server 429 RATE_LIMITED met een Retry-After header die het aantal seconden wachttijd aangeeft.

  • Registratie-endpoint: rate-limited op IP-adres en token om brute-force te voorkomen.
  • Check-in endpoint: rate-limited per scannercredential.
  • Status-endpoint: rate-limited per scannercredential.

Scanners ZOUDEN exponential backoff moeten implementeren bij 429 responses en de Retry-After-waarde respecteren.

Laatst bijgewerkt : 20 mei 2026