Skip to content

Airtable API

The Airtable API lets you connect an Airtable base, explore its schema, fetch records, and use that data to generate PDFs. These endpoints act as a proxy to the Airtable API, handling authentication and formatting records for template rendering.

MethodEndpointDescription
POST/v1/airtable/connectValidate an Airtable token and list accessible bases
GET/v1/airtable/bases/:baseId/tablesList tables in a base
GET/v1/airtable/bases/:baseId/tables/:tableId/schemaGet field schema for a table
GET/v1/airtable/bases/:baseId/tables/:tableId/recordsFetch sample records
GET/v1/airtable/bases/:baseId/tables/:tableId/records/:recordIdGet a single record

POST /v1/airtable/connect

Validate an Airtable Personal Access Token (PAT) and return a list of accessible bases. This is the first step in the Airtable integration flow.

HeaderRequiredDescription
AuthorizationYesBearer gk_your_api_key
Content-TypeYesapplication/json
{
"apiKey": "patXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
ParameterTypeRequiredDescription
apiKeystringYesAirtable Personal Access Token (pat...) or legacy API key (key...)
{
"success": true,
"bases": [
{
"id": "appXXXXXXXXXXXXXX",
"name": "Sales Pipeline",
"permissionLevel": "create"
},
{
"id": "appYYYYYYYYYYYYYY",
"name": "Invoices",
"permissionLevel": "read"
}
],
"message": "Connected successfully. Found 2 accessible base(s)."
}
FieldTypeDescription
successbooleanWhether the connection succeeded
basesarrayList of accessible Airtable bases
bases[].idstringBase ID (starts with app)
bases[].namestringHuman-readable base name
bases[].permissionLevelstringPermission level (read, comment, edit, create)
messagestringSummary message

400 Bad Request — Invalid key format

{
"error": "Invalid Airtable API key format. Keys should start with 'pat' (personal access token) or 'key' (legacy).",
"code": "INVALID_KEY_FORMAT"
}

401 Unauthorized — Invalid token

{
"error": "Failed to connect to Airtable. Please check your API key.",
"code": "AIRTABLE_AUTH_ERROR"
}
Terminal window
curl -X POST https://api.glyph.you/v1/airtable/connect \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{"apiKey": "patXXXXXXXXXXXXXX.XXXX"}'
const response = await fetch('https://api.glyph.you/v1/airtable/connect', {
method: 'POST',
headers: {
'Authorization': 'Bearer gk_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
apiKey: 'patXXXXXXXXXXXXXX.XXXX'
})
});
const { success, bases } = await response.json();
if (success) {
for (const base of bases) {
console.log(`${base.name} (${base.id}) - ${base.permissionLevel}`);
}
}
import requests
response = requests.post(
'https://api.glyph.you/v1/airtable/connect',
headers={
'Authorization': 'Bearer gk_your_api_key',
'Content-Type': 'application/json'
},
json={'apiKey': 'patXXXXXXXXXXXXXX.XXXX'}
)
result = response.json()
if result['success']:
for base in result['bases']:
print(f"{base['name']} ({base['id']}) - {base['permissionLevel']}")

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

List all tables in an Airtable base with their field counts and view counts.

HeaderRequiredDescription
AuthorizationYesBearer gk_your_api_key
X-Airtable-KeyYesAirtable PAT for accessing the base
ParameterTypeDescription
baseIdstringAirtable base ID (e.g. appXXXXXXXXXXXXXX)
{
"success": true,
"baseId": "appXXXXXXXXXXXXXX",
"tables": [
{
"id": "tblXXXXXXXXXXXXXX",
"name": "Orders",
"description": "All customer orders",
"primaryFieldId": "fldXXXXXXXXXXXXXX",
"fieldCount": 12,
"viewCount": 3
}
]
}
FieldTypeDescription
tables[].idstringTable ID
tables[].namestringTable name
tables[].descriptionstringTable description (if set in Airtable)
tables[].primaryFieldIdstringID of the primary field
tables[].fieldCountnumberNumber of fields in the table
tables[].viewCountnumberNumber of views
Terminal window
curl https://api.glyph.you/v1/airtable/bases/appXXXXXXXXXXXXXX/tables \
-H "Authorization: Bearer gk_your_api_key" \
-H "X-Airtable-Key: patXXXXXXXXXXXXXX.XXXX"
const response = await fetch(
'https://api.glyph.you/v1/airtable/bases/appXXXXXXXXXXXXXX/tables',
{
headers: {
'Authorization': 'Bearer gk_your_api_key',
'X-Airtable-Key': 'patXXXXXXXXXXXXXX.XXXX'
}
}
);
const { tables } = await response.json();
for (const table of tables) {
console.log(`${table.name}: ${table.fieldCount} fields, ${table.viewCount} views`);
}

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

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

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

