Almost every operations base eventually needs to produce a document. A quote a client can sign. A statement of work. An invoice. A site report. The data already lives in Airtable, so the job should be mechanical, but most teams still export a view, paste numbers into a Google Doc, save a PDF, and email it by hand. That is where version drift, wrong totals, and "which quote did they actually sign?" come from.
This tutorial covers the whole path: modelling the data so a document can be generated cleanly, choosing template tooling, building the automation that produces and attaches the file, wiring e-signature status back into the base, and the failure modes we see most often on client projects.
Step 1: model the document before you design it
A document is a parent record plus a set of child rows. Get that structure right and templating is easy; get it wrong and you will fight the template forever.
A minimal quote-to-signature schema:
Quotes— one record per document. Fields:Quote number(unique),Client(link toClients),Status(single select:Draft,Generated,Sent,Signed,Declined,Expired),Valid until(date),Subtotal,Tax,Total(rollups),Document(attachment),Signed document(attachment),Signature request ID(text),Generated at(date),Terms version(text).Quote lines— one record per line item, linked toQuotes. Fields:Description,Quantity,Unit price,Line total(formula{Quantity} * {Unit price}),Sort order(number).Clients—Name,Legal entity name,Billing address,Primary contact,Contact email,VAT / tax ID.
Three rules that save pain later:
- Never let the template do maths. Compute
Line total,Subtotal,Tax, andTotalas Airtable formulas and rollups, so the number on the PDF is the number in the base and reporting agrees with the paperwork. - Snapshot what must not change. Copy the client's legal name, billing address, and your terms version onto the quote record at generation time. If the client later changes address, last year's signed PDF should not retroactively disagree with the base.
- Give every document a stable, human-readable ID. A
Quote numberlikeQ-2026-0184generated once and never recomputed. Formula-based numbering that depends on record order will renumber itself and destroy your audit trail.
Step 2: pick the generation approach
There are four realistic options, and the right one depends on how complex the document is and who maintains it.
A. Docs-as-template merge tools (Documint, DocsAutomator, Docupilot and similar). You design the template in Google Docs or a visual editor, map Airtable fields, and the service returns a PDF URL. Best for business users who need to edit wording without a developer. Handles repeating line items via tables or loop syntax.
B. Google Docs / Apps Script via Make or n8n. Copy a Doc template, replace placeholders, export as PDF, upload back. More moving parts, but no per-document vendor fee and full control over branding.
C. HTML-to-PDF in your own service. Render an HTML template (Handlebars, Nunjucks) and print it with a headless browser or an API like PDFMonkey or Api2Pdf. Best for pixel-precise, high-volume, or multi-language documents. Requires a developer to change wording.
D. Airtable scripting extension with a PDF API. A script in an automation calls a rendering API and writes the returned URL to an attachment field. Keeps everything inside Airtable; scripts are subject to automation runtime limits, so keep the script to a single API call rather than generating the PDF in-process.
For most consulting clients we start with A or B for quotes and proposals, and move to C only when the document becomes a product in itself (certificates, regulated reports, batch invoicing).
Step 3: build the generate action
Document generation should be an explicit, idempotent action — not something that fires on every edit.
Add a Generate document button field (or a button element on an Interface) that triggers a webhook, or use a Generate? checkbox with a "When record matches conditions" trigger. Then:
- Validate first. In the automation, run a conditional step: stop unless
Client, at least oneQuote line,Valid until, andTotalare all present. Half-finished PDFs sent to clients are the number one complaint after a doc-gen rollout. - Collect line items. Use a "Find records" step on
Quote linesfiltered to the current quote and sorted bySort order. Most merge services accept an array of line objects; if yours wants a single blob, build the rows in a script step. - Call the generator. Send the parent fields and the line array. Keep a
Terms versionstring in the payload so the template can pull the correct legal wording. - Store the result. Write the returned file URL into the
Documentattachment field — Airtable fetches it and stores its own copy. SetStatustoGeneratedand stampGenerated at.
A script step that attaches a returned URL and stamps the record:
let table = base.getTable('Quotes');
let { recordId, fileUrl, filename } = input.config();
await table.updateRecordAsync(recordId, {
'Document': [{ url: fileUrl, filename: filename }],
'Status': { name: 'Generated' },
'Generated at': new Date().toISOString()
});
Two things about that attachment write. First, the URL must be publicly reachable for long enough for Airtable to fetch it — many generators return short-lived links, so attach immediately rather than queuing the step for later. Second, writing to an attachment field replaces the array unless you read the existing value and append; for versioned documents, keep prior PDFs by appending rather than overwriting, or store them on a linked Document versions table.
Step 4: send for e-signature and get the status back
Generating a PDF is half the job. The value is knowing, inside the base, whether it was signed.
Most signature platforms (DocuSign, Dropbox Sign, SignWell, PandaDoc, Yousign) follow the same shape:
- Your automation POSTs the generated PDF plus signer name and email to create a signature request.
- The API returns a request ID — store it in
Signature request ID. This is your join key; without it you cannot match callbacks to records. - Set
StatustoSentand stamp aSent atdate. - The platform sends webhook events (
viewed,signed,declined,expired) to an endpoint you control.
For the return path, do not poll the signature API on a schedule if you can avoid it — it burns automation runs and lags by minutes. Instead point the provider's webhook at a small handler (a serverless function, n8n, or Make scenario) that looks up the Airtable record by Signature request ID and patches Status, Signed at, and the countersigned PDF into Signed document.
If you want the handler inside Airtable itself, you can use an incoming webhook trigger in an automation, then a "Find records" step matching the request ID. Remember that Airtable's webhook trigger URL is a bearer secret: anyone with it can create runs. Verify the provider's signature header inside your own middleware where the platform supports it, and treat the payload as untrusted — never write raw payload text into a field that renders in an Interface without sanitising it.
Step 5: close the loop into downstream systems
Once Status becomes Signed, the interesting automations begin:
- Create the project record and its task template from the signed quote.
- Push the deal to the CRM as closed-won.
- Generate the first invoice from the same line items, reusing the identical rollups so billing cannot drift from the quote.
- Notify the account owner in Slack with the signed PDF attached.
- Start the renewal clock: a scheduled automation that flags contracts approaching their end date.
This is also where a lot of teams discover their quote data model was too thin. If you ever plan to invoice in stages, model Quote lines so a line can carry a Billing schedule or a link to Invoice lines, rather than re-keying amounts later.
Failure modes we see in production
Duplicate generation. A checkbox trigger plus an impatient user equals three PDFs. Guard with a condition on Status (Draft only) and clear the trigger checkbox in the first automation step.
Silent template drift. Someone edits the Google Doc template and breaks a placeholder; PDFs start shipping with {{client_legal_name}} printed literally. Keep a smoke-test record ("ACME Test Ltd") and regenerate it after every template change.
Long text that overflows. Scope descriptions pasted from email arrive with hard line breaks and 4,000 characters. Test your template with the ugliest real record you have, not with tidy sample data.
Currency, tax, and locale. Rounding per line versus rounding the total gives different answers. Decide once, implement it in the Airtable formulas, and make the template dumb.
Attachment bloat. Every generated version is stored in your base and counts against attachment storage. Set a retention rule: keep the signed document forever, keep the last two drafts, delete older ones with a scheduled automation.
Permissions leakage. Airtable attachment URLs can be shared. For contracts containing personal or commercial data, keep the canonical copy in your document store (Drive, SharePoint, S3) and hold a link plus a light preview copy in Airtable.
A sensible rollout order
- One document type only — usually the quote.
- Generation and attachment, manually emailed. Run it for two weeks and collect complaints about wording.
- Add e-signature and the webhook status write-back.
- Add downstream automation (project creation, invoicing, CRM).
- Only then add the second and third document types, reusing the same pattern.
Trying to launch all of it at once is how doc-gen projects stall: the template arguments and the integration debugging collide and nothing ships.
Need this built?
BaseBrainers builds quote-to-signature and invoicing workflows on Airtable, including template design, e-signature integration, and the webhook plumbing that keeps status accurate. If you have a base full of clean data and a process still running on copy-paste, get in touch and tell us what the document needs to say.