Die Dokumenten-API
Authentifizierung, der Erzeugungs-Endpunkt, das Eingabeformat, Fehlersemantik und was berechnet wird.
Die Dokumenten-API erzeugt Dokumente von außerhalb der App: Ihr System liefert Werte, Final Wording wendet sie auf die verwaltete Vorlage an. Sie ist bewusst klein – ein PDF rendern, ein Dokument aus einer Vorlage auflösen oder anlegen, und das Schema, das die Eingaben beschreibt.
Authentifizierung
Authorization: Bearer <workspace_api_token>
Ein Token gehört zu genau einem Arbeitsbereich. Behandeln Sie es als arbeitsbereichsweites Lese- und Render-Recht: Wer es hält, kann jede Dokumentversion dieses Arbeitsbereichs finden und rendern und beliebige Eingabewerte liefern. Bewahren Sie es entsprechend auf – es gehört in einen Secrets-Manager, nicht in ein Repository.
Administratoren des Arbeitsbereichs stellen Tokens unter Arbeitsbereichseinstellungen → API-Tokens aus: Erstellen Sie ein benanntes Token – benennen Sie es nach der Integration, die es verwenden wird – und kopieren Sie das Secret. Es wird genau einmal angezeigt und nur als Hash gespeichert. Dieselbe Liste zeigt zu jedem Token, wer es erstellt hat, wann es zuletzt verwendet wurde und was es erzeugt hat, und widerruft ein Token mit sofortiger Wirkung. Rotation ist gewollte Überlappung: Erst den Ersatz erstellen, dann die Aufrufer umstellen, dann das alte Token widerrufen – zwei aktive Tokens während des Wechsels sind vorgesehen.
Ein fehlendes, ungültiges oder widerrufenes Token ist ein 401; eine Version
außerhalb des Arbeitsbereichs, zu dem das Token gehört, ein 404 –
ununterscheidbar von einer Version, die es nicht gibt.
Ein PDF erzeugen
POST /api/v1/document-generations/pdf
Authorization: Bearer <workspace_api_token>
Idempotency-Key: <optional>
Content-Type: application/json
{
"document_version_key": "<document_version_key>",
"inputs": { "fields": { "customer_name": { "textValue": "Grace Hopper" } } }
}
Ein erfolgreicher Render liefert das PDF selbst:
200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="<Dokumentname>.pdf"
inputs ist optional. Fehlt es, rendert die Version aus den auf ihr
gespeicherten Werten. Ist es vorhanden, ersetzt es die gespeicherten
Werte für genau diesen Render: Nichts wird ins Dokument zurückgeschrieben,
und es gibt keine Teil-Zusammenführung – ein vorhandenes inputs-Objekt ist
der vollständige Wertesatz, ein Pflichtfeld, das auf der Version gespeichert
ist, muss also erneut mitgeliefert werden.
Das Eingabeformat
inputs ist ein Objekt mit einer einzigen fields-Map, deren Schlüssel die
Feldnamen der Vorlage sind. Jeder Wert nennt seinen Typ explizit:
| Feldtyp der Vorlage | Wert |
|---|---|
| Text | {"textValue": "…"} |
| Ja/Nein | {"booleanValue": true} |
| Dezimalzahl | {"decimalValue": "1200.50"} – exakt, als String |
| Datum | {"dateValue": "2026-07-28"} – ISO-Datum, ohne Zone |
| Objekt | {"objectValue": {"fields": { … }}} |
| Liste | {"listValue": {"items": [ … ]}} |
| null (optional) | {"nullValue": true} |
Der maßgebliche Vertrag ist maschinenlesbar – erzeugen Sie Ihre Typen daraus, statt Feldnamen hart zu kodieren:
GET /api/v1/document-versions/{document_version_key}/input-schema
Authorization: Bearer <workspace_api_token>
liefert ein JSON Schema (Draft 2020-12), das exakt die Felder dieser Version beschreibt, einschließlich Pflichtfeldern und Typisierung.
Ein Dokument aus einer Vorlage anlegen
Zwei Endpunkte arbeiten mit einer angehefteten Vorlagenversion und natürlichen
bindings – schlichte JSON-Werte je Feldname, ohne die typisierten Hüllen:
POST /api/v1/document-versions/{document_version_key}/resolve
POST /api/v1/document-versions/{document_version_key}/documents
resolve wendet Ihre Bindings an und meldet jede Diagnose, ohne etwas
anzulegen – der Probelauf, gegen den eine Integration testet. documents
legt ein gewöhnliches bearbeitbares Dokument (samt Erstversion) in einem
ausdrücklich benannten Projekt an; project_key und ein nicht leerer name
sind Pflicht, ebenso ein Idempotency-Key – denn doppelt anlegen ist
schlimmer als doppelt rendern. Im angelegten Dokument sind Bedingungen und
Wiederholungen vollständig ausmaterialisiert: Es ist von da an ein normales
Dokument und durchläuft Kommentare, Freigaben und Erzeugung wie jedes andere.
Das Anlegen hat eine Grenze, die die Render-Endpunkte nicht haben: Der mit dem
Token verknüpfte Benutzer muss im Zielprojekt aktuell mindestens
Bearbeiter-Zugriff halten; fällt dieser Zugriff weg, schlägt das Anlegen mit
403 fehl – bewusst geschlossen.
Fehler bedeuten zweierlei
400,401,404,405– die Anfrage selbst ist falsch: kaputtes JSON, unbekannte Felder, ein schlechtes Token, eine falsche URL. Korrigieren Sie den Aufrufer.422 Unprocessable Entity– die Anfrage war in Ordnung, aber das Dokument lässt sich mit diesen Werten nicht auflösen: ein fehlendes Pflichtfeld, ein missratenes Datum, ein Wert der falschen Art. Der Body listet jeden auffindbaren Fehler als Diagnose mit stabilemcodeund dem Pfad des betroffenen Werts. Ein422heißt „Eingaben oder Dokument korrigieren“, nie „erneut versuchen“ – dieselbe Anfrage scheitert genauso wieder.500– ein unerwarteter Render-Fehler auf unserer Seite. Ein erneuter Versuch ist vernünftig.
Eine Feinheit, die man kennen sollte: Eine weggelassene optionale Liste ist
eine gültige leere Sammlung – die Wiederholung erzeugt null Vorkommen. Ein
explizites null ist eine andere Aussage und wird als Wiederholungsquelle
abgelehnt.
Abrechnung und Wiederholungen
Berechnet wird ein Render erst nach Erfolg: einmal je erzeugtem Dokument plus
einmal je gerenderter Seite, gezählt ab Seite eins. Ein gescheiterter Render –
jedes 4xx oder 5xx – wird nie berechnet.
Senden Sie einen Idempotency-Key bei Anfragen, die Sie wiederholen könnten.
Ein wiederholter Key rendert erneut und liefert das PDF wieder aus, erzeugt
aber keine zweite Belastung – eine Timeout-und-Retry-Schleife kann nicht
doppelt abrechnen.
Was die API bewusst nicht tut
- Sie wartet nicht auf Freigaben. Eine Version mit offenen verlangten
Freigaben rendert trotzdem – mit demselben
DRAFT · UNAPPROVED-Aufdruck, den auch der Export in der App trüge. - Sie nimmt keine Auflösungs-Limits vom Aufrufer entgegen: Wiederholungstiefe,
Listengrößen und Ausgabegröße begrenzt allein der Server; ein
limits-Schlüssel wird als unbekannt abgelehnt. Der Request-Body ist auf 4 MiB begrenzt. - Rendern schreibt keine Werte ins Dokument zurück – gelieferte
inputsändern einen Render, nicht die Aufzeichnung. Ein Dokument anzulegen ist ein eigener, ausdrücklicher Endpunkt und nie Nebenwirkung des Renderns.
Eine Anfrage, die durchgehend funktioniert
curl -sS -X POST https://app.finalwording.com/api/v1/document-generations/pdf \
-H "Authorization: Bearer $FW_API_TOKEN" \
-H "Idempotency-Key: rechnung-2026-08-04-0001" \
-H "Content-Type: application/json" \
-d '{
"document_version_key": "'"$VERSION_KEY"'",
"inputs": { "fields": {
"customer_name": { "textValue": "Grace Hopper" },
"signed_on": { "dateValue": "2026-07-28" },
"fee": { "decimalValue": "1200.50" }
} }
}' \
-o vertrag.pdf
$VERSION_KEY benennt die freigegebene Dokumentversion, auf der Ihre Vorlage
liegt; die Antwort in vertrag.pdf ist dasselbe PDF, das der App-Export
dieser Version mit diesen Werten erzeugen würde.