API-Dokumentation
Mit der Snapfritz-API lässt sich der PDF-Dienst aus eigener Software oder von einem autonomen Agenten nutzen: PDF hochladen, ausgelesene Felder prüfen und bestätigen, unterschreiben und das fertige PDF laden.
Überblick
- Basis-URL
https://snapfritz.com/api/v1- Format
- JSON (UTF-8); Upload als multipart/form-data oder application/pdf
- Tarif
- Platin – ohne Platin antworten Aufrufe mit 403 plan_required
- Version
- v1 – Erweiterungen kommen abwärtskompatibel dazu
Der Ablauf besteht immer aus denselben Schritten:
- Hochladen – die Felder werden sofort ausgelesen
- Felder prüfen und bestätigen (oder an einen Menschen übergeben)
- Signieren
- Fertiges PDF herunterladen
Authentifizierung
Jede Anfrage trägt einen API-Schlüssel im Header Authorization. Schlüssel legen Sie unter Entwickler an; sie werden nur einmal angezeigt und bei uns nur als Hash gespeichert. Ein Schlüssel gehört zu genau einem Konto und darf nur, was seine Scopes erlauben.
Authorization: Bearer sf_live_…| Scope | Erlaubt |
|---|---|
documents:read | Dokumente und Felder lesen, Kontingent abfragen, signiertes PDF herunterladen |
documents:write | PDFs hochladen, Felder bestätigen, Checkbox-Optionen wählen |
documents:sign | Dokumente mit der gespeicherten Unterschrift des Kontos signieren – standardmäßig aus |
Behandeln Sie den Schlüssel wie ein Passwort: nie in Code-Repositories oder Client-Apps ablegen. Bei Verdacht unter Entwickler widerrufen und neu anlegen.
Schnellstart
Ein vollständiger Durchlauf. Ersetzen Sie $DOC und $FIELD durch die IDs aus der Antwort.
export SNAPFRITZ_API_KEY=sf_live_…
# 1. upload
curl -s -X POST https://snapfritz.com/api/v1/documents \
-H "Authorization: Bearer $SNAPFRITZ_API_KEY" \
-F file=@formular.pdf
# 2. confirm a field (omit "value" to accept the suggestion)
curl -s -X POST https://snapfritz.com/api/v1/documents/$DOC/fields/$FIELD/confirm \
-H "Authorization: Bearer $SNAPFRITZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"value": "Erika Muster"}'
# 3. sign (needs the documents:sign scope)
curl -s -X POST https://snapfritz.com/api/v1/documents/$DOC/sign \
-H "Authorization: Bearer $SNAPFRITZ_API_KEY"
# 4. download the filled PDF
curl -s https://snapfritz.com/api/v1/documents/$DOC/download \
-H "Authorization: Bearer $SNAPFRITZ_API_KEY" -o ausgefuellt.pdfDasselbe als Python-Skript
Bestätigt sicher erkannte Felder automatisch und übergibt alles Unsichere an einen Menschen.
import os
import requests
BASE = "https://snapfritz.com/api/v1"
H = {"Authorization": f"Bearer {os.environ['SNAPFRITZ_API_KEY']}"}
with open("formular.pdf", "rb") as f:
doc = requests.post(f"{BASE}/documents", headers=H, files={"file": f}, timeout=120)
doc.raise_for_status()
doc = doc.json()
if doc["status"] == "failed":
raise SystemExit("PDF not readable")
for field in doc["fields"]:
if field["confirmed"] or field["state"] in ("not_applicable", "out_of_scope"):
continue
if field["state"] != "ok":
# unsure / missing / hand: decide yourself or hand over to a human
raise SystemExit(f"Needs a decision: {field['label']} -> {doc['reviewUrl']}")
requests.post(f"{BASE}/documents/{doc['id']}/fields/{field['id']}/confirm",
headers=H, json={}).raise_for_status()
requests.post(f"{BASE}/documents/{doc['id']}/sign", headers=H).raise_for_status()
pdf = requests.get(f"{BASE}/documents/{doc['id']}/download", headers=H)
open("ausgefuellt.pdf", "wb").write(pdf.content)Beispielantwort des Uploads
Gekürzt auf ein Feld; Werte sind Beispiele.
{
"id": "3f0c2d5e-8a4b-4f0e-9c1a-2b7d6e5f4a31",
"filename": "formular.pdf",
"title": "Anmeldung",
"documentType": "registration",
"status": "ready_for_review",
"pageCount": 2,
"requiresStrongerSignature": false,
"requiresStrongerSignatureReason": null,
"createdAt": "2026-09-25T13:04:11.000Z",
"signedAt": null,
"sentAt": null,
"downloadable": false,
"reviewUrl": "https://snapfritz.com/documents/3f0c2d5e-8a4b-4f0e-9c1a-2b7d6e5f4a31",
"fields": [
{
"id": "b1f7c8a0-52de-4c1e-8f3a-9d0e7a6b5c42",
"page": 1,
"type": "text",
"label": "Nachname",
"semanticKey": "last_name",
"state": "ok",
"value": "Muster",
"source": "profile",
"confirmed": false,
"checkboxGroup": null
}
]
}Endpunkte
Alle Pfade beziehen sich auf die Basis-URL. IDs sind UUIDs; fremde oder ungültige IDs antworten mit 404.
GET/usage
Kontingent im aktuellen Zeitraum
Zeigt, wie viele Formulare schon fertiggestellt wurden und wie viele bleiben; unter „uploads“ dasselbe für hochgeladene PDFs.
Antworten
- 200 Erfolgreich
GET/documents
Dokumente auflisten, neueste zuerst
Parameter
| Name | in | Typ | Beschreibung |
|---|---|---|---|
limit | query | integer | optional · 1–100, default 25 |
offset | query | integer | optional · default 0 |
status | query | DocumentStatus | optional |
Antworten
- 200 Erfolgreich
POST/documents
PDF hochladen und Felder auslesen
Die Extraktion läuft synchron und dauert meist 10–60 Sekunden; die Antwort enthält das fertige Dokument mit allen Feldern. Senden Sie entweder multipart/form-data mit dem Teil „file“ oder das rohe PDF als application/pdf (Dateiname über den Header X-Filename). Maximal 20 MB und 20 Seiten. Jeder Upload zählt zum Upload-Kontingent; nicht lesbare Scans enden mit dem Status „failed“ und zählen nicht.
Request-Body
multipart/form-data (Teil „file“) oder application/pdf
Antworten
- 201 Angelegt
- 402 Upload-Kontingent aufgebraucht (quota_exceeded)
- 413 Datei zu groß
- 415 Kein PDF
- 422 Mehr Seiten, als ein Formular haben darf (too_many_pages)
- 429 Zu viele Uploads (10 pro Minute und Schlüssel)
GET/documents/{id}
Ein Dokument mit seinen Feldern
Parameter
| Name | in | Typ | Beschreibung |
|---|---|---|---|
id | path | string (uuid) | Pflicht |
Antworten
- 200 Erfolgreich
- 404 Nicht gefunden
POST/documents/{id}/fields/{fieldId}/confirm
Feld bestätigen, optional mit geändertem Wert
Ohne „value“ wird der Vorschlag unverändert übernommen. „null“ oder ein leerer String leert das Feld.
Parameter
| Name | in | Typ | Beschreibung |
|---|---|---|---|
id | path | string (uuid) | Pflicht |
fieldId | path | string (uuid) | Pflicht |
Request-Body
{ "value": "Erika Muster" } – optional
Antworten
- 200 Erfolgreich
- 404 Nicht gefunden
POST/documents/{id}/checkbox-groups/select
Eine Option einer Checkbox-Gruppe wählen
Alle anderen Optionen der Gruppe werden auf „not_applicable“ gesetzt.
Parameter
| Name | in | Typ | Beschreibung |
|---|---|---|---|
id | path | string (uuid) | Pflicht |
Request-Body
{ "fieldId": "<uuid>" }
Antworten
- 200 Erfolgreich
- 404 Nicht gefunden
- 422 Das Feld gehört zu keiner Checkbox-Gruppe
POST/documents/{id}/sign
PDF ausfüllen und Unterschrift aus dem Profil setzen
Braucht den Scope documents:sign (standardmäßig aus). Antwortet mit 409, solange Felder unbestätigt sind, und mit 422, wenn das Dokument eine stärkere Signatur verlangt, als wir liefern können, oder keine Unterschrift hinterlegt ist. Das Fertigstellen zählt ein Formular zum Kontingent (eine wieder geöffnete Kopie nicht): 402, wenn es aufgebraucht ist, 403 „plan_required“, wenn der Tarif das Unterschreiben im Namen der Organisation nicht enthält. Bei einem bereits signierten Dokument idempotent.
Parameter
| Name | in | Typ | Beschreibung |
|---|---|---|---|
id | path | string (uuid) | Pflicht |
Antworten
- 200 Erfolgreich
- 402 Allowance of finished forms used up, and additional forms off or at their cap (`quota_exceeded`)
- 403 Tarif ohne Unterschreiben im Namen der Organisation (plan_required)
- 409 Noch nicht signierbar (unbestätigte Felder)
- 422 Lässt sich nicht automatisch signieren
GET/documents/{id}/download
Das ausgefüllte, signierte PDF
Antwortet mit 409 „not_signed“, solange kein signiertes PDF existiert.
Parameter
| Name | in | Typ | Beschreibung |
|---|---|---|---|
id | path | string (uuid) | Pflicht |
Antworten
- 200 Erfolgreich
- 409 Noch nicht signiert
Maschinenlesbare Beschreibung für Client-Generatoren und Agenten-Frameworks: OpenAPI 3.1 (JSON)
Objekte
Das öffentliche Format eines Dokuments und seiner Felder. Interne Angaben wie Speicherorte sind bewusst nicht enthalten.
Dokument
| Name | Typ | Beschreibung |
|---|---|---|
id | uuid | Dokument-ID |
filename | string | Name der hochgeladenen Datei |
title | string | null | Erkannter Titel des Formulars |
documentType | string | null | Erkannte Dokumentart |
status | string | Bearbeitungsstand, siehe unten |
pageCount | integer | null | Seitenzahl |
requiresStrongerSignature | boolean | true: braucht mehr als eine einfache elektronische Signatur – Signieren per API wird abgelehnt |
requiresStrongerSignatureReason | string | null | Begründung dazu |
createdAt / signedAt / sentAt | date-time | null | ISO 8601 |
downloadable | boolean | true, sobald ein signiertes PDF abrufbar ist |
reviewUrl | uri | Prüfansicht im Browser – hierhin übergeben Sie, wenn ein Mensch entscheiden soll |
fields | Field[] | Nur bei einzelnem Dokument und Upload enthalten |
Feld
| Name | Typ | Beschreibung |
|---|---|---|
id | uuid | Feld-ID |
page | integer | Seite im PDF |
type | text | date | checkbox | signature | |
label | string | Beschriftung im Formular |
semanticKey | string | null | Bedeutung, z. B. der Profilwert, aus dem befüllt wurde |
state | string | Verlässlichkeit, siehe unten |
value | string | null | Vorgeschlagener oder bestätigter Wert |
source | profile | learned_cache | user_input | none | Woher der Wert stammt |
confirmed | boolean | Erst wenn alle relevanten Felder bestätigt sind, kann signiert werden |
checkboxGroup | string | null | Gleicher Wert = Optionen schließen sich gegenseitig aus |
Feld-Status (state)
ok | Sicher erkannt und befüllt. |
unsure | Vorschlag vorhanden, aber unsicher – bitte prüfen. |
missing | Kein Wert bekannt – muss geliefert werden. |
hand | Handschriftlich oder nicht maschinell lesbar – besser einem Menschen übergeben (reviewUrl). |
not_applicable | Trifft hier nicht zu (z. B. abgewählte Checkbox-Option); muss nicht bestätigt werden. |
out_of_scope | Wird nicht von Snapfritz befüllt; muss nicht bestätigt werden. |
Dokument-Status (status)
received | Eingegangen, wird verarbeitet. |
understanding | Dokumentart wird erkannt. |
extracting | Felder werden ausgelesen. |
ready_for_review | Fertig ausgelesen – Felder bestätigen. |
in_review | Wird gerade im Browser geprüft. |
signed | Signiert; das PDF ist abrufbar. |
sent | Signiert und versendet. |
revoked | Widerrufen. |
failed | Nicht lesbar; zählt nicht zum Kontingent. |
Fehler
Fehler haben immer diese Form; der code ist stabil und für Programme gedacht, die message für Menschen:
{ "error": { "code": "not_found", "message": "Document not found." } }| HTTP | code | Bedeutung |
|---|---|---|
| 400 | invalid_json, invalid_parameter, missing_file | Fehlerhafte Anfrage |
| 401 | unauthorized | Schlüssel fehlt, ist unbekannt oder widerrufen |
| 402 | quota_exceeded | Kontingent des Zeitraums aufgebraucht – quota.kind sagt, ob fertige Formulare (forms) oder Uploads (uploads) |
| 403 | plan_required, insufficient_scope | Tarif ohne API-Zugang bzw. ohne Unterschreiben im Namen der Organisation, oder dem Schlüssel fehlt der Scope |
| 403 | forbidden | Das Dokument ist mit Ihnen nur zum Ansehen bzw. Ausfüllen geteilt |
| 403 | key_owner_left | Wer den Schlüssel angelegt hat, gehört nicht mehr zur Organisation – neuen Schlüssel anlegen |
| 404 | not_found | Unbekannte, ungültige oder fremde ID – auch ein nicht mit Ihnen geteiltes Dokument der Organisation |
| 409 | conflict, not_signed | Falscher Zustand, z. B. unbestätigte Felder oder noch nichts zum Herunterladen |
| 413 / 415 | payload_too_large, not_a_pdf, unsupported_media_type | Ungeeigneter Upload |
| 422 | invalid, too_many_pages | Lässt sich nicht automatisch erledigen (stärkere Signatur nötig, keine Unterschrift hinterlegt …) bzw. PDF mit mehr als 20 Seiten (Felder pages und limit) |
| 429 | rate_limited | Zu viele Anfragen – Header Retry-After beachten |
| 500 | internal_error | Fehler auf unserer Seite – später erneut versuchen |
HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"error": {
"code": "quota_exceeded",
"message": "The plan's upload allowance for this period is used up.",
"quota": { "kind": "uploads", "plan": "platin", "used": 200, "limit": 200, "resetsAt": "2026-10-25T00:00:00.000Z" }
}
}Limits & Kontingent
- 60 Anfragen pro Minute und Schlüssel, davon höchstens 10 Uploads. Darüber: 429 mit Retry-After (Sekunden); jede Antwort trägt X-RateLimit-Header.
- PDFs bis 20 MB und 20 Seiten. Der Tarif zählt fertige Formulare (jedes erfolgreiche Signieren) und, doppelt so viele, hochgeladene lesbare PDFs.
- Ist eins davon aufgebraucht, antworten Upload bzw. Signieren mit 402 quota_exceeded. Es wird nichts nachberechnet. GET /usage zeigt vorab, wie viel bleibt und wann es sich erneuert.
- Die Extraktion läuft synchron im Upload-Request und dauert je nach Umfang bis zu etwa einer Minute – Timeout im Client entsprechend hoch setzen (≥ 120 s).
- Alle Aktionen mit einem Schlüssel erscheinen im Protokoll des Kontos als „API-Schlüssel <Präfix>“.
Für Agenten
- Prüfen Sie state und confirmed jedes Felds. Nur ok automatisch bestätigen; bei unsure, missing und hand entscheiden Sie selbst oder übergeben an einen Menschen über reviewUrl.
- Rufen Sie vor dem Upload GET /usage ab, um 402 zu vermeiden.
- Bei 429 den Header Retry-After abwarten, bei 5xx mit Backoff wiederholen. POST …/sign ist idempotent; Uploads sind es nicht – nach einem Timeout zuerst GET /documents prüfen, statt blind neu hochzuladen.
- Vergeben Sie documents:sign nur an Schlüssel, die wirklich unterschreiben sollen, und trennen Sie Lese- von Schreibschlüsseln.
- Dokumente mit requiresStrongerSignature = true lassen sich nicht per API signieren – sie gehören in die Prüfansicht.