Zapier
The Formfeed app for Zapier has six actions and one trigger. It is listed in Zapier's app directory: search for Formfeed when you add a step to a Zap. In the Formfeed app, Integrations shows the Formfeed Zap templates and your Zaps without leaving the app, once you choose Show Zapier; that loads Zapier's own page into the app and hands Zapier your name and email address, so it can create a Zapier account for you in one step.
Zap templates for Google Forms, Typeform, Google Sheets, Google Drive, Stripe and Slack are published in the directory as well. Starting from one puts the trigger and the Formfeed step in place; you connect the two accounts and pick your own template, and the Zap is done.
Connect
Add a Formfeed connection and paste an API key from the app
(API keys). The default scopes of a new key (render:create, render:read, template:read,
account:read) cover the connection test, the template list and every render action; tick
file:write and webhook:manage as well when you use Upload File or the trigger. What each step
needs:
| Scope | Needed for |
|---|---|
account:read | the connection test, which reads GET /account (a default scope) |
template:read | the template list and the fields of a template (a default scope) |
render:create | the three Create Document actions, Create E-Invoice and Convert Document to PDF (a default scope) |
file:write | Upload File |
webhook:manage | the Render Completed trigger, which registers a webhook |
A ff_test_ key renders for free (with a watermark on the Free plan), which is what you want while
building a Zap; switch the connection to a ff_live_ key before the Zap goes on. The connection shows
as organisation / workspace, so several workspaces stay apart. Leave Region on Europe (every
workspace is in the EU today) and Custom API URL empty.
Actions
| Action | What it does |
|---|---|
| Create Document | Renders a published template. Picking the template loads its fields, so you map invoice.number instead of writing JSON, and a Version choice when the template has release channels. Word and PowerPoint templates render DOCX, PPTX or PDF. |
| Create Document From HTML | Renders HTML built earlier in the Zap, with the template language of your choice. |
| Create Document From URL | Renders a public page to PDF or an image. |
| Upload File | Adds an image or PDF from an earlier step to the file library, where templates use it with asset(). The same name replaces the file. |
| Convert Document to PDF | Turns a Word, Excel, PowerPoint, OpenDocument or RTF file from an earlier step (up to 20 MB, not kept), or the render of a Word or PowerPoint template by its ID, into a PDF. Starter plan and above. |
| Create E-Invoice | Renders a ZUGFeRD / Factur-X e-invoice from fields for the invoice itself, validated before it is delivered. See below. Starter plan and above. |
The fields of each action:
| Action | Fields |
|---|---|
| Create Document | Template (required), then the template's own fields and Version; Output (empty: the template's format, PDF for a PDF template, its image format for an image template, its default for a Word or PowerPoint template), File name, Locale (for example de-DE, overrides the template's), Data (JSON) |
| Create Document From HTML | HTML (required), Template language (Jinja2, the default, Liquid or Handlebars), Output (PDF, the default, PNG, JPG or WebP), File name, Data (JSON), Settings (JSON) (paper, margins, header and footer, as in Override settings per request) |
| Create Document From URL | URL (required, a public page), Output (PDF, the default, PNG, JPG or WebP), File name, Settings (JSON) |
| Upload File | File (required: PNG, JPEG, WebP, GIF, SVG, AVIF or PDF, up to 10 MB), Name in library (the name templates use with asset(), for example brand/logo.png; the file's own name when empty) |
| Convert Document to PDF | File (DOCX, XLSX, PPTX, ODT, ODS, ODP, DOC, XLS, PPT or RTF) or Render ID (rnd_… of a render with output DOCX or PPTX), exactly one of the two; Page ranges (for example 1-3,5, all when empty), Landscape and One page per sheet (for spreadsheets and documents without their own page setup), File name (the file's own name with .pdf when empty) |
The Template list shows the workspace's templates by name and kind, up to 100 of them, unpublished
ones included; only published templates render, and an unpublished one fails with
template_not_found. Its fields come from the template's
data schema, or, when it has none, from its sample data. Nested
objects become dotted names (invoice.number); lists are left out of the fields and go into
Data (JSON).
Every Create Document action returns the render: id, status, download_url, page_count and
units. Map Download Url into the next step: file fields in Zapier (Gmail's Attachments,
Google Drive's File) accept a URL and fetch the document. Copy the file rather than storing the link:
a download link is valid for at most seven days, and the file itself only for the workspace's
retention period (one day on the Free plan,
at most 24 hours for a test key). A render that takes longer than a minute continues in the
background, and the action then returns it with status: queued and no download URL; the
trigger receives it when it finishes.
Lists (invoice line items, table rows) go into the Data (JSON) field, which is merged over the mapped fields value by value: an object in the JSON adds to the mapped fields at the same place, a value replaces the mapped one, and a list replaces the whole list. A Looping by Zapier step or a Code step usually builds that array.
E-invoices
Create E-Invoice makes a ZUGFeRD / Factur-X e-invoice: a PDF/A-3 that carries the invoice as
XML, checked by the validator before the Zap receives it. Instead of a template's fields, the action
asks for the invoice itself, in groups: the invoice (number, issue date, currency, document type,
references), seller and buyer, the lines and the VAT breakdown, the five totals and the payment.
Lines and the VAT breakdown are line items, so a trigger that brings line items (an invoice of your
shop or accounting app) maps them line by line. The action sends everything as the _invoice block,
and the template prints the same block, so every value is mapped once. The E-invoice example of the
gallery in the app is such a template.
Nothing is computed: the totals and the VAT breakdown are the ones your system states, and an invoice
whose totals do not add up to the cent is refused. The Zap's error then names every field with the
rule it breaks, such as _invoice.totals.due: … (BR-CO-16). What the fields do not offer (the
invoice a credit note refers to, allowances and charges, the delivery, a direct debit mandate, the
notes French invoices need) goes into Invoice (JSON) with the names of the
field reference, merged over the fields. The options choose
the profile (EN 16931 or Basic), the name of the specification (Factur-X or ZUGFeRD; the file is the
same), whether the XML is also stored as a file of its own, and whether a value the PDF does not show
fails the render instead of being reported.
The action returns the render with the validator's report as einvoice; E-invoice valid,
Rules checked, PDF/A level, XML URL and the two SHA-256 fields can be mapped into the next
step. Live e-invoices need the Starter plan or higher; a test key makes a limited number a day, each
with the test mark (see Plans and units).
Trigger
Render Completed subscribes to the workspace's webhooks. Choose the events you care about:
render.completed (the default), render.failed, job.completed, job.failed, quota.warning,
quota.exceeded. Zapier registers the endpoint when the Zap is turned on and removes it when the Zap
is turned off, so nothing is left behind; while it exists, it is listed in the app under Webhooks
as Zapier.
The trigger fires for every render of the workspace, of live and test keys alike, not only for
renders started by a Zap: batches from the app, API calls from your backend and renders that outlasted
the synchronous limit (the action then returns them with status: queued) all arrive here. Its fields
are Render ID, Event Type, Status, Output Format, Download URL, Page Count,
Template, Error Code, Error Title, Error Detail and, for a batch, Batch ZIP URL.
A Zap needs at least one real action after the trigger; Formatter, Filter and Delay steps alone do
not count. Do not add a Formfeed Create Document action to a Zap that triggers on
render.completed: every render would start the Zap again.
Example Zaps
Zapier's free plan runs Zaps of two steps; an example with a third step needs a paid Zapier plan. Build the template in the Formfeed app first and publish it: Create Document lists unpublished templates too, but renders only published ones.
Most of these exist as a published Zap template: open it from the app directory or from Integrations in the Formfeed app, and the steps are already in place. The fields are written out here anyway, because a template cannot know what your own template expects.
Send a certificate for every form response
A participant submits a form and receives their certificate by email.
-
Trigger: Google Forms → New Form Response (Typeform → New Entry works the same way).
-
Action: Formfeed → Create Document
Field Value Template your certificate template, for example Certificate (pdf) name Full name from step 1 course Course from step 1 date Timestamp from step 1 File name certificate-followed by Full name from step 1 -
Action: Gmail → Send Email: To is the Email answer from step 1, Attachments is Download Url from step 2.
The template reads the fields as {{ name }}, {{ course }} and {{ date | date('dd.MM.yyyy') }}.
Google Forms sends the timestamp as text such as 9/16/2026 10:15:00; put a Formatter by Zapier →
Date / Time → Format step before the Formfeed step, with the output format YYYY-MM-DD, and map
its output to date.
Turn a spreadsheet row into an invoice in Google Drive
Every new row in the sheet becomes a PDF in a Drive folder.
-
Trigger: Google Sheets → New Spreadsheet Row, with columns
number,customer,street,city,amount. -
Action: Formfeed → Create Document, template Invoice, and map the columns onto the template's fields (
invoice.number,customer.name, …). The line items go into Data (JSON) in the shape your template loops over, for example:{"items": [{ "description": "Consulting", "quantity": 1, "unit_price": 450 }]} -
Action: Google Drive → Upload File: File is Download Url from step 2, File Name is
Invoicefollowed by number from step 1.
Render HTML without a stored template
When an earlier step already produces the text, render it directly.
-
Trigger: any app, for example Schedule by Zapier → Every Week.
-
Action: Formfeed → Create Document From HTML
Field Value HTML <h1>Weekly report for {{ team }}</h1><p>{{ summary }}</p>Template language Jinja2 Output PDF Data (JSON) {"team": "Fennlor Studio", "summary": "All systems normal."}Settings (JSON) {"paper": {"format": "A4"}, "margin": {"top": "20mm", "bottom": "20mm"}}Map values from earlier steps into the JSON instead of the fixed text.
-
Action: Email by Zapier → Send Outbound Email with Download Url in the body.
Zapier does not touch {{ }} inside a field, so the template syntax reaches Formfeed unchanged.
Keep the logo in the file library up to date
- Trigger: Google Drive → New File in Folder, the folder your designers use for brand assets.
- Action: Formfeed → Upload File: File is the file from step 1, Name in library
brand/logo.png.
Every template that shows <img src="{{ asset('brand/logo.png') }}" alt=""> uses the new logo from the
next render on.
Get a Slack message when a render fails
- Trigger: Formfeed → Render Completed, Events set to Render failed and Batch failed.
- Action: Slack → Send Channel Message, with the text
Render failed:followed by Render ID and Error Detail picked from step 1.erroris the render's problem, so its Error Title and Error Code fields are there as well.
This covers renders from the app and the API as well, which makes it a cheap alert for a backend integration.