API de Captura
ISO 27001SOC 2 CertifiedGDPR CompliantGASA Partner

API de Captura de TruthScan

Cree un enlace de captura para el teléfono, reciba una foto firmada y lea el resultado con su clave de API.

Todos los endpoints están en https://truthscan.com. Envíe al usuario final a captureLink. Su backend no recibe el JPEG.

Autenticación

Cree una clave secreta en su cuenta.

Envíela en cada llamada en el encabezado x-api-key o como Authorization: Bearer. La clave debe pertenecer a una organización con acceso a la API. El enlace abierto en el teléfono no usa esta clave.

Sustituya YOUR_API_KEY por su clave secreta.

Crear una sesión

Devuelve un enlace de captura. inviteeEmail es obligatorio. expiresInSeconds es 15 minutos por defecto y no supera 7 días. maxCaptures es 20 por defecto y no supera 20. webhookUrl es opcional. Si se envía, debe ser https y resolverse a una dirección pública. webhookSecret solo aparece en esta respuesta.

POST /api/capture/session/create

Ponga sendEmail en true para que TruthScan envíe el enlace por correo. Entonces subject y message son obligatorios. Ponga {link} en el mensaje donde debe aparecer la URL de captura. emailSent es true solo cuando ese correo se envió. Si no, envíe captureLink usted mismo.

Guarde webhookSecret. Es la clave HMAC de capture.completed.

Ejemplo de solicitud

curl -X POST https://truthscan.com/api/capture/session/create \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: YOUR_API_KEY' \
  -d '{
    "inviteeEmail": "person@example.com",
    "expiresInSeconds": 900,
    "maxCaptures": 1,
    "webhookUrl": "https://example.com/hooks/capture"
  }'

Ejemplo de respuesta

{
  "sessionId": "11111111-1111-4111-8111-111111111111",
  "captureToken": "…",
  "captureUrl": "/capture/11111111-1111-4111-8111-111111111111?token=…",
  "captureLink": "https://truthscan.com/capture/11111111-1111-4111-8111-111111111111?token=…",
  "expiresAt": "2026-10-07T16:00:00.000Z",
  "expiresInSeconds": 900,
  "maxCaptures": 1,
  "webhookSecret": "…",
  "emailSent": false
}

Leer resultados

Consulte la sesión hasta que capturesUsed aumente, o espere el webhook. Las URL de descarga caducan al cabo de una hora.

Estado de la sesión

Caducidad, capturas usadas y la URL de webhook que registró.

GET /api/capture/sessions/{sessionId}

Ejemplo de solicitud

curl https://truthscan.com/api/capture/sessions/SESSION_ID \
  -H 'x-api-key: YOUR_API_KEY'

Ejemplo de respuesta

{
  "sessionId": "11111111-1111-4111-8111-111111111111",
  "expiresAt": "2026-10-07T16:00:00.000Z",
  "maxCaptures": 1,
  "capturesUsed": 1,
  "inviteeEmail": "person@example.com",
  "webhookUrl": "https://example.com/hooks/capture",
  "createdAt": "2026-10-07T15:45:00.000Z"
}

Listar fotos

Fotos de una sesión, de la más reciente a la más antigua. Use page y limit (máximo 50). Cada elemento es un resumen más downloadUrl. La ubicación de la lista solo incluye latitud, longitud y altitud. Obtenga el archivo para precisión, rumbo y velocidad.

GET /api/capture/sessions/{sessionId}/assets

Ejemplo de solicitud

curl 'https://truthscan.com/api/capture/sessions/SESSION_ID/assets?page=1&limit=20' \
  -H 'x-api-key: YOUR_API_KEY'

Ejemplo de respuesta

