Zum Hauptinhalt springen

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.ioFormfeed-ShimNatives 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-htmlPOST …/v1/compat/apitemplate/create-pdf-from-htmlPOST /v1/renders mit html und engine: jinja2
POST …/v2/create-pdf-from-urlPOST …/v1/compat/apitemplate/create-pdf-from-urlPOST /v1/renders mit url

Was sich ändert​

  • Schlüssel: Der Header X-API-KEY bleibt; senden Sie darin einen Formfeed-Schlüssel (ff_live_…, oder ff_test_…, um es kostenlos auszuprobieren) oder nutzen Sie Authorization: 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_id bleibt 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-pdf und create-image nehmen die Vorlagendaten als JSON-Body, genau wie zuvor; ein Body, der kein JSON-Objekt ist, zählt als keine Daten. create-pdf-from-html nimmt body (das HTML, als Jinja2-Vorlage gerendert), css (als <style>-Block davor gesetzt), data und settings; create-pdf-from-url nimmt url und settings. Query-Parameter außer template_id, output_image_type und export_type werden ignoriert.

  • Einstellungen (nur create-pdf-from-html und create-pdf-from-url; create-pdf und create-image nutzen die mit der Vorlage gespeicherten Einstellungen) werden auf Formfeed-Einstellungen abgebildet:

    apitemplate.ioFormfeed
    paper_sizepaper.format: A3, A4, A5, Letter, Legal, Tabloid, Ledger; jede andere Größe rendert als A4
    custom_width, custom_heightpaper.width, paper.height; eine Zahl ohne Einheit ist Millimeter
    orientationpaper.landscape (landscape oder 2)
    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 sind
    header_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 zeichnet
    displayHeaderFooterfalse lässt Kopf- und Fußzeile weg
    print_background, scale, page_ranges, prefer_css_page_sizeprintBackground, scale, pageRanges, preferCssPageSize

    Schlüssel ohne Gegenstück werden ignoriert. Siehe die Referenz der Einstellungen.

  • output_image_type (create-image): 1 (der Standard) oder jpegOnly rendert ein JPEG und liefert es in download_url, 2 oder pngOnly ein PNG in download_url_png, all beides. Das jeweils andere Feld ist null. all erzeugt zwei Renderings und kostet beide. Jeder andere Wert ergibt 400 invalid_request und rendert nichts.

  • Antwort: status: "success", download_url, transaction_ref (die Formfeed-Render-ID, nutzbar mit GET /v1/renders/{id}), total_pages (null bei Bildern) und bei create-pdf und create-image die template_id, die Sie gesendet haben. download_url ist 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=file antwortet mit einer 302-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 (404 bei unbekannter Vorlage, 402 bei aufgebrauchtem Kontingent, 403 bei fehlendem Scope, 422 bei 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 seine transaction_ref, damit das Render-Protokoll und GET /v1/renders/{id} es finden. Eine url, die die API ablehnt, und HTML mit CSS über 5 MB ergeben 400 nur mit status und message. Ein fehlender oder falscher Schlüssel (401), ein Browser-Origin, den der Schlüssel nicht erlaubt (403), das Rate-Limit (429), ein fehlendes template_id, body oder url und ein unbekannter output_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_unavailable und 429 rate_limited tragen einen Retry-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 mit 504 render_timeout und seiner transaction_ref; diese Anfrage nicht wiederholen, sonst wird das Dokument ein zweites Mal gerendert, sondern das Rendering mit GET /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.