Make
The Formfeed app for Make has ten modules, a trigger and the universal Make an API call module. It is built and in Make's review: until Make approves it, it does not appear in Make's list of apps. Until then the HTTP module does the same job with one request, see the end of this page.
Connect
Add a Formfeed connection and paste an API key from the app (API keys).
A ff_test_ key renders for free (with a watermark on the Free plan), which is what you want while
building a scenario. The connection shows as organisation / workspace, so several workspaces stay
apart.
The default scopes of a new key (render:create, render:read, template:read, account:read)
cover the connection test, the template list and fields, the render and batch modules and
Get a render / Get a batch. The other modules need one more scope
each, which a new key has only when you tick it:
| Module | Scope |
|---|---|
| Watch events | webhook:manage (it registers a webhook endpoint) |
| Upload a file | file:write |
| List files | file:read (included in file:write) |
| Delete a file | file:delete |
The advanced API URL is for an address Formfeed support gives you, such as a staging gateway,
without /v1 and without a trailing slash. Leave it empty for https://api.formfeed.dev. It can only
be set when the connection is created, because the API key goes to that address alone; for another
address, add a new connection.
Modules
| Module | What it does |
|---|---|
| Create a document | Renders a published template to PDF, PNG, JPG or WebP, and a Word or PowerPoint template to DOCX, PPTX or PDF. Picking the template loads its fields. |
| Create a document from HTML | Renders HTML built earlier in the scenario, with the template language of your choice. |
| Create a document from a URL | Renders a public page. |
| Convert a document to PDF | Turns a Word, Excel, PowerPoint, OpenDocument or RTF file from an earlier module (up to 20 MB, not kept), or the render of a Word or PowerPoint template, into a PDF, with the file for the next module. Starter plan and above. |
| Get a render | Returns a render by its ID, with the file once it has succeeded. |
| Create a batch | Queues up to 1,000 documents from one template, optionally with one zip of all of them. |
| Get a batch | Returns the progress of a batch, its documents and the zip URL. |
| Watch events | Starts the scenario on render.completed, render.failed, job.completed, job.failed, quota.warning or quota.exceeded. |
| Upload a file | Adds an image or PDF from an earlier module to the file library, where templates use it with asset(). The same name replaces the file. |
| List files | Returns the files of the library, optionally one folder (brand/). |
| Delete a file | Removes a file from the library by its fil_… ID. |
| Make an API call | Calls any other endpoint with the connection's key, for example /v1/pdf/merge. |
The fields of each module:
| Module | Fields |
|---|---|
| Create a document | Template (required), then the template's own fields and, with release channels, 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; Word templates render DOCX or PDF, PowerPoint templates PPTX or PDF), File name, Locale (for example de-DE, overrides the template's and selects its translations), Download the document (on by default) |
| Create a document from HTML | HTML (required), Template language (Jinja2, the default, Liquid or Handlebars), Data (JSON), Output (PDF, the default, PNG, JPG or WebP), File name, Download the document, Settings (JSON) (paper, margins, header and footer, or the image size, as in Override settings per request) |
| Create a document from a URL | URL (required, a public page; private networks and internal hosts are refused), Output (PDF, the default, PNG, JPG or WebP), File name, Download the document, Settings (JSON) |
| Convert a document to PDF | Document: A file from an earlier module (File name and Data: DOCX, XLSX, PPTX, ODT, ODS, ODP, DOC, XLS, PPT or RTF, up to 20 MB; the type is read from the content) or The render of a Word or PowerPoint template (Render ID, rnd_… of a render with output DOCX or PPTX); Page ranges (for example 1-3,5, all when empty), Landscape, One page per sheet (for spreadsheets and documents without their own page setup), File name (the uploaded file's name with .pdf when empty), Download the document |
| Get a render | Render ID (required, rnd_…), Download the document |
| Create a batch | Template (required), Documents (required, up to 1,000, each with the template's fields, File name, Output and Locale), Zip all documents (on by default) |
| Get a batch | Batch ID (required, job_…) |
| Watch events | Events (required, Render completed by default) |
| Upload a file | File name and Data (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) |
| List files | Name starts with (for example brand/), Limit (10 by default) |
| Delete a file | File ID (required, fil_…). Templates that use the file show a missing image afterwards |
| Make an API call | URL (required, a path such as /v1/templates, always appended to the connection's address), Method, Headers, Query string, Body. The connection adds the Authorization header |
Fields from your template
The Template list shows the workspace's templates by name and kind and marks the ones that are
not published; only published templates render. Picking a template loads the fields of its
data schema, or, when the template has none, the fields of its
sample data. Nested objects become groups, and lists such as invoice lines become arrays: map an
Array aggregator onto them to turn the bundles of an earlier module into line items. A template
with neither a schema nor sample data offers one Data (JSON) field instead. A template with
release channels besides published also gets a Version select
listing them.
The file for the next module
With Download the document on (the default), the document modules return the file as well as the render, so the next module takes it directly: Gmail's attachment, a Google Drive or Dropbox upload, an FTP transfer. Turn it off when the download URL is enough.
A render that takes longer than a minute continues in the background. The module then checks every five seconds for up to five minutes and returns the render once it has finished; after that it returns the render as it is, and Get a render or Watch events picks it up later.
Watch events reads every render and batch event back from the API before the scenario sees it, so the bundle carries a fresh download URL, and a render or batch event that did not come from Formfeed stops with an error instead of running your scenario on made-up data. Quota events pass through as they arrive.
Errors come back with the status code, the problem detail and its code, for example
[404] No published template "invoice-de" in workspace fennlor (template_not_found), so a scenario's
error handler can route on them. Template and data errors (422) and a render that failed while the
module waited for it arrive as data errors (DataError), so a handler can tell them from the rest.
Errors lists every code.
Batches
Create a batch takes an array of documents: data, and optionally a file name, output format and locale for each. The usual shape of the scenario is
- a search module (Google Sheets, Airtable, a database) that returns one bundle per row,
- an Array aggregator with Create a batch as its target structure, mapping the columns onto the template's fields,
- Create a batch, which answers at once with the batch ID.
A second scenario starting with Watch events on Batch completed receives the zip URL when the batch is done, and Get a batch lists its documents. See Async and batch for how batches behave.
Until the app is published
The HTTP module's Make a request works with every Formfeed endpoint today:
- URL
https://api.formfeed.dev/v1/renders, methodPOST - Header
Authorization: Bearer ff_test_… - Body type Raw, content type JSON, request content
{"template": "invoice-de", "data": {"invoice": {"number": "2026-0042"}}} - Parse response on
The response contains download_url, which a second HTTP module (Get a file) turns into a file.
The request shape is described in Rendering.