{
  "assets": [
    {
      "id": "22222222-2222-4222-8222-222222222222",
      "verificationState": "trusted",
      "trustTier": "standard",
      "risk": { "score": 0.95, "flags": ["geolocation_low_accuracy"] },
      "capturedAtUtc": "2026-10-07T15:50:00.000Z",
      "submittedAtUtc": "2026-10-07T15:50:01.200Z",
      "signedAtUtc": "2026-10-07T15:50:03.000Z",
      "captureToSubmitMs": 1200,
      "geolocation": {
        "latitude": 37.7749,
        "longitude": -122.4194,
        "altitude": 15,
        "altitudeAccuracyMeters": null,
        "accuracyMeters": null,
        "headingDegrees": null,
        "speedMetersPerSecond": null
      },
      "deviceModel": "iPhone",
      "devicePlatform": "iOS",
      "inviteeEmail": "person@example.com",
      "thumbnailUrl": "https://…",
      "downloadUrl": "https://…"
    }
  ],
  "pagination": {
    "page": 1,
    "totalPages": 1,
    "total": 1,
    "hasPreviousPage": false,
    "hasNextPage": false
  }
}

Obtener una foto

El mismo registro que la página de detalle de la captura, más assetUrl del JPEG firmado. El ejemplo muestra los campos con los que decide el flujo. device también incluye pantalla, lista de cámaras, GPU y entrada. sensors.geolocation repite el objeto de ubicación.

GET /api/capture/assets/{assetId}

Ejemplo de solicitud

curl https://truthscan.com/api/capture/assets/ASSET_ID \
  -H 'x-api-key: YOUR_API_KEY'

Ejemplo de respuesta

{
  "id": "22222222-2222-4222-8222-222222222222",
  "sessionId": "11111111-1111-4111-8111-111111111111",
  "verificationState": "trusted",
  "trustTier": "standard",
  "risk": { "score": 0.95, "flags": ["geolocation_low_accuracy"] },
  "inviteeEmail": "person@example.com",
  "mimeType": "image/jpeg",
  "assetUrl": "https://…",
  "thumbnailUrl": null,
  "capturedAtUtc": "2026-10-07T15:50:00.000Z",
  "submittedAtUtc": "2026-10-07T15:50:01.200Z",
  "serverReceivedAtUtc": "2026-10-07T15:50:02.000Z",
  "signedAtUtc": "2026-10-07T15:50:03.000Z",
  "createdAtUtc": "2026-10-07T15:50:03.100Z",
  "captureToSubmitMs": 1200,
  "timing": {
    "capturedAtUtc": "2026-10-07T15:50:00.000Z",
    "submittedAtUtc": "2026-10-07T15:50:01.200Z",
    "serverReceivedAtUtc": "2026-10-07T15:50:02.000Z",
    "signedAtUtc": "2026-10-07T15:50:03.000Z",
    "captureToSubmitMs": 1200
  },
  "geolocation": {
    "latitude": 37.7749,
    "longitude": -122.4194,
    "altitude": 15,
    "altitudeAccuracyMeters": 10,
    "accuracyMeters": 12,
    "headingDegrees": null,
    "speedMetersPerSecond": null
  },
  "deviceModel": "iPhone",
  "devicePlatform": "iOS",
  "device": {
    "browserName": "Mobile Safari",
    "platform": "iOS",
    "timezone": "America/Los_Angeles",
    "screenWidth": 390,
    "screenHeight": 844,
    "camera": { "width": 1920, "height": 1080, "facingMode": "environment" },
    "connection": { "effectiveType": "4g", "downlinkMbps": 10, "rttMs": 50 },
    "network": {
      "publicIp": "203.0.113.10",
      "country": "US",
      "city": "San Francisco"
    }
  },
  "sensors": {
    "gyroVariance": 0.02,
    "accelVariance": 0.11,
    "motionSampleCount": 24,
    "permissionDenied": {
      "camera": false,
      "geolocation": false,
      "motion": false
    }
  }
}

Campos del resultado

verificationState, trustTier y risk.flags son los valores para decidir el flujo. assetUrl y downloadUrl caducan al cabo de una hora.

