Referencia de la API
Endpoints, parámetros, códigos de respuesta y ejemplos para integrar el protocolo de verificación de tickets de Praticable.
Esta página cubre el uso práctico de la API. Para comprender cómo funciona el protocolo (criptografía, formato del payload, flujo de verificación), consulte la especificación del protocolo →
Descripción general
La API expone tres endpoints para aplicaciones scanner, servidos por cada instancia issuer.
La URL base es el iss del despliegue del cliente (por ejemplo,
https://tickets.example.com).
Intercambia un token de enrollment por una API key
Marca un ticket como utilizado en la puerta de acceso
Devuelve el estado actual de un ticket sin modificarlo
También hay disponible un endpoint público de descubrimiento en
{iss}/.well-known/ticket-issuer.json (no requiere autenticación).
Su estructura se describe en la
especificación del protocolo.
Autenticación
Los endpoints check-in y status requieren un Bearer token.
La API key se obtiene a través del intercambio de enrollment (más abajo). El endpoint de
enrollment en sí no requiere un Bearer; utiliza el token de enrollment como credencial.
Authorization: Bearer sk_live_01HXXX...long-opaque-key - Cada API key está limitada a un evento (y opcionalmente a una puerta de acceso).
- Las keys expiran en el timestamp
expires_atdevuelto durante el enrollment. - Una key inválida, expirada o revocada devuelve
401 UNAUTHORIZED. - Las keys DEBEN almacenarse en el almacenamiento seguro de la plataforma (Keychain, Keystore).
Registrar scanner
Intercambia un token de enrollment (de un código QR de configuración) por una API key de larga duración.
El token es de un solo uso: un segundo intento con el mismo token devuelve
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 - North Gate",
"scanner_platform": "ios-18.2"
}' Parámetros del request
Token de enrollment del código QR de configuración. Opaco, ≥ 128 bits de entropía, un solo uso.
Identificador único y estable generado por la aplicación scanner (se recomienda UUID). Se utiliza para la identificación cruzada de enrollments y auditoría.
Nombre legible mostrado en la interfaz de administración (por ejemplo, nombre del dispositivo).
Información de la plataforma para soporte y seguimiento de compatibilidad.
Response · 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"
}
} API key de larga duración. Almacenar en Keychain/Keystore. Nunca registrar en logs, incluir en informes de fallos ni persistir en texto plano.
Identificador de la key, seguro para registrar en logs. Se utiliza para pistas de auditoría.
Alcance de la key: eid, event_name, event_date, gate_id (opcional, null si aplica a todas las puertas), expires_at.
Información del issuer: name (nombre comercial) e iss (URL base).
Errores de enrollment
El token tiene formato incorrecto, ha expirado o ya fue utilizado.
El token fue revocado por el organizador antes de ser utilizado.
El issuer no soporta la versión del protocolo solicitada.
Demasiados intentos de enrollment desde esta IP.
Error del servidor. Reintentar con backoff exponencial.
Check-in
Marca un ticket como utilizado. Idempotente: repetir el mismo request
con la misma idempotency_key devuelve el mismo resultado.
Un segundo request con el mismo tid pero una idempotency_key diferente
se trata como un doble escaneo y devuelve already_used.
Request
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"
}' Identificador del ticket.
Identificador del evento.
Timestamp del escaneo (ISO 8601 UTC). El issuer DEBE aceptar timestamps de hasta 48 horas en el pasado para escaneos offline en cola.
ej. 2026-06-15T19:42:13ZIdentificador único y estable del dispositivo.
Identificador de la puerta de acceso, incluido con fines de auditoría.
UUID v4 por intento de escaneo. Deduplica reintentos. También se puede pasar a través del header Idempotency-Key.
Response · 200 OK
La respuesta siempre es 200 con un campo status que indica
el resultado. Esto permite a los scanners distinguir entre diferentes casos sin analizar
los códigos de status 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"
}
} Valores de status
Ticket válido, check-in realizado. Primer escaneo exitoso.
Ticket ya utilizado. La respuesta incluye el checked_in_at original.
Ticket revocado (reembolso, fraude, etc.).
Ticket válido pero para un evento diferente.
La fecha de expiración del ticket ya ha pasado.
El scanner informa que no se pudo verificar la signature. Se registra para auditoría en el lado del issuer.
Estado del ticket
Devuelve el estado actual de un ticket sin modificarlo. Útil para verificaciones previas del scanner, herramientas de administración o conciliación posterior al evento.
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
} Ticket emitido, no utilizado, no expirado.
Ticket ya utilizado. checked_in_at contiene el timestamp.
Ticket revocado (reembolso, fraude).
La fecha de expiración ya ha pasado.
Si el tid no existe, el issuer devuelve 404 NOT_FOUND.
Idempotencia
El endpoint de check-in utiliza una clave de idempotencia para deduplicar reintentos.
Genere un UUID v4 único por intento de escaneo y páselo en el body
(idempotency_key) o en el header HTTP (Idempotency-Key).
Reintento del mismo escaneo. El servidor devuelve el resultado original (idempotente).
Doble escaneo detectado. El servidor devuelve already_used.
Conflicto de idempotencia. El servidor devuelve 409 IDEMPOTENCY_CONFLICT.
Ante una falla de red, el scanner pone el request en cola con su
idempotency_key y acepta el ticket de forma optimista. Cuando
se restablece la conectividad, los requests en cola se envían. La idempotencia
del lado del issuer garantiza que no haya inconsistencias. Consulte la
especificación del modo offline.
Códigos de error
Todas las respuestas no-2xx utilizan un sobre de error estándar:
{
"error": {
"code": "UNAUTHORIZED",
"message": "API key is missing, expired, or revoked.",
"details": {}
}
} Retry-After indica el tiempo de espera. Límites de frecuencia
Los issuers DEBEN aplicar límites de frecuencia en cada endpoint por credencial de scanner.
Cuando se alcanza el límite, el servidor devuelve 429 RATE_LIMITED
con un header Retry-After que indica el número de segundos a esperar.
- Endpoint de enrollment: limitado por IP y por token para prevenir ataques de fuerza bruta.
- Endpoint de check-in: limitado por credencial de scanner.
- Endpoint de status: limitado por credencial de scanner.
Los scanners DEBEN implementar backoff exponencial en respuestas 429
y respetar el valor de Retry-After.