Documentación / Referencia de la API / v1
Especificación del protocoloReferencia de la APIGuías
Documentación / Referencia de la API / v1
ESTABLE · DESDE V1

Referencia de la API

Endpoints, parámetros, códigos de respuesta y ejemplos para integrar el protocolo de verificación de tickets de Praticable.

Especificación del protocolo

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 →

§ 01

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).

Endpoint Descripción
POST /api/v1/scanners/enroll

Intercambia un token de enrollment por una API key

POST /api/v1/tickets/check-in

Marca un ticket como utilizado en la puerta de acceso

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

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.

§ 02

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.

Authentication header
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_at devuelto 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).
§ 03

Registrar scanner

POST /api/v1/scanners/enroll no requiere Bearer

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
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

Campo Descripción
token
stringrequired

Token de enrollment del código QR de configuración. Opaco, ≥ 128 bits de entropía, un solo uso.

scanner_id
stringrequired

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.

scanner_name
stringoptional

Nombre legible mostrado en la interfaz de administración (por ejemplo, nombre del dispositivo).

scanner_platform
stringoptional

Información de la plataforma para soporte y seguimiento de compatibilidad.

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"
  }
}
Campo Descripción
api_key
string

API key de larga duración. Almacenar en Keychain/Keystore. Nunca registrar en logs, incluir en informes de fallos ni persistir en texto plano.

api_key_id
string

Identificador de la key, seguro para registrar en logs. Se utiliza para pistas de auditoría.

scope
object

Alcance de la key: eid, event_name, event_date, gate_id (opcional, null si aplica a todas las puertas), expires_at.

issuer
object

Información del issuer: name (nombre comercial) e iss (URL base).

Errores de enrollment

Código Significado
INVALID_TOKEN
400

El token tiene formato incorrecto, ha expirado o ya fue utilizado.

TOKEN_REVOKED
403

El token fue revocado por el organizador antes de ser utilizado.

PROTOCOL_VERSION_UNSUPPORTED
400

El issuer no soporta la versión del protocolo solicitada.

RATE_LIMITED
429

Demasiados intentos de enrollment desde esta IP.

INTERNAL
500

Error del servidor. Reintentar con backoff exponencial.

§ 04

Check-in

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

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
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"
  }'
Campo Descripción
tid
stringrequired

Identificador del ticket.

eid
stringrequired

Identificador del evento.

scanned_at
stringrequired

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:13Z
scanner_id
stringrequired

Identificador único y estable del dispositivo.

gate_id
stringoptional

Identificador de la puerta de acceso, incluido con fines de auditoría.

idempotency_key
stringrequired

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.

ADMITIDO 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"
  }
}
RECHAZADO 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"
  }
}

Valores de status

Status Significado
valid
200

Ticket válido, check-in realizado. Primer escaneo exitoso.

already_used
200

Ticket ya utilizado. La respuesta incluye el checked_in_at original.

revoked
200

Ticket revocado (reembolso, fraude, etc.).

wrong_event
200

Ticket válido pero para un evento diferente.

expired
200

La fecha de expiración del ticket ya ha pasado.

invalid_signature
400

El scanner informa que no se pudo verificar la signature. Se registra para auditoría en el lado del issuer.

§ 05

Estado del ticket

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

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
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 Significado
valid

Ticket emitido, no utilizado, no expirado.

checked_in

Ticket ya utilizado. checked_in_at contiene el timestamp.

revoked

Ticket revocado (reembolso, fraude).

expired

La fecha de expiración ya ha pasado.

Si el tid no existe, el issuer devuelve 404 NOT_FOUND.

§ 06

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).

Mismo tid + misma key

Reintento del mismo escaneo. El servidor devuelve el resultado original (idempotente).

Mismo tid + key diferente

Doble escaneo detectado. El servidor devuelve already_used.

Misma key + body diferente

Conflicto de idempotencia. El servidor devuelve 409 IDEMPOTENCY_CONFLICT.

Modo offline

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.

§ 07

Códigos de error

Todas las respuestas no-2xx utilizan un sobre de error estándar:

Error envelope
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "API key is missing, expired, or revoked.",
    "details": {}
  }
}
Código Tipo Descripción
400 INVALID_REQUEST Payload con formato incorrecto o campos requeridos faltantes.
400 INVALID_TOKEN El token de enrollment tiene formato incorrecto, ha expirado o ya fue utilizado.
400 PROTOCOL_VERSION_UNSUPPORTED El issuer no soporta la versión del protocolo del payload.
401 UNAUTHORIZED La API key falta, es inválida, ha expirado o fue revocada.
403 FORBIDDEN API key válida pero sin permiso para este recurso.
403 TOKEN_REVOKED Token de enrollment revocado por el organizador antes de su uso.
404 NOT_FOUND El recurso solicitado no existe.
409 IDEMPOTENCY_CONFLICT Se utilizó la misma clave de idempotencia con un payload diferente.
429 RATE_LIMITED Demasiados requests. El header Retry-After indica el tiempo de espera.
500 INTERNAL Error del servidor. Reintentar con backoff exponencial.
§ 08

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.

Última actualización : 20 de mayo de 2026