Skip to content

Airtable API Integration

Connect your Airtable bases to Glyph via API and generate professional PDFs from your data programmatically.

With Glyph + Airtable, you can automatically generate:

  • Invoices from your billing table
  • Quotes & Proposals from your sales pipeline
  • Reports from project tracking data
  • Contracts from your client database
  • Certificates from your records
  • Packing slips from inventory data
  1. Get your Airtable Personal Access Token

    Go to airtable.com/create/tokens, click Create new token, name it “Glyph Integration”, and add these scopes:

    • data.records:read — Read records from tables
    • schema.bases:read — Read base and table schemas

    Under Access, select the bases you want to connect. Click Create token and copy the value (starts with pat).

  2. Connect your base

    Terminal window
    curl -X POST https://api.glyph.you/v1/airtable/connect \
    -H "Authorization: Bearer gk_your_glyph_api_key" \
    -H "Content-Type: application/json" \
    -d '{"apiKey": "patXXXXXXXXXXXXXX"}'

    This returns a list of accessible bases with their IDs.

  3. Pick a table and inspect its schema

    Terminal window
    # List tables in your base
    curl https://api.glyph.you/v1/airtable/bases/appXXXXXX/tables \
    -H "Authorization: Bearer gk_your_glyph_api_key" \
    -H "X-Airtable-Key: patXXXXXXXXXXXXXX"
    # Get field schema for a specific table
    curl https://api.glyph.you/v1/airtable/bases/appXXXXXX/tables/tblXXXXXX/schema \
    -H "Authorization: Bearer gk_your_glyph_api_key" \
    -H "X-Airtable-Key: patXXXXXXXXXXXXXX"
  4. Fetch a record and generate a PDF

    Terminal window
    # Get a single record
    curl https://api.glyph.you/v1/airtable/bases/appXXXXXX/tables/tblXXXXXX/records/recXXXXXX \
    -H "Authorization: Bearer gk_your_glyph_api_key" \
    -H "X-Airtable-Key: patXXXXXXXXXXXXXX"
    # Create a preview session with that data
    curl -X POST https://api.glyph.you/v1/preview \
    -H "Authorization: Bearer gk_your_glyph_api_key" \
    -H "Content-Type: application/json" \
    -d '{"template": "quote-modern", "data": { ... }}'
    # Generate the PDF
    curl -X POST https://api.glyph.you/v1/generate \
    -H "Authorization: Bearer gk_your_glyph_api_key" \
    -H "Content-Type: application/json" \
    -d '{"sessionId": "SESSION_ID", "format": "pdf"}' \
    --output invoice.pdf

All Airtable endpoints require two credentials:

  1. Glyph API KeyAuthorization: Bearer gk_your_api_key
  2. Airtable Token — either in the request body (POST /connect) or via the X-Airtable-Key header (all other endpoints)

Validate an Airtable token and list all accessible bases.

Request body:

{
"apiKey": "patXXXXXXXXXXXXXX"
}

The apiKey field must start with pat (Personal Access Token) or key (legacy API key).

Response (200):

{
"success": true,
"bases": [
{
"id": "appXXXXXXXXXXXXXX",
"name": "Sales Pipeline",
"permissionLevel": "create"
}
],
"message": "Connected successfully. Found 1 accessible base(s)."
}

Errors:

CodeStatusMeaning
VALIDATION_ERROR400Missing or empty apiKey
INVALID_KEY_FORMAT400Key does not start with pat or key
AIRTABLE_AUTH_ERROR401Token is invalid, expired, or revoked
CONNECT_ERROR500Unexpected server error

List all tables in a base with field and view counts.

Response (200):

{
"baseId": "appXXXXXXXXXXXXXX",
"tables": [
{
"id": "tblXXXXXXXXXXXXXX",
"name": "Invoices",
"description": "Customer invoices",
"primaryFieldId": "fldXXXXXXXXXXXXXX",
"fieldCount": 12,
"viewCount": 3
}
]
}

Errors:

CodeStatusMeaning
MISSING_AIRTABLE_KEY400X-Airtable-Key header not provided
AIRTABLE_ERROR400Invalid API key or base ID

GET /v1/airtable/bases/:baseId/tables/:tableId/schema

