apitemplate.io-Kompatibilitätsendpunkte
Der Kompatibilitäts-Shim lässt eine bestehende apitemplate.io-Integration durch Ändern der Basis-URL und des
Schlüssels umziehen. Er deckt die vier Endpunkte ab, die die meisten Integrationen nutzen, und antwortet
im Format von apitemplate.io (status, download_url, transaction_ref). Er ist für die Migration gedacht:
Neue Funktionen erscheinen nur auf den nativen Endpunkten, und der Shim hat keine Ausnahmen bei Rate-Limits
oder Kontingenten. Jeder Aufruf ist ein normales Rendering: Er braucht den Scope
render:create, zählt gegen das Rate-Limit, kostet Einheiten
wie ein natives Rendering und erscheint im Render-Protokoll.
| apitemplate.io | Formfeed-Shim | Natives Gegenstück |
|---|---|---|
POST https://rest.apitemplate.io/v2/create-pdf?template_id=… | POST https://api-eu.formfeed.dev/v1/compat/apitemplate/create-pdf?template_id=<slug> | POST /v1/renders mit template |
POST …/v2/create-image?template_id=…&output_image_type=… | POST …/v1/compat/apitemplate/create-image?template_id=<slug>&output_image_type=1 (oder 2, all) | POST /v1/renders mit output: jpg oder png |
POST …/v2/create-pdf-from-html | POST …/v1/compat/apitemplate/create-pdf-from-html | POST /v1/renders mit html und engine: jinja2 |
POST …/v2/create-pdf-from-url | POST …/v1/compat/apitemplate/create-pdf-from-url | POST /v1/renders mit url |
Was sich ändert
-
Schlüssel: Der Header
X-API-KEYbleibt; senden Sie darin einen Formfeed-Schlüssel (ff_live_…, oderff_test_…, um es kostenlos auszuprobieren) oder nutzen SieAuthorization: Bearer ff_live_…. -
Vorlagen-IDs: Vorlagen, die Sie mit Ihrem apitemplate.io-API-Schlüssel importiert haben (Vorlagen → Importieren → apitemplate.io → Mit API-Schlüssel), merken sich ihre apitemplate.io-ID,
template_idbleibt also unverändert. Formfeed sucht den Wert zuerst als eine solche ID, dann als Slug,tpl_…-ID oder UUID der Vorlage; Vorlagen, die Sie in Formfeed angelegt haben, brauchen eines davon. Eine Suche wird eine Minute zwischengespeichert, eine gerade importierte oder archivierte Vorlage reagiert also innerhalb dieser Minute auf ihre alte ID. Eine archivierte Vorlage reagiert nicht mehr auf ihre alte ID; erneut importiert übernimmt die neue Kopie sie. -
Veröffentlichte Version: Die Endpunkte rendern die veröffentlichte Version, veröffentlichen Sie also jeden importierten Entwurf zuerst. Eine Vorlage ohne veröffentlichte Version antwortet mit
404. -
Body:
create-pdfundcreate-imagenehmen die Vorlagendaten als JSON-Body, genau wie zuvor; ein Body, der kein JSON-Objekt ist, zählt als keine Daten.create-pdf-from-htmlnimmtbody(das HTML, als Jinja2-Vorlage gerendert),css(als<style>-Block davor gesetzt),dataundsettings;create-pdf-from-urlnimmturlundsettings. Query-Parameter außertemplate_id,output_image_typeundexport_typewerden ignoriert. -
Einstellungen (nur
create-pdf-from-htmlundcreate-pdf-from-url;create-pdfundcreate-imagenutzen die mit der Vorlage gespeicherten Einstellungen) werden auf Formfeed-Einstellungen abgebildet:apitemplate.io Formfeed paper_sizepaper.format:A3,A4,A5,Letter,Legal,Tabloid,Ledger; jede andere Größe rendert als A4custom_width,custom_heightpaper.width,paper.height; eine Zahl ohne Einheit ist Millimeterorientationpaper.landscape(landscapeoder2)margin_top,margin_right,margin_bottom,margin_leftmargin; eine Zahl ohne Einheit ist CSS-Pixel, wie Chromium sie liest, und Längen mit Einheit (10mm) bleiben, wie sie sindheader_template,footer_templateheader.html,footer.html;{{pageNumber}},{{totalPages}},{{date}},{{title}}und{{url}}werden zu den Seitenfeldern von Chromium, und das Markup wird um 4/3 skaliert, die Größe, in der apitemplate.io es zeichnetdisplayHeaderFooterfalselässt Kopf- und Fußzeile wegprint_background,scale,page_ranges,prefer_css_page_sizeprintBackground,scale,pageRanges,preferCssPageSizeSchlüssel ohne Gegenstück werden ignoriert. Siehe die Referenz der Einstellungen.
-
output_image_type(create-image):1(der Standard) oderjpegOnlyrendert ein JPEG und liefert es indownload_url,2oderpngOnlyein PNG indownload_url_png,allbeides. Das jeweils andere Feld istnull.allerzeugt zwei Renderings und kostet beide. Jeder andere Wert ergibt400 invalid_requestund rendert nichts. -
Antwort:
status: "success",download_url,transaction_ref(die Formfeed-Render-ID, nutzbar mitGET /v1/renders/{id}),total_pages(nullbei Bildern) und beicreate-pdfundcreate-imagedietemplate_id, die Sie gesendet haben.download_urlist ein signierter Link, höchstens sieben Tage gültig und nie länger, als die Datei aufbewahrt wird, worüber die Aufbewahrungsfrist des Plans entscheidet (ein Tag im Free-Plan);GET /v1/renders/{id}stellt einen frischen aus. Identische Live-Anfragen innerhalb von 24 Stunden werden wie native Renderings dedupliziert und liefern das frühere Rendering. -
export_type=fileantwortet mit einer302-Weiterleitung zur Ausgabe statt mit JSON. -
Fehler des Renderings, des Scopes, des Plans und des Kontingents kommen als
{ "status": "error", "message": …, "code": … }mit dem HTTP-Status des zugrunde liegenden Problems zurück (404bei unbekannter Vorlage,402bei aufgebrauchtem Kontingent,403bei fehlendem Scope,422bei einem Fehler in der Vorlage). Der Fehler eines Renderings, das vor seinem Scheitern aufgezeichnet wurde, etwa bei einem Fehler in der Vorlage oder einem Seitenlimit, trägt auch seinetransaction_ref, damit das Render-Protokoll undGET /v1/renders/{id}es finden. Eineurl, die die API ablehnt, und HTML mit CSS über 5 MB ergeben400nur mitstatusundmessage. Ein fehlender oder falscher Schlüssel (401), ein Browser-Origin, den der Schlüssel nicht erlaubt (403), das Rate-Limit (429), ein fehlendestemplate_id,bodyoderurlund ein unbekannteroutput_image_type(400) antworten wie die native API, als RFC-9457-Problem. -
Ausgelastete Regionen lassen die Anfrage warten: Die Endpunkte antworten immer mit dem fertigen Dokument, auch wenn das Rendering in die Warteschlange ging, weil alle Render-Slots belegt waren.
503 region_unavailableund429 rate_limitedtragen einenRetry-After-Header und dürfen nach so vielen Sekunden wiederholt werden. Ein Rendering, das zwei Minuten, nachdem es in den Hintergrund gewandert ist, noch läuft, antwortet mit504 render_timeoutund seinertransaction_ref; diese Anfrage nicht wiederholen, sonst wird das Dokument ein zweites Mal gerendert, sondern das Rendering mitGET /renders/{id}abrufen.
Beispiel
curl "https://api-eu.formfeed.dev/v1/compat/apitemplate/create-pdf?template_id=invoice-de" \
-H "X-API-KEY: $FORMFEED_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "invoice": { "number": "2026-0042", "lines": [] } }'
{
"status": "success",
"download_url": "https://cdn.formfeed.dev/o/eu/…?exp=…&sig=…",
"transaction_ref": "rnd_0f3c9a2e7b1d4e5f8a6c3b2d1e0f9a8b",
"total_pages": 1,
"template_id": "invoice-de"
}
Nicht abgedeckt
list-objects, delete-object, list-templates, die Konto-Endpunkte und die Helfer für Zusammenführen und
Wasserzeichen sind nicht geshimmt; jeder andere Pfad unter /v1/compat/apitemplate/ antwortet mit 404 not_found.
Nehmen Sie stattdessen die nativen Endpunkte: GET /v1/renders für list-objects,
DELETE /v1/renders/{id}/outputs für delete-object, GET /v1/templates für list-templates,
GET /v1/account und GET /v1/usage für das Konto und die PDF-Tools
(POST /v1/pdf/merge, /v1/pdf/watermark, ab Starter) zum Zusammenführen und für Wasserzeichen. Der
Importer zieht die Vorlagen um.