Get the detailed field schema for a table, including field types, descriptions, and AI-optimized schema output.

HeaderRequiredDescription
AuthorizationYesBearer gk_your_api_key
X-Airtable-KeyYesAirtable PAT
ParameterTypeDescription
baseIdstringAirtable base ID
tableIdstringTable ID or table name
{
"success": true,
"baseId": "appXXXXXXXXXXXXXX",
"table": {
"id": "tblXXXXXXXXXXXXXX",
"name": "Orders",
"description": "All customer orders",
"primaryFieldId": "fldXXXXXXXXXXXXXX"
},
"fields": [
{
"id": "fldXXXXXXXXXXXXXX",
"name": "Order Number",
"type": "singleLineText",
"description": "Unique order identifier",
"options": null
},
{
"id": "fldYYYYYYYYYYYYYY",
"name": "Total",
"type": "currency",
"description": null,
"options": {
"precision": 2,
"symbol": "$"
}
}
],
"views": [
{
"id": "viwXXXXXXXXXXXXXX",
"name": "Grid view",
"type": "grid"
}
],
"aiSchema": "Order Number (singleLineText), Total (currency), ..."
}
FieldTypeDescription
fields[].idstringField ID
fields[].namestringHuman-readable field name
fields[].typestringAirtable field type (e.g. singleLineText, currency, multipleRecordLinks)
fields[].descriptionstringField description (if set)
fields[].optionsobjectType-specific options (precision, choices, linked table, etc.)
viewsarrayAvailable views for filtering records
aiSchemastringAI-optimized schema summary for template generation
Terminal window
curl https://api.glyph.you/v1/airtable/bases/appXXXX/tables/tblXXXX/schema \
-H "Authorization: Bearer gk_your_api_key" \
-H "X-Airtable-Key: patXXXXXXXXXXXXXX.XXXX"

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

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

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

Fetch sample records from a table. Records are returned in both raw Airtable format and a template-friendly format.

HeaderRequiredDescription
AuthorizationYesBearer gk_your_api_key
X-Airtable-KeyYesAirtable PAT
ParameterTypeDescription
baseIdstringAirtable base ID
tableIdstringTable ID or table name
ParameterTypeDefaultDescription
maxRecordsnumber5Number of records to fetch (1-100)
viewstringAirtable view name or ID to filter records
{
"success": true,
"baseId": "appXXXXXXXXXXXXXX",
"tableId": "tblXXXXXXXXXXXXXX",
"tableName": "Orders",
"recordCount": 5,
"records": [
{
"Order Number": "ORD-001",
"Customer": "Acme Corp",
"Total": "$1,500.00",
"Status": "Paid"
}
],
"rawRecords": [
{
"id": "recXXXXXXXXXXXXXX",
"createdTime": "2026-01-15T10:00:00.000Z",
"fields": {
"Order Number": "ORD-001",
"Customer": "Acme Corp",
"Total": 1500,
"Status": { "name": "Paid", "color": "greenBright" }
}
}
]
}
FieldTypeDescription
recordsarrayTemplate-friendly records with formatted values (currency symbols, dates, etc.)
rawRecordsarrayRaw Airtable records with original field types
rawRecords[].idstringAirtable record ID
rawRecords[].fieldsobjectRaw field values
Terminal window
# Fetch 10 records from a specific view
curl "https://api.glyph.you/v1/airtable/bases/appXXXX/tables/tblXXXX/records?maxRecords=10&view=Grid%20view" \
-H "Authorization: Bearer gk_your_api_key" \
-H "X-Airtable-Key: patXXXXXXXXXXXXXX.XXXX"
const baseId = 'appXXXXXXXXXXXXXX';
const tableId = 'tblXXXXXXXXXXXXXX';
const response = await fetch(
`https://api.glyph.you/v1/airtable/bases/${baseId}/tables/${tableId}/records?maxRecords=10`,
{
headers: {
'Authorization': 'Bearer gk_your_api_key',
'X-Airtable-Key': airtableToken
}
}
);
const { records, recordCount } = await response.json();
console.log(`Fetched ${recordCount} records`);
// Use the first record to generate a PDF
const pdfResponse = await fetch('https://api.glyph.you/v1/create', {
method: 'POST',
headers: {
'Authorization': 'Bearer gk_your_api_key',
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
data: records[0],
intent: 'professional invoice'
})
});

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

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

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

