ThisVerify API
REST API פשוט: שולחים קובץ, מקבלים דוח JSON מלא.
סקירה
ה-API של ThisVerify מאפשר לשלוח מסמך (PDF או תמונה) ולקבל דוח זיוף מלא: ציון סיכון 0–100, החלטה (סיכון נמוך / לבדיקה / סיכון גבוה), ממצאים עם מיקום מדויק על המסמך, בדיקות חשבוניות ונתונים שחולצו. ה-API מבוסס REST, מחזיר JSON ועובד בצורה אסינכרונית: יוצרים בדיקה, ומקבלים את התוצאה ב-Webhook או בשליפה.
- 1. שליחהPOST /scans עם הקובץ. תשובה מיידית 202 עם מזהה בדיקה.
- 2. ניתוחהמנועים רצים במקביל — לרוב 20–60 שניות.
- 3. תוצאהWebhook scan.completed, או GET /scans/{id}.
אימות ומפתחות
כל בקשה נשלחת עם מפתח API בכותרת Authorization. המפתחות שייכים לארגון (לא למשתמש בודד), נוצרים במסך "API ואינטגרציות" באזור האישי, מוצגים פעם אחת בלבד ונשמרים אצלנו כגיבוב (hash) בלבד. אפשר להחזיק כמה מפתחות — למשל אחד לכל מערכת — ולבטל כל אחד בנפרד.
מפתחות API ו-Webhooks זמינים לארגונים בחבילה העסקית או הארגונית. התיעוד, הדוגמאות והמפרט פתוחים לכולם — אפשר לתכנן את החיבור כבר עכשיו. מפתח של ארגון בלי חבילה מתאימה יקבל 403 NO_API_ACCESS.
Authorization: Bearer tv_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxהרשאות (Scopes)
לכל מפתח מוגדרות הרשאות. תנו לכל מערכת רק את מה שהיא צריכה.
| שדה | סוג | תיאור |
|---|---|---|
| scans:write | scope | יצירת בדיקות |
| scans:read | scope | קריאת בדיקות ודוחות |
| scans:delete | scope | מחיקת בדיקות |
| usage:read | scope | קריאת שימוש ומכסה |
התחלה מהירה
בדיקה ראשונה בשתי פקודות:
curl -X POST https://thisverify-green.vercel.app/api/v1/scans \
-H "Authorization: Bearer $THISVERIFY_KEY" \
-H "Idempotency-Key: loan-88231-doc-1" \
-F "file=@transfer.pdf" \
-F 'context={"document_type":"bank_transfer","expected_amount":"12500","expected_name":"ישראל ישראלי"}' \
-F "client_reference=loan-88231"
# → 202 {"id":"8f1c…","object":"scan","status":"queued",…}
curl https://thisverify-green.vercel.app/api/v1/scans/8f1c… -H "Authorization: Bearer $THISVERIFY_KEY"יצירת בדיקה
שלוש דרכים לשלוח את הקובץ: multipart (מומלץ), JSON עם base64, או JSON עם כתובת https ציבורית שממנה נוריד את הקובץ. מחזיר 202 עם אובייקט הבדיקה בסטטוס queued. דורש scans:write. כל בדיקה מנכה אחת מהמכסה החודשית של הארגון; אם הניתוח נכשל אצלנו — הבדיקה מוחזרת למכסה.
| שדה | סוג | תיאור |
|---|---|---|
| file | binary | הקובץ (multipart). PDF, JPEG, PNG, WEBP או HEIC. |
| file.content_base64 | string | חלופה ב-JSON: תוכן הקובץ ב-base64 (אפשר גם data URL). עם file.name. |
| file_url | string | חלופה ב-JSON: כתובת https ציבורית. חייבת להחזיר את הקובץ תוך 15 שניות, ללא הפניות. כתובות פנימיות נחסמות. |
| context.document_type | enum | רמז לסוג המסמך: bank_transfer, payment_app, bank_statement, account_confirmation, balance_confirmation, check, deposit_receipt, card_statement, payslip, invoice, tax_form, id_document, utility_bill, loan_document, medical, contract, other |
| context.expected_amount | string | הסכום שאתם מצפים לראות. אי-התאמה תסומן כממצא. |
| context.expected_name | string | שם המוטב/בעל החשבון/העובד הצפוי. |
| context.expected_date | YYYY-MM-DD | התאריך הצפוי. |
| context.expected_reference | string | אסמכתא/מספר חשבון צפוי. |
| context.notes | string | הקשר חופשי למנתח (עד 1,000 תווים). |
| client_reference | string | המזהה שלכם (מספר בקשה/תיק). חוזר בכל תשובה וב-Webhook, ואפשר לסנן לפיו. |
| metadata | object | עד 20 זוגות מפתח-ערך שלכם (ערכים עד 500 תווים). ב-multipart שולחים כמחרוזת JSON. |
| lang | "he" | "en" | שפת הדוח. ברירת מחדל: he. |
POST /api/v1/scans
Content-Type: application/json
Idempotency-Key: 4c1f…
{
"file": { "name": "payslip-06.pdf", "content_base64": "JVBERi0xLjcK…" },
"context": { "document_type": "payslip", "expected_name": "Dana Levi" },
"client_reference": "app-55102",
"metadata": { "branch": "tel-aviv", "officer": "u-1182" },
"lang": "en"
}שליפת בדיקה ודוח
מחזיר את הבדיקה. כשהסטטוס completed — כולל את הדוח המלא בשדה report. הוסיפו ?include=summary כדי לקבל רק תקציר (בלי report). דורש scans:read. בזמן עיבוד השדה stage מראה את השלב הנוכחי.
{
"id": "8f1c2a4e-…",
"object": "scan",
"status": "completed",
"verdict": "high_risk",
"risk_score": 91,
"document_type": "bank_transfer",
"issuer": "בנק הפועלים",
"channel": "app_screenshot",
"client_reference": "loan-88231",
"report": {
"summary": "…",
"recommended_actions": ["…"],
"findings": [
{
"id": "ai-1",
"category": "visual",
"severity": "high",
"confidence": 0.93,
"title": "Amount digits re-rendered",
"detail": "The digits of the amount use a different font weight and anti-aliasing…",
"box": { "page": 1, "box_2d": [412, 520, 446, 700] }
}
],
"checks": [ { "id": "arith", "label": "…", "status": "fail", "detail": "…" } ],
"extracted": { "amounts": ["12,500.00"], "dates": ["2026-10-05"], "iban": "IL62…" },
"forensic_analysis": { "pixel_variance": { "has_variance": true, "score": 0.88 } },
"engine": { "version": "…", "duration_ms": 31244, "layers": ["pdf", "metadata", "ela", "content", "ai"] }
}
}box_2d הוא [ymin, xmin, ymax, xmax] בסקאלה 0–1000 יחסית לעמוד — כך אפשר לצייר את הסימון בכל רזולוציה.
רשימת בדיקות
מהחדש לישן, עם עימוד מבוסס cursor. דורש scans:read.
| שדה | סוג | תיאור |
|---|---|---|
| limit | 1–100 | מספר תוצאות בעמוד. ברירת מחדל 25. |
| cursor | string | הערך next_cursor מהעמוד הקודם. |
| status | enum | queued · processing · completed · failed |
| verdict | enum | low_risk · review · high_risk |
| client_reference | string | סינון לפי המזהה שלכם. |
| created_after / created_before | ISO 8601 | טווח תאריכים. |
{
"object": "list",
"data": [ { "id": "…", "object": "scan", "status": "completed", "verdict": "review", … } ],
"has_more": true,
"next_cursor": "eyJ0IjoiMjAyNi0xMC0w…"
}מחיקת בדיקה
מוחק לצמיתות את הבדיקה, הדוח וקובץ המקור (כולל עותקים שנאספו לאימון). דורש scans:delete. מתאים לבקשות מחיקה לפי חוק הגנת הפרטיות / GDPR.
שימוש ומכסה
השימוש של הארגון בתקופה הנוכחית. דורש usage:read.
{
"object": "usage",
"plan": { "id": "business", "name": "Business" },
"period": { "start": "2026-10-01T00:00:00.000Z", "end": "2026-11-01T00:00:00.000Z" },
"used": 1840,
"limit": 5000,
"remaining": 3160,
"total_scans": 22114
}ולבדיקת מפתח: GET /api/v1 מחזיר את הארגון וההרשאות של המפתח.
Webhooks
במקום לשאול שוב ושוב — הגדירו כתובת https במסך "API ואינטגרציות", ואנחנו נשלח POST כשהבדיקה מסתיימת. לכל כתובת סוד חתימה משלה (whsec_…).
| שדה | סוג | תיאור |
|---|---|---|
| scan.completed | event | הבדיקה הסתיימה. כולל verdict, risk_score, client_reference ו-metadata. לדוח המלא — GET /scans/{id}. |
| scan.failed | event | הבדיקה נכשלה (למשל קובץ פגום). היחידה הוחזרה למכסה. |
| ping | event | אירוע בדיקה שנשלח מכפתור "שליחת בדיקה". |
ThisVerify-Event: scan.completed
ThisVerify-Delivery: 5b0e… ← unique event id (dedupe on it)
ThisVerify-Signature: t=1791364364,v1=3f9a…
{
"id": "5b0e…",
"type": "scan.completed",
"created": "2026-10-07T09:13:21.004Z",
"data": {
"scan": {
"id": "8f1c…", "object": "scan", "status": "completed",
"verdict": "high_risk", "risk_score": 91, "document_type": "bank_transfer",
"client_reference": "loan-88231", "metadata": { "branch": "tel-aviv" },
"file": { "name": "transfer.pdf", "sha256": "…" }
}
}
}- • החזירו 2xx תוך 10 שניות. עבודה כבדה — עשו ברקע אחרי שהחזרתם תשובה.
- • ניסיונות חוזרים: מיד, אחרי 3 ו-10 שניות, ואז אחרי 1 דק׳, 5 דק׳, 30 דק׳, שעתיים ו-12 שעות.
- • ייתכנו כפילויות — זהו אותן לפי ThisVerify-Delivery.
- • אחרי 50 כשלונות רצופים הכתובת מושבתת אוטומטית; אפשר להפעיל מחדש מהמסך.
אימות חתימה
ודאו שכל בקשה הגיעה מאיתנו: חשבו HMAC-SHA256 על המחרוזת "{t}.{גוף הבקשה הגולמי}" עם סוד ה-Webhook, השוו ל-v1 בהשוואה בזמן קבוע, ודחו בקשות שה-t שלהן ישן מ-5 דקות.
import crypto from 'node:crypto';
export function verifyThisVerify(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(expected), b = Buffer.from(parts.v1 || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// Express: app.post('/hooks/thisverify', express.raw({ type: 'application/json' }), (req, res) => {
// if (!verifyThisVerify(req.body.toString(), req.get('ThisVerify-Signature'), process.env.TV_WHSEC)) return res.sendStatus(400);
// res.sendStatus(200); queue.push(JSON.parse(req.body));
// });אידמפוטנטיות
שלחו כותרת Idempotency-Key (עד 200 תווים, למשל מזהה המסמך אצלכם) בכל POST /scans. אם הבקשה נשלחת שוב עם אותו מפתח ואותו קובץ — תקבלו את אותה בדיקה (200 עם Idempotent-Replayed: true) בלי חיוב נוסף. אותו מפתח עם קובץ אחר מחזיר 409. המפתחות נשמרים 7 ימים.
מגבלות קצב
המגבלה היא לכל ארגון, לדקה (ברירת מחדל 120; בחבילות ארגוניות לפי הסכם). כל תשובה כוללת RateLimit-Limit, RateLimit-Remaining ו-RateLimit-Reset. בחריגה — 429 עם Retry-After בשניות. גודל קובץ מרבי: 10MB.
שגיאות
כל שגיאה מוחזרת במבנה אחיד עם קוד קבוע ו-request_id (שלחו אותו לתמיכה).
HTTP/1.1 402 Payment Required
X-Request-Id: req_0c51d0a3e8b14f2a9d11
{ "error": { "code": "QUOTA_EXCEEDED", "message": "The organization has used its monthly allowance.", "request_id": "req_0c51d0a3e8b14f2a9d11" } }| HTTP | code | משמעות |
|---|---|---|
| 401 | NO_KEY | Missing API key. Send "Authorization: Bearer tv_live_…". |
| 401 | INVALID | The API key is invalid or revoked. |
| 403 | SUSPENDED | The organization or key owner is suspended. |
| 403 | NO_API_ACCESS | API access requires a paid plan that includes the API (Business or Enterprise). Upgrade from the dashboard or contact sales. |
| 403 | INSUFFICIENT_SCOPE | The API key does not have the required scope. |
| 429 | RATE_LIMITED | Too many requests. Retry after the time in the Retry-After header. |
| 400 | INVALID_REQUEST | The request is malformed. |
| 400 | FILE_REQUIRED | Provide a file as multipart "file", JSON "file.content_base64", or JSON "file_url". |
| 400 | EMPTY_FILE | The file is empty. |
| 413 | FILE_TOO_LARGE | The file exceeds the size limit. |
| 415 | UNSUPPORTED_FILE | Unsupported file type. Use PDF, JPEG, PNG, WEBP or HEIC. |
| 400 | FILE_URL_REJECTED | file_url must be a public https URL that returns the file within 15 seconds. |
| 402 | QUOTA_EXCEEDED | The organization has used its monthly allowance. |
| 503 | AI_NOT_CONFIGURED | The analysis service is temporarily unavailable. |
| 404 | NOT_FOUND | Resource not found. |
| 409 | CONFLICT | An Idempotency-Key was reused with a different request. |
| 500 | SERVICE_ERROR | Unexpected error. Retry with the same Idempotency-Key. |
אובייקט הבדיקה
| שדה | סוג | תיאור |
|---|---|---|
| status | enum | queued → processing → completed / failed |
| verdict | enum | low_risk — לא נמצאו סימני זיוף משמעותיים · review — נדרשת בדיקה אנושית · high_risk — סימני זיוף מובהקים |
| risk_score | 0–100 | ציון משוקלל מכל שכבות הבדיקה. |
| document_type / issuer / channel | string | סוג המסמך, הגוף המנפיק (בנק/מעסיק/קופה) ומקור הקובץ (PDF מקורי, צילום מסך, צילום נייר…). |
| report.findings[] | array | ממצאים: category, severity (info/low/medium/high/critical), confidence (0–1), כותרת, פירוט ו-box. |
| report.checks[] | array | בדיקות דטרמיניסטיות: חשבון, יתרות, מע״מ, IBAN, ספרת ביקורת ת״ז, קוד בנק, יום בשבוע ועוד — pass/warn/fail. |
| report.extracted | object | נתונים שחולצו: סכומים, תאריכים, שמות, חשבונות, תנועות. |
| label | enum | null | תיוג אנושי שלכם (genuine/fraud), אם סומן בממשק. |
OpenAPI
המפרט המלא בפורמט OpenAPI 3.1 — לייבוא ל-Postman, Insomnia או לייצור SDK בכל שפה.