CampoSignificado
verificationStatetrusted, valid_untrusted, invalid o none
trustTierstandard o high
risk.scoreDe 0 a 1. Empieza en 1. Cada señal del sensor lo reduce.
risk.flagscamera_permission_denied, geolocation_permission_denied, geolocation_missing, geolocation_low_accuracy, motion_permission_denied, motion_samples_missing, gyro_missing, zero_gyro_variance, accel_missing
geolocationlatitude, longitude, altitude, altitudeAccuracyMeters, accuracyMeters, headingDegrees, speedMetersPerSecond
deviceNavegador, plataforma, user agent, zona horaria, pantalla, cámara, conexión (tipo, downlink, RTT) y red (IP pública, ASN, organización, país, ciudad, región)
sensorsmotionSampleCount, gyroVariance, accelVariance y permissionDenied de cámara, geolocalización y movimiento
timingHoras del obturador, del envío, de la recepción en el servidor y de la firma, más captureToSubmitMs

Webhook

Tras una captura de confianza, TruthScan envía POST capture.completed a webhookUrl. No se siguen redirecciones. El cuerpo no incluye la ubicación precisa. Obtenga el archivo para el registro completo.

Lea X-TruthScan-Signature. El formato es t=<segundos unix>,v1=<hex>. Calcule HMAC-SHA256 de t + "." + el cuerpo sin procesar con webhookSecret y rechace marcas de tiempo con más de cinco minutos de diferencia.

Ejemplo de cuerpo

{
  "id": "…",
  "type": "capture.completed",
  "data": {
    "sessionId": "11111111-1111-4111-8111-111111111111",
    "assetId": "22222222-2222-4222-8222-222222222222",
    "verificationState": "trusted",
    "trustTier": "standard",
    "capturedAtUtc": "2026-10-07T15:50:00.000Z"
  }
}

Límites de tasa

Los límites se comparten entre instancias. Un 429 incluye Retry-After en segundos.

Límites

Cada llamada cuenta como una solicitud contra la IP y contra la organización.

RutaCuboLímite
Crear y leerIP600 / minuto
Crear y leerOrganización2.000 / minuto
Captura en el teléfonoIP60 / minuto
Captura en el teléfonoOrganización2.000 / minuto

Crear y leer cubre POST /api/capture/session/create y las tres rutas GET de resultado. La captura en el teléfono cubre nonce, upload-url y firma. El teléfono no envía su clave de API.

Respuesta limitada

Espere Retry-After y vuelva a enviar la solicitud.

HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json

{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "retryAfter": 12
}

Qué leer

  • Retry-After: segundos hasta que se reinicia la ventana
  • retryAfter: el mismo valor en el cuerpo JSON

Buenas prácticas

  • Consulte el estado de la sesión en lugar de listar archivos en un bucle corto.
  • Prefiera el webhook cuando pueda recibir callbacks HTTPS.

Errores

Las llamadas fallidas devuelven JSON con error y code.

401 y 403 significan que la clave no se puede usar. 404 significa que la sesión o el archivo no está en su organización.

CódigoSignificado
MISSING_API_KEYNo hay x-api-key ni token Bearer
INVALID_API_KEYClave desconocida, inactiva o sin organización
ORG_NO_API_ACCESSEl acceso a la API de la organización está desactivado
INVITEE_EMAIL_REQUIREDFaltaba inviteeEmail
INVITEE_EMAIL_INVALIDinviteeEmail no es una dirección válida
INVITE_MESSAGE_REQUIREDsendEmail es true y message falta o es demasiado largo
INVITE_SUBJECT_REQUIREDsendEmail es true y falta subject
WEBHOOK_URL_REJECTEDwebhookUrl no es https público
SESSION_NOT_FOUNDNo hay sesión con ese id en su organización
ASSET_NOT_FOUNDNo hay archivo con ese id en su organización
RATE_LIMIT_EXCEEDEDDemasiadas solicitudes en la ventana actual

Preguntas frecuentes

Cómo encaja la API de Captura en su backend.