API de Captura
ISO 27001SOC 2 CertifiedGDPR CompliantGASA Partner

API de Captura TruthScan

Crie um link de captura para o telefone, receba uma foto assinada e leia o resultado com sua chave de API.

Todos os endpoints ficam em https://truthscan.com. Envie o usuário final para captureLink. Seu backend não recebe o JPEG.

Autenticação

Crie uma chave secreta na sua conta.

Envie-a em toda chamada no cabeçalho x-api-key ou em Authorization: Bearer. A chave precisa pertencer a uma organização com acesso à API. O link aberto no telefone não usa essa chave.

Substitua YOUR_API_KEY pela sua chave secreta.

Criar uma sessão

Devolve um link de captura. inviteeEmail é obrigatório. expiresInSeconds padrão é 15 minutos e não passa de 7 dias. maxCaptures padrão é 20 e não passa de 20. webhookUrl é opcional. Quando enviado, precisa ser https e resolver para um endereço público. webhookSecret aparece só nesta resposta.

POST /api/capture/session/create

Defina sendEmail como true para a TruthScan enviar o link por e-mail. Aí subject e message são obrigatórios. Coloque {link} na mensagem onde a URL de captura deve aparecer. emailSent é true só quando esse e-mail foi enviado. Caso contrário, envie captureLink você mesmo.

Guarde webhookSecret. Ele é a chave HMAC de capture.completed.

Exemplo de pedido

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"
  }'

Exemplo de resposta

{
  "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
}

Ler resultados

Consulte a sessão até capturesUsed aumentar, ou espere o webhook. As URLs de download expiram em uma hora.

Status da sessão

Validade, capturas usadas e a URL de webhook que você registrou.

GET /api/capture/sessions/{sessionId}

Exemplo de pedido

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

Exemplo de resposta

{
  "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 uma sessão, da mais nova para a mais antiga. Use page e limit (máximo 50). Cada item é um resumo mais downloadUrl. A localização da lista só inclui latitude, longitude e altitude. Busque o arquivo para precisão, direção e velocidade.

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

Exemplo de pedido

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

Exemplo de resposta

{
  "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
  }
}

Obter uma foto

O mesmo registro da página de detalhe da captura, mais assetUrl do JPEG assinado. O exemplo mostra os campos em que você decide o fluxo. device também inclui tela, lista de câmeras, GPU e entrada. sensors.geolocation repete o objeto de localização.

GET /api/capture/assets/{assetId}

Exemplo de pedido

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

Exemplo de resposta

{
  "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 do resultado

verificationState, trustTier e risk.flags são os valores para decidir o fluxo. assetUrl e downloadUrl expiram depois de uma hora.

CampoSignificado
verificationStatetrusted, valid_untrusted, invalid ou none
trustTierstandard ou high
risk.scoreDe 0 a 1. Começa em 1. Cada sinal do sensor reduz o valor.
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, fuso, tela, câmera, conexão (tipo, downlink, RTT) e rede (IP público, ASN, organização, país, cidade, região)
sensorsmotionSampleCount, gyroVariance, accelVariance e permissionDenied de câmera, geolocalização e movimento
timingHorários do obturador, do envio, do recebimento no servidor e da assinatura, mais captureToSubmitMs

Webhook

Depois de uma captura confiável, a TruthScan envia POST capture.completed para webhookUrl. Redirecionamentos não são seguidos. O corpo não inclui a localização precisa. Busque o arquivo para o registro completo.

Leia X-TruthScan-Signature. O formato é t=<segundos unix>,v1=<hex>. Calcule HMAC-SHA256 de t + "." + o corpo bruto com webhookSecret e rejeite timestamps com mais de cinco minutos de diferença.

Exemplo de corpo

{
  "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"
  }
}

Limites de taxa

Os limites são compartilhados entre instâncias. Um 429 inclui Retry-After em segundos.

Limites

Cada chamada conta como um pedido contra o IP e contra a organização.

CaminhoBaldeLimite
Criar e lerIP600 / minuto
Criar e lerOrganização2.000 / minuto
Captura no telefoneIP60 / minuto
Captura no telefoneOrganização2.000 / minuto

Criar e ler cobre POST /api/capture/session/create e as três rotas GET de resultado. A captura no telefone cobre nonce, upload-url e assinatura. O telefone não envia sua chave de API.

Resposta limitada

Espere Retry-After e envie o pedido de novo.

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

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

O que ler

  • Retry-After: segundos até a janela reiniciar
  • retryAfter: o mesmo valor no corpo JSON

Boas práticas

  • Consulte o status da sessão em vez de listar arquivos em um loop curto.
  • Prefira o webhook quando puder receber callbacks HTTPS.

Erros

Chamadas com falha devolvem JSON com error e code.

401 e 403 significam que a chave não pode ser usada. 404 significa que a sessão ou o arquivo não está na sua organização.

CódigoSignificado
MISSING_API_KEYSem x-api-key nem token Bearer
INVALID_API_KEYChave desconhecida, inativa ou sem organização
ORG_NO_API_ACCESSO acesso à API da organização está desligado
INVITEE_EMAIL_REQUIREDinviteeEmail estava ausente
INVITEE_EMAIL_INVALIDinviteeEmail não é um endereço válido
INVITE_MESSAGE_REQUIREDsendEmail é true e message está ausente ou longo demais
INVITE_SUBJECT_REQUIREDsendEmail é true e subject está ausente
WEBHOOK_URL_REJECTEDwebhookUrl não é https público
SESSION_NOT_FOUNDNenhuma sessão com esse id na sua organização
ASSET_NOT_FOUNDNenhum arquivo com esse id na sua organização
RATE_LIMIT_EXCEEDEDPedidos demais na janela atual

Perguntas frequentes

Como a API de Captura entra no seu backend.