Section titled “GET /v1/airtable/bases/:baseId/tables/:tableId/schema”

Get detailed field schema for a specific table. The tableId parameter accepts either a table ID (tblXXX) or the table name (case-sensitive).

Response (200):

{
"baseId": "appXXXXXXXXXXXXXX",
"table": {
"id": "tblXXXXXXXXXXXXXX",
"name": "Invoices",
"description": "Customer invoices",
"primaryFieldId": "fldXXXXXXXXXXXXXX"
},
"fields": [
{
"id": "fldXXXXXXXXXXXXXX",
"name": "Invoice Number",
"type": "autoNumber",
"description": null
},
{
"id": "fldYYYYYYYYYYYYYY",
"name": "Amount",
"type": "currency",
"options": { "precision": 2, "symbol": "$" }
}
],
"views": [
{ "id": "viwXXXXXXXXXXXXXX", "name": "All Invoices", "type": "grid" }
],
"aiSchema": {
"tableName": "Invoices",
"tableDescription": "Customer invoices",
"fields": [
{
"name": "Invoice Number",
"type": "autoNumber",
"glyphType": "number",
"description": "Invoice Number field",
"mustachePath": "fields.Invoice Number",
"isArray": false,
"hasConditional": true
}
]
}
}

The aiSchema object is designed for AI agents and template engines. It provides:

  • glyphType — the normalized type Glyph uses for rendering
  • mustachePath — the Mustache template path to reference this field
  • isArray — whether the field holds multiple values
  • hasConditional — always true since any Airtable field can be empty

Errors:

CodeStatusMeaning
MISSING_AIRTABLE_KEY400Header not provided
TABLE_NOT_FOUND404Table ID/name does not exist in the base

GET /v1/airtable/bases/:baseId/tables/:tableId/records

Section titled “GET /v1/airtable/bases/:baseId/tables/:tableId/records”

Fetch records from a table. Returns both formatted (template-ready) and raw records.

Query parameters:

ParameterTypeDefaultDescription
maxRecordsnumber5Number of records to return (1—100)
viewstringFilter by Airtable view name

Response (200):

{
"baseId": "appXXXXXXXXXXXXXX",
"tableId": "tblXXXXXXXXXXXXXX",
"tableName": "Invoices",
"recordCount": 2,
"records": [
{
"_id": "recXXXXXXXXXXXXXX",
"_createdTime": "2024-01-15T10:30:00.000Z",
"fields": {
"Invoice Number": "1001",
"Client Name": "Acme Corp",
"Amount": "2,500.00",
"Due Date": "2/15/2024",
"Paid": true
}
}
],
"rawRecords": [
{
"id": "recXXXXXXXXXXXXXX",
"createdTime": "2024-01-15T10:30:00.000Z",
"fields": {
"Invoice Number": 1001,
"Client Name": "Acme Corp",
"Amount": 2500,
"Due Date": "2024-02-15",
"Paid": true
}
}
]
}

records contains formatted values (localized numbers, dates, currency symbols). rawRecords contains the original Airtable values.

Errors:

CodeStatusMeaning
MISSING_AIRTABLE_KEY400Header not provided
TABLE_NOT_FOUND404Table does not exist
RECORDS_ERROR400Failed to fetch records (bad view name, permissions, etc.)

GET /v1/airtable/bases/:baseId/tables/:tableId/records/:recordId

Section titled “GET /v1/airtable/bases/:baseId/tables/:tableId/records/:recordId”

Fetch a single record by its Airtable record ID.

Response (200):

{
"baseId": "appXXXXXXXXXXXXXX",
"tableId": "tblXXXXXXXXXXXXXX",
"tableName": "Invoices",
"record": {
"_id": "recXXXXXXXXXXXXXX",
"_createdTime": "2024-01-15T10:30:00.000Z",
"fields": {
"Invoice Number": "1001",
"Client Name": "Acme Corp",
"Amount": "2,500.00"
}
},
"rawRecord": {
"id": "recXXXXXXXXXXXXXX",
"createdTime": "2024-01-15T10:30:00.000Z",
"fields": {
"Invoice Number": 1001,
"Client Name": "Acme Corp",
"Amount": 2500
}
}
}

Errors:

