Fileverity-API-Dokumentation
Dokumentprüfungen in einem Eingangs-Workflow
Fügen Sie einem Eingangs-Workflow Dokumentprüfungen hinzu: hochladen, den Webhook empfangen, nach Risikostufe weiterleiten, Prüfung durch Menschen in die Warteschlange stellen, die Berichts-ID speichern und später verifizieren.
Diese Anleitung stellt Dokumentprüfungen vor einen Prozess, der Dokumente von außen entgegennimmt: Kreditanträge, Schadenmeldungen, Lieferanten-Onboarding oder Spesenabrechnungen. Jedes Dokument wird einmal geprüft, nach seiner Risikostufe weitergeleitet, und seine Berichts-ID wird als Audit-Nachweis aufbewahrt. Die API liefert eine Stufe und eine empfohlene Maßnahme. Ihre Richtlinie und die prüfenden Personen entscheiden.
Es verwendet das Modell fvdoc-3 mit den Aufrufen aus Dateien, Analysen und Webhooks. Mit einem Testschlüssel liefern Upload und Prüfung sofort ein Beispiel, aber es wird kein Webhook gesendet und es gibt kein Beispiel-PDF. Nutzen Sie Test senden bei einem Webhook-Endpunkt in der Konsole, um Ihren Empfänger auszuprobieren.
Der Ablauf
- Laden Sie die Datei mit
POST /fileshoch und starten Sie die Prüfung mitPOST /analyses. Tragen Sie Ihre Vorgangs-ID inmetadataein und senden Sie einenIdempotency-Key. - Antworten Sie Ihren Nutzern sofort. Dokumente können in eine Warteschlange kommen; halten Sie die Anfrage daher nicht offen. Der Webhook meldet Ihnen, wann die Prüfung abgeschlossen ist.
- Empfangen Sie
analysis.completedoderanalysis.failed, prüfen Sie die Signatur und stellen Sie einen Job in die Warteschlange. - Rufen Sie im Job die Analyse ab, leiten Sie sie anhand ihrer Zusammenfassung weiter und speichern Sie das Ergebnis und den PDF-Bericht beim Vorgang.
- Senden Sie Vorgänge, die von einer Person geprüft werden müssen, mit angehängtem PDF an eine Prüfwarteschlange.
- Verifizieren Sie den Bericht später anhand der gespeicherten Datei.
1. Hochladen und Prüfung starten
Dateien bis 4 MB werden als Multipart hochgeladen. Für größere Dateien bis 50 MB verwenden Sie einen Upload über eine vorsignierte URL, wie unter Dateien beschrieben. Das Erstellen der Analyse liefert 202 mit status: processing (ein Testschlüssel liefert 200 mit einem fertigen Beispiel), und Ihre metadata wird mit der Analyse und in jedem zugehörigen Webhook zurückgegeben.
FILE_ID=$(curl -s https://api.fileverity.com/v1/files \ -H "Authorization: Bearer $FILEVERITY_API_KEY" \ -H "Idempotency-Key: intake-A-10492-file" \ -F file=@application.pdf | jq -r .id) curl https://api.fileverity.com/v1/analyses \ -H "Authorization: Bearer $FILEVERITY_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: intake-A-10492-check" \ -d "{\"model\": \"fvdoc-3\", \"file\": \"$FILE_ID\", \"metadata\": {\"case_id\": \"A-10492\"}}"import { readFile } from "node:fs/promises";import { basename } from "node:path"; const base = "https://api.fileverity.com/v1";const auth = { Authorization: "Bearer " + process.env.FILEVERITY_API_KEY }; async function call(path, init) { const response = await fetch(base + path, init); const body = await response.json(); if (!response.ok) throw new Error(body.error.code + " (" + body.error.request_id + ")"); return body;} export async function submit(caseId, path) { const form = new FormData(); form.append("file", new Blob([await readFile(path)]), basename(path)); const file = await call("/files", { method: "POST", headers: { ...auth, "Idempotency-Key": `intake-${caseId}-file` }, body: form, }); return call("/analyses", { method: "POST", headers: { ...auth, "Content-Type": "application/json", "Idempotency-Key": `intake-${caseId}-check` }, body: JSON.stringify({ model: "fvdoc-3", file: file.id, metadata: { case_id: caseId } }), });}import osimport requests BASE = "https://api.fileverity.com/v1"HEADERS = {"Authorization": "Bearer " + os.environ["FILEVERITY_API_KEY"]} def call(method, path, **kwargs): headers = {**HEADERS, **kwargs.pop("headers", {})} response = requests.request(method, BASE + path, headers=headers, timeout=90, **kwargs) body = response.json() if not response.ok: raise RuntimeError(body["error"]["code"] + " (" + body["error"]["request_id"] + ")") return body def submit(case_id, path): with open(path, "rb") as source: file = call("POST", "/files", headers={"Idempotency-Key": f"intake-{case_id}-file"}, files={"file": source}) return call( "POST", "/analyses", headers={"Idempotency-Key": f"intake-{case_id}-check"}, json={"model": "fvdoc-3", "file": file["id"], "metadata": {"case_id": case_id}}, ){ "id": "an_8Hk2pQ4vN9sL1xR7cW3mY6zB", "object": "analysis", "created": 1793700120, "model": "fvdoc-3-2026-11-03", "livemode": true, "status": "processing", "file": { "name": "application.pdf", "bytes": 18874368, "format": "pdf" }, "report_id": null, "report_url": null, "summary": null, "result": null, "error": null, "progress": { "stage": "queued", "done": 0, "total": 0, "position": 1 }, "usage": { "amount": 599, "currency": "usd", "funding": "balance" }, "metadata": { "case_id": "A-10492" }, "completed_at": null, "expires_at": null}Speichern Sie id beim Vorgang. Da die Idempotenzschlüssel aus der Vorgangs-ID abgeleitet werden, liefert ein erneuter Aufruf von submit nach einem Timeout die ersten Antworten zurück, statt eine zweite Datei hochzuladen oder eine zweite Prüfung zu berechnen. Idempotenzschlüssel werden 24 Stunden lang aufbewahrt; siehe Idempotenz.
2. Das Ergebnis empfangen
Prüfen Sie die Signatur mit der Funktion verify aus Webhooks, gespeichert als verify.js oder verify.py. Antworten Sie schnell mit 2xx und erledigen Sie die Arbeit in einem Job. enqueue steht für Ihre eigene Job-Warteschlange. Speichern Sie jeden Job unter der Ereignis-ID, damit eine doppelte Zustellung keinen zweiten Job erzeugt.
import express from "express";import { verify } from "./verify.js"; const app = express(); app.post("/webhooks/fileverity", express.raw({ type: "application/json" }), async (req, res) => { let event; try { event = verify(process.env.FILEVERITY_WEBHOOK_SECRET, req.headers, req.body.toString("utf8")); } catch { return res.sendStatus(400); } if (event.type === "analysis.completed" || event.type === "analysis.failed") { await enqueue({ eventId: event.id, analysisId: event.data.id }); } res.sendStatus(200);});import os from fastapi import FastAPI, HTTPException, Request from verify import verify app = FastAPI() @app.post("/webhooks/fileverity")async def receive(request: Request): body = await request.body() try: event = verify(os.environ["FILEVERITY_WEBHOOK_SECRET"], request.headers, body) except (KeyError, ValueError): raise HTTPException(status_code=400) if event["type"] in ("analysis.completed", "analysis.failed"): enqueue(event["id"], event["data"]["id"]) return {"ok": True}3. Nach Risikostufe weiterleiten
summary ist die stabile, maschinenlesbare Einstufung einer Dokumentprüfung. level reicht von L1 bis L5, und action ist der empfohlene nächste Schritt. Leiten Sie anhand beider Felder weiter und behandeln Sie jeden Wert, den Sie nicht kennen, als Vorgang für eine Person.
| Zusammenfassung | Bedeutung | Beispiel für die Weiterleitung |
|---|---|---|
L1 oder L2, accept | Es wurden keine Anzeichen von Manipulation gefunden. L1 bedeutet, dass die Quelle verifiziert wurde. | Automatisch fortfahren. Berichts-ID speichern. |
L1 oder L2, note | Keine Anzeichen von Manipulation, aber im Bericht ist von KI verfasster Text oder eine KI-Kennzeichnung markiert. | Fortfahren und den Vorgang markieren, wenn Ihre Richtlinie von KI verfasste Inhalte einschränkt. |
L3, review | Erfordert manuelle Prüfung. | Reguläre Prüfwarteschlange. |
L4, review | Hohes Risiko. | Vorrangige Prüfwarteschlange. |
L5, reject | Im Bericht sind Probleme nachgewiesen. | Vorrangige Prüfwarteschlange. Eine Person bestätigt, bevor etwas abgelehnt wird. |
status ist failed oder canceled | Die Prüfung wurde nicht abgeschlossen, und Ihnen wurde nichts berechnet. | Das gespeicherte Original erneut hochladen oder den Vorgang an eine Person übergeben. |
Die Zuordnung folgt Ihrer eigenen Richtlinie. Ändern Sie die Funktion, um L3 in die vorrangige Warteschlange zu legen oder note zur Prüfung weiterzuleiten. Zu den möglichen Aktionen gehört außerdem resubmit, das die Funktion als Anforderung einer weiteren Kopie der Datei behandelt. Jedes Feld der Zusammenfassung ist unter Analysen beschrieben.
export function route(analysis) { if (analysis.status !== "succeeded") return "manual"; const { action, level } = analysis.summary; if (action === "accept") return "accept"; if (action === "note") return "accept_with_note"; if (action === "resubmit") return "request_new_copy"; if (action === "reject" || level === "L4" || level === "L5") return "priority_review"; return "review";}def route(analysis): if analysis["status"] != "succeeded": return "manual" action = analysis["summary"]["action"] level = analysis["summary"]["level"] if action == "accept": return "accept" if action == "note": return "accept_with_note" if action == "resubmit": return "request_new_copy" if action == "reject" or level in ("L4", "L5"): return "priority_review" return "review"4. Berichts-ID und PDF speichern
Der Job ruft die Analyse ab, leitet sie weiter und speichert, was Sie später brauchen. Er verwendet call, route und die Zugangsdaten aus den vorherigen Schritten erneut, und saveCase und saveReport stehen für Ihren eigenen Speicher. Laden Sie das PDF im selben Job herunter: Das Analyseergebnis wird 7 Tage lang aufbewahrt, die Seitenbilder und Textauszüge eines Dokuments 3 Stunden lang, und Fileverity bewahrt danach nur den Verifizierungsdatensatz auf, nicht den vollständigen Bericht.
export async function handleResult(analysisId) { const analysis = await call(`/analyses/${analysisId}`, { headers: auth }); const decision = route(analysis); await saveCase(analysis.metadata.case_id, { analysisId: analysis.id, reportId: analysis.report_id, reportUrl: analysis.report_url, summary: analysis.summary, model: analysis.model, decision, }); if (analysis.status === "succeeded") { const pdf = await fetch(`${base}/analyses/${analysis.id}/report.pdf`, { headers: auth }); await saveReport(analysis.report_id, Buffer.from(await pdf.arrayBuffer())); } return decision;}def handle_result(analysis_id): analysis = call("GET", f"/analyses/{analysis_id}") decision = route(analysis) save_case(analysis["metadata"]["case_id"], { "analysis_id": analysis["id"], "report_id": analysis["report_id"], "report_url": analysis["report_url"], "summary": analysis["summary"], "model": analysis["model"], "decision": decision, }) if analysis["status"] == "succeeded": pdf = requests.get(f"{BASE}/analyses/{analysis['id']}/report.pdf", headers=HEADERS, timeout=90) pdf.raise_for_status() save_report(analysis["report_id"], pdf.content) return decisionreport_id(FV-XXXX-XXXX-XXXX) ist der Schlüssel zum Audit-Nachweis. Speichern Sie sie beim Vorgang, in Ihrer Datenbank und auf jedem Entscheidungsschreiben.modelist der datierte Snapshot, der das Ergebnis erzeugt hat, sodass Sie später genau sagen können, welche Version das Dokument geprüft hat.- Bewahren Sie die Originaldatei in Ihrem eigenen Speicher auf. Fileverity löscht eine hochgeladene Datei, sobald die Analyse beginnt, und nach einer fehlgeschlagenen Prüfung ist ein neuer Upload nötig. Siehe Datenaufbewahrung und Sicherheit.
5. Die Warteschlange für die Prüfung durch Menschen betreiben
Legen Sie pro weitergeleitetem Vorgang eine Aufgabe an. Geben Sie der prüfenden Person alles, was sie für eine Entscheidung braucht, ohne die API erneut aufzurufen:
- Die Vorgangs-ID,
level,action,reasonund die Befund-IDs infindings, mit angehängtem PDF-Bericht. Das PDF listet jeden Befund mit Fundstelle und Beleg auf. - Die Originaldatei, die Sie gespeichert haben.
report_url, die öffentliche Verifizierungsseite. Sie bestätigt den Berichtsdatensatz und den Fingerabdruck der Datei, ersetzt aber nicht die Lektüre des Berichts.
Halten Sie die prüfende Person, die Entscheidung und den Zeitpunkt in Ihrem eigenen System neben report_id fest.
Eine unauffällige Prüfung ist kein Beweis dafür, dass ein Dokument echt ist, und ein Befund ist kein Beweis für Betrug. Lehnen Sie einen Vorgang nicht allein auf Grundlage des API-Ergebnisses ab. Bei Einkommens-, Identitäts- oder Eigentumsnachweisen bestätigen Sie die Angaben beim Aussteller über einen Kontakt, den Sie selbst recherchiert haben. Der Ratgeber zum Erkennen gefälschter und KI-generierter Dokumente zeigt, was je Dokumenttyp zu prüfen ist.
6. Den Bericht später verifizieren
Monate später können Auditoren oder Kunden den Datensatz ohne Fileverity-Konto prüfen. Öffnen Sie die gespeicherte report_url. Sie zeigt die Berichtsart, den festgehaltenen Befund und den nächsten Schritt, den SHA-256-Fingerabdruck der untersuchten Datei und den RFC-3161-Zeitstempel. Ziehen Sie Ihr gespeichertes Original auf die Seite, dann berechnet Ihr Browser dessen SHA-256-Hash und vergleicht ihn mit dem Datensatz; es wird nichts hochgeladen. Jede erneut gespeicherte, konvertierte oder bearbeitete Kopie ergibt einen anderen Fingerabdruck.
Denselben Vergleich können Sie in Ihrem eigenen System durchführen:
sha256sum application.pdfimport { createHash } from "node:crypto";import { readFile } from "node:fs/promises"; const digest = createHash("sha256").update(await readFile("application.pdf")).digest("hex");console.log(digest);import hashlib print(hashlib.sha256(open("application.pdf", "rb").read()).hexdigest())Die Verifizierung analysiert die Datei nicht erneut und bescheinigt nicht, dass ein Dokument authentisch ist. Sie hält fest, welche Datei untersucht wurde, was der Bericht ergab und wann. Der vollständige Bericht existiert nur in dem PDF, das Sie gespeichert haben. Die Felder des Berichts sind im Abschnitt Das Berichtsobjekt beschrieben.
Bevor Sie live gehen
- Entwickeln Sie zunächst mit einem Testschlüssel. Er liefert sofort ein Beispiel, Stufe
L2mit Maßnahmeaccept, ohne das Modell auszuführen. Webhooks und der PDF-Download erfordern einen Live-Schlüssel, den Sie mit Ihrem kostenlosen Start ausprobieren können. Übergeben Sie die anderen Zusammenfassungen aus Analysen anroute, um jeden Zweig zu testen. - Behandeln Sie
503 service_unavailable: Warten Sie die Sekunden ausretry-afterab und wiederholen Sie die Anfrage mit demselbenIdempotency-Key. Siehe Wenn der Dienst ausgelastet ist. - Legen Sie für den Schlüssel ein monatliches Ausgabenlimit fest und richten Sie einen Webhook für
balance.lowein, damit der Eingangs-Workflow nicht mitinsufficient_balancestoppt. Siehe Preise und Abrechnung. - Rufen Sie die API von Ihrem Server aus auf und bewahren Sie Schlüssel in einem Secrets-Manager auf, nie in Browser-Code.
- Geben Sie den Wert des Headers
x-request-idan, wenn Sie den Support kontaktieren.