Capture-API
ISO 27001SOC 2 CertifiedGDPR CompliantGASA Partner

TruthScan Capture-API

Erstellen Sie einen Capture-Link für das Telefon, erhalten Sie ein signiertes Foto und lesen Sie das Ergebnis mit Ihrem API-Schlüssel.

Alle Endpunkte liegen auf https://truthscan.com. Schicken Sie die Endnutzerin zu captureLink. Ihr Backend erhält das JPEG nicht.

Authentifizierung

Erstellen Sie einen geheimen Schlüssel in Ihrem Konto.

Senden Sie ihn bei jedem Aufruf als Header x-api-key oder als Authorization: Bearer. Der Schlüssel muss zu einer Organisation mit API-Zugang gehören. Der Link auf dem Telefon verwendet diesen Schlüssel nicht.

Ersetzen Sie YOUR_API_KEY durch Ihren geheimen Schlüssel.

Sitzung erstellen

Liefert einen Capture-Link. inviteeEmail ist erforderlich. expiresInSeconds ist standardmäßig 15 Minuten und höchstens 7 Tage. maxCaptures ist standardmäßig 20 und höchstens 20. webhookUrl ist optional. Gesetzt muss sie https sein und auf eine öffentliche Adresse zeigen. webhookSecret steht nur in dieser Antwort.

POST /api/capture/session/create

Setzen Sie sendEmail auf true, damit TruthScan den Link per E-Mail sendet. Dann sind subject und message erforderlich. Setzen Sie {link} in die Nachricht, wo die Capture-URL erscheinen soll. emailSent ist nur true, wenn diese E-Mail gesendet wurde. Sonst senden Sie captureLink selbst.

Speichern Sie webhookSecret. Er ist der HMAC-Schlüssel für capture.completed.

Beispielanfrage

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

Beispielantwort

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

Ergebnisse lesen

Fragen Sie die Sitzung ab, bis capturesUsed steigt, oder warten Sie auf den Webhook. Download-URLs laufen nach einer Stunde ab.

Sitzungsstatus

Ablauf, verbrauchte Aufnahmen und die registrierte Webhook-URL.

GET /api/capture/sessions/{sessionId}

Beispielanfrage

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

Beispielantwort

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

Fotos auflisten

Fotos einer Sitzung, neueste zuerst. Query page und limit (höchstens 50). Jeder Eintrag ist eine Zusammenfassung plus downloadUrl. Der Listenstandort enthält nur Breitengrad, Längengrad und Höhe. Holen Sie das Asset für Genauigkeit, Richtung und Geschwindigkeit.

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

Beispielanfrage

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

Beispielantwort

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

Ein Foto lesen

Derselbe Datensatz wie die Capture-Detailseite, plus assetUrl für das signierte JPEG. Das Beispiel zeigt die Felder, nach denen Sie verzweigen. device enthält außerdem Bildschirm, Kameraliste, GPU und Eingabe. sensors.geolocation wiederholt das Standortobjekt.

GET /api/capture/assets/{assetId}

Beispielanfrage

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

Beispielantwort

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

Ergebnisfelder

verificationState, trustTier und risk.flags sind die Werte für die Verzweigung. assetUrl und downloadUrl laufen nach einer Stunde ab.

FeldBedeutung
verificationStatetrusted, valid_untrusted, invalid oder none
trustTierstandard oder high
risk.score0 bis 1. Beginnt bei 1. Jedes Sensor-Flag senkt den Wert.
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
deviceBrowser, Plattform, User-Agent, Zeitzone, Bildschirm, Kamera, Verbindung (Typ, Downlink, RTT) und Netzwerk (öffentliche IP, ASN, Organisation, Land, Stadt, Region)
sensorsmotionSampleCount, gyroVariance, accelVariance und permissionDenied für Kamera, Standort und Bewegung
timingZeiten für Auslöser, Absenden, Serverempfang und Signatur, plus captureToSubmitMs

Webhook

Nach einer vertrauenswürdigen Aufnahme sendet TruthScan POST capture.completed an webhookUrl. Weiterleitungen werden nicht gefolgt. Der Body enthält keinen genauen Standort. Holen Sie das Asset für den vollständigen Datensatz.

Lesen Sie X-TruthScan-Signature. Das Format ist t=<Unix-Sekunden>,v1=<hex>. Berechnen Sie HMAC-SHA256 über t + "." + den Rohkörper mit webhookSecret und lehnen Sie Zeitstempel ab, die mehr als fünf Minuten abweichen.

Beispiel-Body

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

Ratenlimits

Limits gelten über alle Instanzen. Eine 429 enthält Retry-After in Sekunden.

Limits

Jeder Aufruf zählt als eine Anfrage gegen die IP und gegen die Organisation.

PfadBucketLimit
Erstellen und lesenIP600 / Minute
Erstellen und lesenOrganisation2.000 / Minute
Telefon-CaptureIP60 / Minute
Telefon-CaptureOrganisation2.000 / Minute

Erstellen und lesen umfasst POST /api/capture/session/create und die drei GET-Ergebnisrouten. Telefon-Capture umfasst Nonce, upload-url und Signatur. Das Telefon sendet Ihren API-Schlüssel nicht.

Gedrosselte Antwort

Warten Sie Retry-After und senden Sie die Anfrage erneut.

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

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

Was zu lesen ist

  • Retry-After: Sekunden bis das Fenster zurückgesetzt wird
  • retryAfter: derselbe Wert im JSON-Body

Empfehlungen

  • Fragen Sie den Sitzungsstatus ab, statt Assets in einer engen Schleife zu listen.
  • Nutzen Sie den Webhook, wenn Sie HTTPS-Callbacks empfangen können.

Fehler

Fehlgeschlagene Aufrufe liefern JSON mit error und code.

401 und 403 bedeuten, dass der Schlüssel nicht verwendbar ist. 404 bedeutet, dass Sitzung oder Asset nicht in Ihrer Organisation liegt.

CodeBedeutung
MISSING_API_KEYKein x-api-key und kein Bearer-Token
INVALID_API_KEYSchlüssel unbekannt, inaktiv oder ohne Organisation
ORG_NO_API_ACCESSAPI-Zugang der Organisation ist aus
INVITEE_EMAIL_REQUIREDinviteeEmail fehlte
INVITEE_EMAIL_INVALIDinviteeEmail ist keine gültige Adresse
INVITE_MESSAGE_REQUIREDsendEmail ist true und message fehlt oder ist zu lang
INVITE_SUBJECT_REQUIREDsendEmail ist true und subject fehlt
WEBHOOK_URL_REJECTEDwebhookUrl ist kein öffentliches https
SESSION_NOT_FOUNDKeine Sitzung mit dieser id in Ihrer Organisation
ASSET_NOT_FOUNDKein Asset mit dieser id in Ihrer Organisation
RATE_LIMIT_EXCEEDEDZu viele Anfragen im aktuellen Fenster

Häufige Fragen

Wie die Capture-API in Ihr Backend passt.