CodeStatusMeaning
MISSING_AIRTABLE_KEY400Header not provided
TABLE_NOT_FOUND404Table does not exist
RECORD_ERROR400Record not found or inaccessible

Glyph normalizes Airtable field types for optimal PDF rendering. The full mapping:

Airtable TypeGlyph TypeFormatting Applied
singleLineText, multilineText, barcode, aiTexttextNone (pass-through)
richTexthtmlPreserved as markdown
emailemailPass-through
urlurlPass-through
phoneNumberphonePass-through
number, autoNumber, count, ratingnumberLocale-formatted, max 2 decimals
currencycurrencyLocale-formatted, 2 decimal places, currency symbol
percentpercentLocale-formatted
datedatetoLocaleDateString("en-US")
dateTime, createdTime, lastModifiedTimedatetimetoLocaleString("en-US")
durationdurationPass-through
checkboxbooleanConverted to true/false
singleSelectselectSingle string value
multipleSelectsmultiselectArray of strings
attachmentattachmentArray of objects; use fields.FieldName.0.url for first image
multipleRecordLinkslinksArray of record IDs
collaborator, createdBy, lastModifiedByuserPass-through
multipleCollaboratorsusersArray
formulacomputedPass-through
rollupcomputedPass-through
lookuplookupPass-through
buttonbuttonPass-through

AI agents using the Glyph MCP server can work with Airtable data through three dedicated tools.

Register an Airtable table as a data source for PDF generation.

{
"type": "airtable",
"name": "Invoices Table",
"config": {
"apiKey": "patXXXXXXXXXXXXXX",
"baseId": "appXXXXXXXXXXXXXX",
"tableName": "Invoices"
}
}

Returns a sourceId you use in subsequent calls.

Get AI-powered mapping suggestions between a template’s placeholders (e.g., {{client.name}}) and the source’s field names (e.g., “Customer Name”). Returns a list of suggested mappings with confidence scores.

{
"templateId": "tpl_XXXXX",
"sourceId": "src_XXXXX"
}

Generate one or more PDFs using a saved template and a connected data source. Supports single-record generation via recordId or batch generation with filters.

{
"templateId": "tpl_XXXXX",
"sourceId": "src_XXXXX",
"recordId": "recXXXXXXXXXXXXXX"
}
  1. glyph_create_source — connect the Airtable table
  2. glyph_suggest_mappings — let AI map fields to template placeholders
  3. glyph_link_template — save the mapping
  4. glyph_generate_from_source — generate PDFs on demand

Airtable’s Omni AI can interact with the Glyph API to generate PDFs from your data. Here are example prompts you can use:

Generate an invoice:

Generate a PDF invoice for the selected record using Glyph API.
Use the invoice-clean template and map fields from this table.

Create a quote document:

Use the Glyph API to create a professional quote PDF from this record.
Include the client name, line items, and totals.

Batch generate receipts:

For each record in the "Completed Orders" view, generate a receipt PDF
using Glyph's /v1/create endpoint and save the download link to the
"Receipt URL" field.

Airtable Scripting Extension (Quick Start)

Section titled “Airtable Scripting Extension (Quick Start)”

The simplest way to generate a PDF from a record using the one-shot /v1/create endpoint:

// Airtable Scripting Extension - Generate PDF with Glyph
const table = base.getTable('Invoices');
const record = await input.recordAsync('Select a record', table);
const response = await fetch('https://api.glyph.you/v1/create', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
data: {
invoice: { number: record.getCellValue('Invoice Number') },
client: { name: record.getCellValue('Client Name') },
items: record.getCellValue('Line Items') || [],
total: record.getCellValue('Total')
}
})
});
const result = await response.json();
output.markdown(`[Download PDF](${result.url})`);

Airtable Scripting Extension (Full Control)

Section titled “Airtable Scripting Extension (Full Control)”

For more control over templates and the generation process, use this inside an Airtable Scripting block:

