Databases and spreadsheets / Airtable
Generate a PDF and attach it in Airtable
A database with a spreadsheet interface, where attachments are a first-class field type and are set in a way that surprises people.
Making the request
An automation's Run script action, which is JavaScript with fetch available, or an outbound webhook to something else that does the work. The script action is the usual route because it can read the record that triggered it.
What it does with the response
There is none, and that is the whole point of this page. An Airtable attachment field cannot be written with bytes. You give it a URL and a filename, Airtable fetches that URL itself, stores its own copy, and replaces what you gave it with a reference to that copy. So the integration shape here is fixed by the platform: render with storage on, get a URL, and hand Airtable the URL. There is no configuration that makes uploading bytes work, and time spent looking for one is time wasted.
Where the document can go afterwards
This is the part that differs most between platforms, and it is usually the reason one platform was chosen over another in the first place.
- an attachment field on the record that triggered the automation
- a second table, if documents are tracked separately from the records they describe
- onward by email or Slack from a later automation step, referencing the attachment
- nowhere else, because once Airtable has re-hosted it the original is no longer what the record points at
The limit that bites in production
Airtable has to be able to reach the URL, so it must be publicly resolvable at the moment the automation runs. The fetch is asynchronous: the attachment appears shortly after the script finishes rather than immediately, so a subsequent step that expects it to be there may run too early. And the attachment URLs Airtable returns from its own API are time-limited, so they must not be stored anywhere as permanent links.
The shape that works
Render with store set to true, take the document URL from the response, and write it into the attachment field as a single-element array with a url and a filename. Let Airtable do the fetching.
// Airtable automation, "Run script" action.
const config = input.config();
const table = base.getTable("Invoices");
const res = await fetch("https://api.pdfpipe.xyz/v1/pdf", {
method: "POST",
headers: {
Authorization: `Bearer ${config.pdfpipeKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
html: config.invoiceHtml,
filename: `${config.invoiceNumber}.pdf`,
// Storage on. The URL is the deliverable here, not the bytes:
// an attachment field cannot be written with bytes at all.
store: true,
options: { format: "A4", margin: "16mm" },
}),
});
if (!res.ok) throw new Error(`Render failed: ${res.status}`);
const doc = await res.json();
await table.updateRecordAsync(config.recordId, {
// A url and a filename. Airtable fetches this itself and stores a
// copy, then points the field at the copy rather than at your URL.
Document: [{ url: doc.url, filename: `${config.invoiceNumber}.pdf` }],
});The mistake people make
Building a base64 string and trying to write it into the attachment field, which is the first thing anyone tries. It fails, and it fails without a message that explains why, because the field simply will not accept it. The attachment field takes a URL. Once that is understood the integration is five lines long.
Frequently asked
Can Airtable handle the PDF bytes directly?
There is none, and that is the whole point of this page. An Airtable attachment field cannot be written with bytes. You give it a URL and a filename, Airtable fetches that URL itself, stores its own copy, and replaces what you gave it with a reference to that copy. So the integration shape here is fixed by the platform: render with storage on, get a URL, and hand Airtable the URL. There is no configuration that makes uploading bytes work, and time spent looking for one is time wasted.
Should I store the document or pass the bytes through?
It depends on what the platform does with a large value. On a platform that serialises everything passing between steps, pushing several megabytes through the workflow is slow and sometimes capped, so storing the document and passing a URL is better. On a platform that hands you a file object natively, passing it straight to its destination is simpler and avoids a second fetch. The page above says which of those this platform is.
Where does the API key live?
In the platform's own secret or environment storage, never in a step body where it is visible in an execution log. Every platform on this list has somewhere to put it, and the execution logs of an automation platform are seen by more people than a codebase is.
Other platforms
Platforms of the same kind, and one from each of the other kinds.
Generate a PDF from Power Automate
Microsoft's cloud flow automation, which sits closest to SharePoint, OneDrive, Outlook and Dataverse and is usually chosen because the documents have to land in one of them.
Generate a PDF from Pipedream
A workflow platform where the steps are real Node.js or Python, so anything the language can do the workflow can do.
Generate a PDF from Retool
An internal tool builder where the UI is assembled from components and the data comes from queries, which makes a file an awkward shape to pass around.
Every automation platform covered
Grouped by what kind of platform it is, with the three that have their own guide linked out.
Storing generated PDFs and fetching them later
The capability several of these integrations are built on, with the retention that applies.
100 free documents a month, and a playground that runs a real render without a key, which is the fastest way to get an HTML sample worth wiring up.