Airtable Integration
Generate PDFs from Airtable records using the DataToPDF API.
Prerequisites
- A DataToPDF account with a Starter plan or higher (API access required)
- An API key generated from Settings > API Key
- A PDF template configured with Airtable as the data source
- Airtable connected to your DataToPDF account
Setup
Connect your Airtable account in DataToPDF:
- Go to Settings > Integrations > Airtable
- Enter your Airtable Personal Access Token
- Click Connect
Creating an Airtable Personal Access Token
- Go to https://airtable.com/create/tokens
- Click Create new token
- Add the following scopes:
data.records:read- Required for reading recordsschema.bases:read- Required for listing bases and tablesdata.records:write- Required for attaching PDFs to records
- Select the bases you want to access (or all bases)
- Click Create token and copy the token
API Usage
Endpoint
POST https://datatopdf.app/api/v1/pdf/generate
Request
{
"templateId": "your_template_id",
"recordId": "airtable_record_id",
"uploadToRecord": false,
"fileName": "custom-filename.pdf",
"attachmentFieldName": "PDF"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
templateId | string | Yes | ID of the PDF template to use |
recordId | string | No | Airtable record ID (starts with rec) for the table configured in your template |
uploadToRecord | boolean | No | If true, uploads the generated PDF to the Airtable record's attachment field |
fileName | string | No | Custom file name for the PDF (defaults to template name) |
attachmentFieldName | string | No | Name of the Airtable attachment field to upload to (defaults to "PDF") |
Airtable Automations
You can automate PDF generation using Airtable Automations with script actions.
Option 1: Script Action
Use a script action to call the DataToPDF API directly from an Airtable automation.
Setup
- Go to your Airtable base
- Click Automations in the top navigation
- Create a new automation or edit an existing one
- Add a trigger (e.g., "When record matches conditions")
- Add a Run a script action
JavaScript Script
// Configuration
const DATATOPDF_API_KEY = 'pk_your_api_key_here';
const TEMPLATE_ID = 'clx1234567890';
// Get the record ID from the trigger
let inputConfig = input.config();
let recordId = inputConfig.recordId;
// Generate PDF
let response = await fetch('https://datatopdf.app/api/v1/pdf/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': DATATOPDF_API_KEY
},
body: JSON.stringify({
templateId: TEMPLATE_ID,
recordId: recordId
})
});
let result = await response.json();
if (response.ok) {
console.log('PDF generated successfully!');
// The PDF is returned as base64 in result.pdf
output.set('pdfGenerated', true);
output.set('pdfBase64', result.pdf);
} else {
console.log('Error:', result.error);
output.set('pdfGenerated', false);
output.set('error', result.error);
}
Script Input Configuration
Configure the input variables in the script settings:
| Input Variable | Value |
|---|---|
| recordId | Record ID from trigger |
Option 2: Webhook (via Make/Zapier)
For more complex workflows, use a webhook integration through Make (Integromat) or Zapier.
Make.com Scenario
- Create a new scenario in Make
- Add Airtable - Watch Records as the trigger
- Add HTTP - Make a request module:
| Setting | Value |
|---|---|
| URL | https://datatopdf.app/api/v1/pdf/generate |
| Method | POST |
| Headers | X-API-Key: pk_your_api_key_here<br>Content-Type: application/json |
| Body type | Raw |
| Content type | JSON |
| Request content | {"templateId": "clx1234567890", "recordId": "{{1.id}}"} |
- Optionally add an Airtable - Update Record module to store the PDF URL or status
Zapier Zap
- Create a new Zap
- Add Airtable - New or Updated Record as the trigger
- Add Webhooks by Zapier - Custom Request:
| Setting | Value |
|---|---|
| Method | POST |
| URL | https://datatopdf.app/api/v1/pdf/generate |
| Data Pass-Through | False |
| Data | templateId: clx1234567890<br>recordId: Record ID from step 1 |
| Headers | X-API-Key: pk_your_api_key_here<br>Content-Type: application/json |
Automation Use Cases
| Trigger | Template | Description |
|---|---|---|
| Record created | Welcome letter | Auto-generate welcome document for new clients |
| Status = "Approved" | Contract template | Generate contract when approval is given |
| Checkbox checked | Invoice template | Create invoice when "Ready to Bill" is checked |
| Date field matches today | Report template | Generate daily/weekly reports |
| Form submitted | Quote template | Create quote from form responses |
Examples
cURL
curl -X POST https://datatopdf.app/api/v1/pdf/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_your_api_key_here" \
-d '{
"templateId": "clx1234567890",
"recordId": "recABC123XYZ"
}'
JavaScript (Node.js)
const fetch = require('node-fetch');
async function generatePdfFromAirtable(recordId, templateId) {
const apiKey = process.env.DATATOPDF_API_KEY;
const response = await fetch('https://datatopdf.app/api/v1/pdf/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({
templateId: templateId,
recordId: recordId
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(`${data.code}: ${data.error}`);
}
return Buffer.from(data.pdf, 'base64');
}
// Example usage
generatePdfFromAirtable('recABC123XYZ', 'clx1234567890')
.then(pdfBuffer => {
console.log('PDF generated, size:', pdfBuffer.length, 'bytes');
})
.catch(error => {
console.error('Error:', error.message);
});
Python
import requests
import base64
import os
def generate_pdf_from_airtable(record_id: str, template_id: str) -> bytes:
api_key = os.environ.get('DATATOPDF_API_KEY')
response = requests.post(
'https://datatopdf.app/api/v1/pdf/generate',
headers={
'Content-Type': 'application/json',
'X-API-Key': api_key
},
json={
'templateId': template_id,
'recordId': record_id
},
timeout=30
)
data = response.json()
if not response.ok:
raise Exception(f"{data.get('code')}: {data.get('error')}")
return base64.b64decode(data['pdf'])
# Example usage
try:
pdf_bytes = generate_pdf_from_airtable('recABC123XYZ', 'clx1234567890')
print(f'PDF generated, size: {len(pdf_bytes)} bytes')
# Save to file
with open('output.pdf', 'wb') as f:
f.write(pdf_bytes)
except Exception as e:
print(f'Error: {e}')
Airtable Scripting Extension
Use this in the Scripting extension to generate PDFs on-demand:
// Get the current record
let table = base.getTable('Your Table Name');
let record = await input.recordAsync('Select a record', table);
if (!record) {
console.log('No record selected');
return;
}
// Configuration
const DATATOPDF_API_KEY = 'pk_your_api_key_here';
const TEMPLATE_ID = 'clx1234567890';
// Generate PDF
console.log('Generating PDF...');
let response = await fetch('https://datatopdf.app/api/v1/pdf/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': DATATOPDF_API_KEY
},
body: JSON.stringify({
templateId: TEMPLATE_ID,
recordId: record.id
})
});
let result = await response.json();
if (response.ok) {
console.log('PDF generated successfully!');
console.log('Content type:', result.contentType);
// You can now use result.pdf (base64) to:
// - Download the PDF
// - Send via email
// - Store in another service
} else {
console.error('Error generating PDF:', result.error);
}
Working with Airtable Data
Supported Field Types
All Airtable field types are supported for merge fields:
| Field Type | Merge Field Output |
|---|---|
| Single line text | Text value |
| Long text | Full text with line breaks |
| Number | Numeric value |
| Currency | Formatted currency |
| Percent | Percentage value |
| Date | ISO date string |
| Checkbox | true or false |
| Single select | Selected option text |
| Multiple select | Comma-separated options |
| Email address | |
| Phone | Phone number |
| URL | Web URL |
| Attachment | First attachment URL |
| Link to another record | Linked record names |
| Formula | Calculated result |
| Lookup | Looked up values |
| Rollup | Aggregated value |
Linked Records
When your template includes linked record fields, the primary field value(s) of the linked records are returned:
{{Linked Projects}} → "Project Alpha, Project Beta"
{{Primary Contact}} → "John Smith"
Attachments
For attachment fields, the first attachment's URL is available:
{{Logo}} → URL to the attachment file
Response Format
Success (200)
{
"pdf": "base64-encoded-pdf-data",
"contentType": "application/pdf"
}
Error Response
{
"error": "Human-readable error message",
"code": "ERROR_CODE"
}
Error Codes
| Code | Description |
|---|---|
UNAUTHORIZED | Missing API key |
INVALID_API_KEY | Invalid or revoked API key |
RATE_LIMIT_EXCEEDED | Too many requests (30/minute limit) |
SUBSCRIPTION_REQUIRED | Active subscription required |
PLAN_UPGRADE_REQUIRED | API access requires Starter plan or higher |
GENERATION_LIMIT_EXCEEDED | Monthly PDF limit reached |
TEMPLATE_NOT_FOUND | Template not found |
CONNECTION_NOT_FOUND | Airtable connection not configured |
DATA_FETCH_ERROR | Failed to fetch Airtable data |
INVALID_REQUEST | Invalid request body or parameters |
GENERATION_FAILED | PDF generation failed |
Rate Limits
- DataToPDF API: 30 requests per minute per API key
- Airtable API: 5 requests per second per base
- Monthly generation limits based on your subscription plan
Best Practices
- Store API keys securely - Use environment variables or Airtable's scripting secrets
- Handle rate limits - Implement retry logic with exponential backoff
- Validate record IDs - Ensure the record ID exists before making API calls
- Use automations wisely - Avoid triggering on every field change to prevent excessive API calls
- Test with specific bases - During development, limit token access to test bases only