// Airtable Scripting Extension
const GLYPH_API_KEY = "gk_your_api_key";
const AIRTABLE_TOKEN = "patXXXXXXXXXXXXXX";
const BASE_ID = "appXXXXXXXXXXXXXX";
const TABLE_ID = "tblXXXXXXXXXXXXXX";
const API = "https://api.glyph.you";
// 1. Get the current record
const table = base.getTable("Invoices");
const record = await input.recordAsync("Pick a record", table);
// 2. Fetch formatted data via Glyph
const dataResp = await fetch(
`${API}/v1/airtable/bases/${BASE_ID}/tables/${TABLE_ID}/records/${record.id}`,
{
headers: {
"Authorization": `Bearer ${GLYPH_API_KEY}`,
"X-Airtable-Key": AIRTABLE_TOKEN,
},
}
);
const { record: formattedRecord } = await dataResp.json();
// 3. Create preview
const previewResp = await fetch(`${API}/v1/preview`, {
method: "POST",
headers: {
"Authorization": `Bearer ${GLYPH_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
template: "quote-modern",
data: {
client: {
name: formattedRecord.fields["Client Name"],
email: formattedRecord.fields["Email"],
},
meta: {
quoteNumber: formattedRecord.fields["Invoice Number"],
date: formattedRecord.fields["Date"],
},
},
}),
});
const { sessionId } = await previewResp.json();
// 4. Generate PDF
const pdfResp = await fetch(`${API}/v1/generate`, {
method: "POST",
headers: {
"Authorization": `Bearer ${GLYPH_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ sessionId, format: "pdf" }),
});
output.markdown(`PDF generated! Session: ${sessionId}`);

Trigger PDF generation when a record enters a view:

  1. In Airtable, create an Automation with trigger “When record enters view”
  2. Add a “Run a script” action
  3. Use the script above, replacing input.recordAsync() with the trigger’s record ID
  4. Optionally add a “Send email” action to deliver the PDF

Airtable Automations - Email with PDF Attachment

Section titled “Airtable Automations - Email with PDF Attachment”

Getting a generated PDF to appear as an email attachment in Airtable requires a specific two-automation pattern. This is because Airtable’s email action can only attach files from attachment fields, not from script outputs.

Why a single automation fails:

  • Script output.set() creates text values, not attachment-compatible sources
  • Using “Find records” between script and email doesn’t help
  • The email action’s Attachment field only recognizes actual attachment field values

The Two-Automation Pattern:

  1. Automation 1: Generate PDF and Save URL

    • Trigger: When record is created (or enters a specific view)
    • Action: Run a script that generates the PDF and writes the URL to an attachment field
  2. Automation 2: Send Email with Attachment

    • Trigger: When “Generated PDF” field is not empty
    • Action: Send email with the attachment field included

This works because the second automation only fires after the attachment field is properly populated by the first automation.

Setting Up the Attachment Field:

In your Airtable table, create a field called “Generated PDF” with type Attachment. This field will store the PDF URL that Airtable converts into a downloadable attachment.

Automation 1: Complete Script

Use this script in your first automation’s “Run a script” action:

