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/createSetzen 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}/assetsBeispielanfrage
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.
| Feld | Bedeutung |
|---|---|
| verificationState | trusted, valid_untrusted, invalid oder none |
| trustTier | standard oder high |
| risk.score | 0 bis 1. Beginnt bei 1. Jedes Sensor-Flag senkt den Wert. |
| risk.flags | camera_permission_denied, geolocation_permission_denied, geolocation_missing, geolocation_low_accuracy, motion_permission_denied, motion_samples_missing, gyro_missing, zero_gyro_variance, accel_missing |
| geolocation | latitude, longitude, altitude, altitudeAccuracyMeters, accuracyMeters, headingDegrees, speedMetersPerSecond |
| device | Browser, Plattform, User-Agent, Zeitzone, Bildschirm, Kamera, Verbindung (Typ, Downlink, RTT) und Netzwerk (öffentliche IP, ASN, Organisation, Land, Stadt, Region) |
| sensors | motionSampleCount, gyroVariance, accelVariance und permissionDenied für Kamera, Standort und Bewegung |
| timing | Zeiten 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.
| Pfad | Bucket | Limit |
|---|---|---|
| Erstellen und lesen | IP | 600 / Minute |
| Erstellen und lesen | Organisation | 2.000 / Minute |
| Telefon-Capture | IP | 60 / Minute |
| Telefon-Capture | Organisation | 2.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.
| Code | Bedeutung |
|---|---|
| MISSING_API_KEY | Kein x-api-key und kein Bearer-Token |
| INVALID_API_KEY | Schlüssel unbekannt, inaktiv oder ohne Organisation |
| ORG_NO_API_ACCESS | API-Zugang der Organisation ist aus |
| INVITEE_EMAIL_REQUIRED | inviteeEmail fehlte |
| INVITEE_EMAIL_INVALID | inviteeEmail ist keine gültige Adresse |
| INVITE_MESSAGE_REQUIRED | sendEmail ist true und message fehlt oder ist zu lang |
| INVITE_SUBJECT_REQUIRED | sendEmail ist true und subject fehlt |
| WEBHOOK_URL_REJECTED | webhookUrl ist kein öffentliches https |
| SESSION_NOT_FOUND | Keine Sitzung mit dieser id in Ihrer Organisation |
| ASSET_NOT_FOUND | Kein Asset mit dieser id in Ihrer Organisation |
| RATE_LIMIT_EXCEEDED | Zu viele Anfragen im aktuellen Fenster |
Häufige Fragen
Wie die Capture-API in Ihr Backend passt.