LegitFlash

API

API

Crea una sesión de verificación, envía al solicitante al enlace alojado, recibe el webhook firmado y consulta el resultado. La referencia en formato máquina es GET /api/v1/openapi.json (OpenAPI 3.1, con webhooks); la legible es la Referencia de la API.

Tokens: real y de prueba

  • Tokens personales. Un token actúa como su propietario en un equipo (X-Team-Id), así que una integración deja de funcionar cuando ese usuario sale del equipo. Usa un usuario dedicado para integraciones en producción.
  • Permisos: sessions:read, sessions:write, flows:read, webhooks:read (más los de cuenta, read/write). El rol del usuario en el equipo sigue aplicándose: borrar una sesión exige ser propietario o administrador.
  • Modo (se elige al crear, Cuenta, Tokens de API): tid_live_... funciona solo sobre sesiones reales; tid_test_... solo sobre sesiones de prueba (livemode: false). El id de una sesión del otro modo da 404.
  • Modo test: el enlace alojado muestra un aviso TEST y un simulador (aprobar, rechazar con un motivo, pedir un reenvío) en lugar de capturas reales. Las sesiones de prueba nunca entran en la cola de revisión, no llegan a Pumble, no se facturan, no envían correos y el registro se borra 24 horas después de su última actividad. Los webhooks se envían con normalidad con "livemode": false.

Inicio rápido

Copiado
# 1. Crea una sesión (con un token de prueba mientras integras)
curl -sS https://YOUR-LEGITFLASH-DOMAIN/api/v1/sessions \
  -H "Authorization: Bearer $TRUSTID_TOKEN" \
  -H "Idempotency-Key: pedido-1234-verificacion" \
  -H "Content-Type: application/json" \
  -d '{"flow_id":"01J...","external_reference":"pedido-1234","metadata":{"order":"1234"},"redirect_url":"https://tienda.example/verificado"}'
# -> 201 {"data":{"id":"01J...","status":"created","url":"https://YOUR-LEGITFLASH-DOMAIN/v/...","qr_svg_url":"...","embed":{...}}}

# 2. Redirige al solicitante a data.url (o muestra el QR, o incrústalo) y espera el webhook.
# 3. Consulta el resultado
curl -sS https://YOUR-LEGITFLASH-DOMAIN/api/v1/sessions/01J... -H "Authorization: Bearer $TRUSTID_TOKEN"
Copiado
// Node 22
const res = await fetch('https://YOUR-LEGITFLASH-DOMAIN/api/v1/sessions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TRUSTID_TOKEN}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': `order-${order.id}-verification`,
  },
  body: JSON.stringify({ flow_id: process.env.TRUSTID_FLOW, external_reference: String(order.id) }),
});
const { data } = await res.json();
redirect(data.url); // solo se muestra en esta respuesta: guarda data.id, no el enlace
Copiado
// PHP (cliente HTTP de Laravel)
$session = Http::withToken(config('services.trustid.token'))
    ->withHeaders(['Idempotency-Key' => "order-{$order->id}-verification"])
    ->post('https://YOUR-LEGITFLASH-DOMAIN/api/v1/sessions', [
        'flow_id' => config('services.trustid.flow'),
        'external_reference' => (string) $order->id,
    ])->throw()->json('data');
return redirect($session['url']);

Webhooks: ver Webhooks (firma, reintentos, carga; el cuerpo incluye también livemode y tus metadata).

Endpoints

Método Ruta Permiso Notas
POST /sessions sessions:write 201 + la sesión y url, qr_svg_url (firmada, 15 min), embed. Respeta Idempotency-Key
GET /sessions sessions:read paginación por cursor; filtros status, flow_id, external_reference, created[gte|lte], decided[gte|lte], per_page (máx. 100)
GET /sessions/{id} sessions:read estado, decisión, motivos, resultado (según el detalle del flujo), nombres de alertas, cronología, media_purge_at. Nunca archivos
POST /sessions/{id}/cancel sessions:write solo antes del envío; si no, 409 not_cancellable
POST /sessions/{id}/link sessions:write enlace nuevo, el anterior deja de valer; 409 not_relinkable una vez decidida o caducada
DELETE /sessions/{id} sessions:write borrado ya a petición del interesado (archivos, registro, cargas de webhook), 204
GET /sessions/{id}/export sessions:read exportación para derecho de acceso (JSON, sin binarios, sin notas internas)
GET /flows, /flows/{id} flows:read filtro archived=0|1
GET /usage sessions:read period, included, used, overage, cap (null = sin tope), overage_allowed
GET /webhook-deliveries webhooks:read session_id, status; solo estado de la entrega, nunca cargas

Cuerpo de creación: flow_id (obligatorio), external_reference, applicant.email, locale (en|es), send_invite (solo modo real), redirect_url (su dominio debe ser uno de los de las URL de retorno del flujo), metadata (hasta 10 pares de texto, 500 bytes cada uno, claves [A-Za-z0-9_.-]{1,40}). Los metadatos no deben contener nunca datos personales: se devuelven en respuestas y webhooks y se guardan en texto plano.

Idempotencia

Envía Idempotency-Key (máx. 255 caracteres) en cualquier POST. Por equipo y modo de token, durante 24 horas: la misma clave con la misma petición repite la primera respuesta 2xx (cabecera Idempotent-Replayed: true, incluso la url de un solo uso); la misma clave con una petición distinta da 422 idempotency_key_reused. Las peticiones fallidas no se guardan, así que un reintento corregido simplemente se ejecuta. Solo se guarda un hash de la clave y la respuesta guardada va cifrada.

Errores, paginación, límites, versiones

  • Los errores son RFC 9457 application/problem+json con un code estable. Más en Errores.
  • Las listas usan paginación por cursor: sigue links.next hasta que sea null.
  • Límite de uso por token según el plan (limits.api_rpm): X-RateLimit-Limit/Remaining, 429 + Retry-After.
  • Un token en la query string da 400; usa siempre la cabecera Authorization.
  • Versiones: los cambios dentro de v1 son aditivos (campos, endpoints, eventos y valores nuevos: ignora lo que no conozcas). Un cambio incompatible llegará como /api/v2 con 12 meses de solapamiento, anunciado con las cabeceras Deprecation y Sunset en v1.
  • Desarrolladores, API en el panel muestra las últimas 100 llamadas del equipo (método, ruta, estado, duración, nombre del token; sin cuerpos).