// Airtable Automation Script - Generate PDF with Glyph
// This uses /v1/create which returns a hosted URL (required for attachments)
const config = input.config();
const recordId = config.recordId;
const GLYPH_API_KEY = "gk_your_api_key";
const API = "https://api.glyph.you";
// Get the table and record
const table = base.getTable("Invoices");
const record = await table.selectRecordAsync(recordId);
if (!record) {
throw new Error(`Record ${recordId} not found`);
}
// Build the data payload from your record fields
const data = {
invoice: {
number: record.getCellValue("Invoice Number"),
date: record.getCellValue("Date"),
},
client: {
name: record.getCellValue("Client Name"),
email: record.getCellValue("Client Email"),
address: record.getCellValue("Address"),
},
items: record.getCellValue("Line Items") || [],
total: record.getCellValue("Total"),
};
// Call Glyph /v1/create - this returns a hosted PDF URL
const response = await fetch(`${API}/v1/create`, {
method: "POST",
headers: {
"Authorization": `Bearer ${GLYPH_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ data }),
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Glyph API error: ${error}`);
}
const result = await response.json();
const pdfUrl = result.url;
// IMPORTANT: Update the attachment field with the correct format
// Airtable attachment fields require an array of objects with 'url' property
await table.updateRecordAsync(recordId, {
"Generated PDF": [{ url: pdfUrl }]
});
console.log(`PDF generated and saved: ${pdfUrl}`);

Automation 1 Setup:

  1. Create a new automation
  2. Set trigger to “When record is created” (or “When record matches conditions”)
  3. Add input configuration: Add a field called recordId and map it to the triggering record’s ID
  4. Add “Run a script” action with the script above
  5. Replace "gk_your_api_key" with your actual Glyph API key
  6. Adjust field names to match your table schema

Automation 2 Setup:

  1. Create a second automation
  2. Set trigger to “When record matches conditions”
  3. Set condition: Generated PDFis not empty
  4. Add “Send email” action
  5. Configure recipient, subject, and body
  6. In the Attachments field, select your “Generated PDF” field

Common Gotchas:

Troubleshooting:

IssueSolution
”Field ‘Generated PDF’ cannot accept the provided value”Ensure you’re passing [{ url: pdfUrl }] (array format)
Email sends but has no attachmentCheck that Automation 2 trigger fires after the field is populated
Script timeoutLarge PDFs may take longer; consider increasing timeout or using simpler templates
”Record not found”Verify recordId is correctly mapped in automation input config

A complete end-to-end example using only curl:

Terminal window
# Variables
GLYPH_KEY="gk_your_api_key"
AT_KEY="patXXXXXXXXXXXXXX"
BASE="appXXXXXXXXXXXXXX"
TABLE="tblXXXXXXXXXXXXXX"
RECORD="recXXXXXXXXXXXXXX"
API="https://api.glyph.you"
# Step 1: Fetch the record
RECORD_DATA=$(curl -s "$API/v1/airtable/bases/$BASE/tables/$TABLE/records/$RECORD" \
-H "Authorization: Bearer $GLYPH_KEY" \
-H "X-Airtable-Key: $AT_KEY")
echo "$RECORD_DATA" | jq '.record.fields'
# Step 2: Create a preview session
# Map Airtable fields to your template's expected data shape
SESSION_ID=$(curl -s -X POST "$API/v1/preview" \
-H "Authorization: Bearer $GLYPH_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "quote-modern",
"data": {
"client": {
"name": "Acme Corp",
"email": "billing@acme.com"
},
"lineItems": [
{"description": "Consulting", "quantity": 10, "rate": 250}
],
"totals": {
"subtotal": "$2,500.00",
"tax": "$200.00",
"total": "$2,700.00"
},
"meta": {
"quoteNumber": "INV-1001",
"date": "1/27/2026",
"validUntil": "2/27/2026"
}
}
}' | jq -r '.sessionId')
echo "Session: $SESSION_ID"
# Step 3: (Optional) Modify with AI
curl -s -X POST "$API/v1/modify" \
-H "Authorization: Bearer $GLYPH_KEY" \
-H "Content-Type: application/json" \
-d "{
\"sessionId\": \"$SESSION_ID\",
\"prompt\": \"Add a professional header with company logo placeholder\"
}" | jq '.selfCheckPassed'
# Step 4: Generate PDF
curl -s -X POST "$API/v1/generate" \
-H "Authorization: Bearer $GLYPH_KEY" \
-H "Content-Type: application/json" \
-d "{\"sessionId\": \"$SESSION_ID\", \"format\": \"pdf\"}" \
--output invoice.pdf
echo "Saved to invoice.pdf"

The easiest way to get started without writing code:

  1. Visit glyph.you
  2. Click Connect Airtable in the navigation or hero section
  3. Paste your Personal Access Token
  4. Select your Base from the dropdown
  5. Select the Table containing your data
  6. Choose a Template Style that fits your document type
  7. Preview your generated PDF with sample data
  8. Download or refine with AI modifications

Your token must start with pat (Personal Access Token) or key (legacy API key). Create a new token at airtable.com/create/tokens.

Check that:

  • Your token has the required scopes (data.records:read, schema.bases:read)
  • The token has access to the base you are trying to connect
  • The token has not expired or been revoked

The tableId parameter accepts both table IDs (starting with tbl) and table names (case-sensitive). Verify the exact value using the list tables endpoint.

  • Records come back with null for any field that has no value
  • Verify the view name if using the view query parameter
  • Check that your token has read access to the table

All endpoints except POST /connect require the X-Airtable-Key header. Make sure you are sending it as a separate header, not in the request body.