Fetch a single record by its Airtable record ID.

HeaderRequiredDescription
AuthorizationYesBearer gk_your_api_key
X-Airtable-KeyYesAirtable PAT
ParameterTypeDescription
baseIdstringAirtable base ID
tableIdstringTable ID or table name
recordIdstringAirtable record ID (starts with rec)
{
"success": true,
"baseId": "appXXXXXXXXXXXXXX",
"tableId": "tblXXXXXXXXXXXXXX",
"tableName": "Orders",
"record": {
"Order Number": "ORD-001",
"Customer": "Acme Corp",
"Total": "$1,500.00"
},
"rawRecord": {
"id": "recXXXXXXXXXXXXXX",
"createdTime": "2026-01-15T10:00:00.000Z",
"fields": {
"Order Number": "ORD-001",
"Customer": "Acme Corp",
"Total": 1500
}
}
}
Terminal window
curl https://api.glyph.you/v1/airtable/bases/appXXXX/tables/tblXXXX/records/recXXXX \
-H "Authorization: Bearer gk_your_api_key" \
-H "X-Airtable-Key: patXXXXXXXXXXXXXX.XXXX"

Here is a complete example that connects to Airtable, fetches a record, and generates a PDF:

const GLYPH_KEY = 'gk_your_api_key';
const AIRTABLE_TOKEN = 'patXXXXXXXXXXXXXX.XXXX';
// Step 1: Connect and find the base
const connectRes = await fetch('https://api.glyph.you/v1/airtable/connect', {
method: 'POST',
headers: {
'Authorization': `Bearer ${GLYPH_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ apiKey: AIRTABLE_TOKEN })
});
const { bases } = await connectRes.json();
const baseId = bases[0].id;
// Step 2: List tables
const tablesRes = await fetch(
`https://api.glyph.you/v1/airtable/bases/${baseId}/tables`,
{
headers: {
'Authorization': `Bearer ${GLYPH_KEY}`,
'X-Airtable-Key': AIRTABLE_TOKEN
}
}
);
const { tables } = await tablesRes.json();
const tableId = tables[0].id;
// Step 3: Fetch records
const recordsRes = await fetch(
`https://api.glyph.you/v1/airtable/bases/${baseId}/tables/${tableId}/records?maxRecords=1`,
{
headers: {
'Authorization': `Bearer ${GLYPH_KEY}`,
'X-Airtable-Key': AIRTABLE_TOKEN
}
}
);
const { records } = await recordsRes.json();
// Step 4: Generate PDF from the record data
const pdfRes = await fetch('https://api.glyph.you/v1/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${GLYPH_KEY}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
data: records[0],
intent: 'professional invoice',
style: 'stripe-clean'
})
});
const pdf = await pdfRes.json();
console.log(`Generated: ${pdf.filename} (${pdf.size} bytes)`);

All Airtable endpoints share these common errors:

StatusCodeDescription
400VALIDATION_ERRORInvalid request data
400INVALID_KEY_FORMATAirtable key does not start with pat or key
400MISSING_REQUIREDMissing X-Airtable-Key header
401AIRTABLE_AUTH_ERRORInvalid Airtable token
404NOT_FOUNDTable or record not found
502AIRTABLE_ERRORFailed to communicate with Airtable API