This workflow corresponds to n8n.io template #11761 — we link there as the canonical source.
This workflow follows the Airtable → OpenAI recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "zlC4TinZxwU0uRNb",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "TPL",
"tags": [],
"nodes": [
{
"id": "babf989a-7fd3-4dd1-b451-f3c849722a07",
"name": "OpenAI Enhancement",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
2144,
1440
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "chatgpt-4o-latest"
},
"options": {},
"responses": {
"values": [
{
"content": "=You are an AI assistant that categorizes invoice items.\n\nTask:\n- Look at the Invoice-Items from the following TOON data:\n{{ $json.toon }}\n\n- Review all invoices and consider the appropriate categories. Assign exactly one category to each invoice item:\n\n- First, structure the result as a JSON array like this:\n[\n { \"category\": \"web_development\" },\n { \"category\": \"system_administration\" }\n]\n\n- Then, **convert this JSON array into TOON notation**.\n- Return **only the TOON notation**, do not include quotes, JSON braces, escaped characters, or explanations.\n"
}
]
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "7f537c67-d5b8-40e5-8212-844ea91c13a7",
"name": "JSON to TOON",
"type": "@custom-js/n8n-nodes-pdf-toolkit.jsonToToon",
"position": [
1984,
1440
],
"parameters": {
"jsonData": "={{ $json }}"
},
"credentials": {
"customJsApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "baf16dab-4b75-4c13-bae6-bb9bd59d802c",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
384,
1456
],
"parameters": {},
"typeVersion": 1
},
{
"id": "4dd1d8ee-d620-4095-9d3b-5b962f7a17d1",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-912,
848
],
"parameters": {
"width": 1120,
"height": 1776,
"content": "# Categorizing invoices with TOON optimization\n\nHere is an example of how you can categorize all \nyour invoices in Airtable, from our [invoice creation example](https://n8n.io/workflows/9772-automatic-invoice-generation-and-email-with-airtable-and-customjs-pdf-generator/):\n\nTo save OpenAI tokens, we convert them into [TOON](https://github.com/toon-format/toon) and back again.\n\n### Setup \n- This workflow uses the CustomJS JSON to TOON node from [CustomJS](https://www.customjs.space), which requires a self-hosted n8n instance and a CustomJS API key.\n- You will also need an API key for an Airtable table, which you can clone if you like. [Public Airtable Example](https://airtable.com/apphyDa3uYAq0VOMW/shrSe39NZYrqm4gtE)\n\n\n### How it works \n1. **Manual Trigger** \n Run the workflow on demand\n\n2. **Load Data from Airtable** \n - Fetch ready invoices \n - Resolve related clients \n - Fetch and aggregate invoice items \n\n3. **Prepare Structured Context** \n Group client, invoice, and invoice items into a single object\n\n4. **JSON \u2192 TOON** \n Convert structured data into token-efficient TOON\n\n5. **AI Categorization** \n - OpenAI receives TOON data \n - Assigns exactly one category per invoice \n - Returns only TOON (no JSON, no prose)\n\n6. **TOON \u2192 JSON** \n Convert AI output back into valid JSON\n\n7. **Persist Result** \n Update the invoice category field in Airtable\n\n@[youtube](QX6ffaf-uvA)"
},
"typeVersion": 1
},
{
"id": "db143ee8-cab9-49af-97d3-a1b839499058",
"name": "Get Ready Invoices",
"type": "n8n-nodes-base.airtable",
"position": [
592,
1456
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "apphyDa3uYAq0VOMW",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW",
"cachedResultName": "Custom JS - Invoicing Template"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblW46vfkwOFQJLMs",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW/tblW46vfkwOFQJLMs",
"cachedResultName": "Invoices"
},
"options": {},
"operation": "search"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "cc0fabf3-3634-4799-acab-b50a9c0f1459",
"name": "Get Clients",
"type": "n8n-nodes-base.airtable",
"position": [
1472,
1440
],
"parameters": {
"id": "={{ $('Get Ready Invoices').item.json['Client ID'][0] }}",
"base": {
"__rl": true,
"mode": "list",
"value": "apphyDa3uYAq0VOMW",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW",
"cachedResultName": "Custom JS - Invoicing Template"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblQdiFVsZ9w3sahJ",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW/tblQdiFVsZ9w3sahJ",
"cachedResultName": "Clients"
},
"options": {}
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "fc2f2761-8bc4-4151-b508-f0be45e40eae",
"name": "Get Invoice Items",
"type": "n8n-nodes-base.airtable",
"position": [
976,
1568
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "apphyDa3uYAq0VOMW",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW",
"cachedResultName": "Custom JS - Invoicing Template"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblASYLVpsnrUoKt5",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW/tblASYLVpsnrUoKt5",
"cachedResultName": "Invoice-Items"
},
"options": {},
"operation": "search",
"filterByFormula": "=FIND(\"{{ $json.ID }}\", ARRAYJOIN({Invoice}))"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "c4a6c493-dbee-4ef3-8c02-74a5609f2f4f",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
1296,
1568
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData",
"destinationFieldName": "items"
},
"typeVersion": 1
},
{
"id": "9a8696bd-459d-49a9-b848-e68a0c0a6e9c",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
800,
1456
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "3bbef89f-1f29-4cc9-9bbf-a2cb64022b37",
"name": "Update record",
"type": "n8n-nodes-base.airtable",
"position": [
2720,
1440
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "apphyDa3uYAq0VOMW",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW",
"cachedResultName": "Custom JS - Invoicing Template"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblW46vfkwOFQJLMs",
"cachedResultUrl": "https://airtable.com/apphyDa3uYAq0VOMW/tblW46vfkwOFQJLMs",
"cachedResultName": "Invoices"
},
"columns": {
"value": {
"id": "={{ $('Get Ready Invoices').item.json.id }}",
"Category": "={{ $json.json.category }}"
},
"schema": [
{
"id": "id",
"type": "string",
"display": true,
"readOnly": true,
"required": false,
"displayName": "id",
"defaultMatch": true
},
{
"id": "ID",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client ID",
"type": "array",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "Client ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Name",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Client Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Description (from Invoice-Items)",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Description (from Invoice-Items)",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Total",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Total",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Invoicedate",
"type": "dateTime",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "Invoicedate",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "options",
"display": true,
"options": [
{
"name": "Delayed",
"value": "Delayed"
},
{
"name": "Sent",
"value": "Sent"
},
{
"name": "Paid",
"value": "Paid"
},
{
"name": "Ready",
"value": "Ready"
}
],
"removed": true,
"readOnly": false,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Category",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Create Invoice (Airtable API)",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Create Invoice (Airtable API)",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Create Invoice (Get Parameters)",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Create Invoice (Get Parameters)",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Invoice-Items",
"type": "array",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "Invoice-Items",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Prices (from Invoice-Items)",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Prices (from Invoice-Items)",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Default Hourly Rate (from Client ID)",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Default Hourly Rate (from Client ID)",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Total (from Invoice-Items)",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "Total (from Invoice-Items)",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ClientAddressField1",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "ClientAddressField1",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ClientAddressField2",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "ClientAddressField2",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ClientTax",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "ClientTax",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "70a430e2-932f-41e3-a431-ce3b0e70ef0e",
"name": "Map Fields",
"type": "n8n-nodes-base.set",
"position": [
1136,
1568
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a95b61df-c10d-43f1-b005-d6d84c6fec47",
"name": "description",
"type": "string",
"value": "={{ $json.Description }}"
},
{
"id": "f290e440-dd5b-46f9-a23b-be419443685b",
"name": "quantity",
"type": "string",
"value": "={{ $json.Hours }}"
},
{
"id": "09688f5f-0461-4c04-988a-2b92da3e595e",
"name": "unitPrice",
"type": "string",
"value": "={{ $json['Custom Hourly Rate'] || $json['Default Hourly Rate'][0]}}"
},
{
"id": "bcdadef7-0f5b-48a3-851b-f7fe5f401fa7",
"name": "invoiceId",
"type": "string",
"value": "={{ $json.ID }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "7689029a-47eb-4aa3-b296-cfe4ae9e0d7b",
"name": "GroupClientAndInvoice",
"type": "n8n-nodes-base.set",
"position": [
1776,
1440
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "44c69f01-7e87-4fb9-8ab6-31fc966073a6",
"name": "clientAndInvoiceData",
"type": "object",
"value": "={ \n \"client\": {{ JSON.stringify($json) }}, \n \"invoice\": {{ JSON.stringify($('Get Ready Invoices').item.json) }} \n}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "68528c43-c25e-4941-9e47-e12c65550214",
"name": "TOON to JSON",
"type": "@custom-js/n8n-nodes-pdf-toolkit.toonToJson",
"position": [
2432,
1440
],
"parameters": {
"toonData": "={{ $json.output[0].content[0].text }}"
},
"credentials": {
"customJsApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "0a0c52fb-2716-4a13-a2a7-bf5457744edc",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
320,
1376
],
"parameters": {
"color": 7,
"width": 1296,
"height": 416,
"content": "## Collect invoice data from Airtable"
},
"typeVersion": 1
},
{
"id": "f1346b90-3f73-4b36-a52a-06139c7ee7d0",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1744,
1376
],
"parameters": {
"color": 7,
"width": 832,
"height": 416,
"content": "## Categorizing Invoices"
},
"typeVersion": 1
},
{
"id": "e3650253-bfd2-4307-af75-66015c69e265",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2672,
1376
],
"parameters": {
"color": 7,
"width": 432,
"height": 416,
"content": "## Save categories back to Airtable"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "b0be609b-1d3d-4916-a554-d6c1827c73bd",
"connections": {
"Aggregate": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Map Fields": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
},
"Get Clients": {
"main": [
[
{
"node": "GroupClientAndInvoice",
"type": "main",
"index": 0
}
]
]
},
"JSON to TOON": {
"main": [
[
{
"node": "OpenAI Enhancement",
"type": "main",
"index": 0
}
]
]
},
"TOON to JSON": {
"main": [
[
{
"node": "Update record",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Get Clients",
"type": "main",
"index": 0
}
],
[
{
"node": "Get Invoice Items",
"type": "main",
"index": 0
}
]
]
},
"Get Invoice Items": {
"main": [
[
{
"node": "Map Fields",
"type": "main",
"index": 0
}
]
]
},
"Get Ready Invoices": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Enhancement": {
"main": [
[
{
"node": "TOON to JSON",
"type": "main",
"index": 0
}
]
]
},
"GroupClientAndInvoice": {
"main": [
[
{
"node": "JSON to TOON",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Get Ready Invoices",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
airtableTokenApicustomJsApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
> ⚠️ Notice: > This workflow uses the CustomJS JSON to TOON node from CustomJS, which requires a self-hosted n8n instance and a CustomJS API key.
Source: https://n8n.io/workflows/11761/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow delivers a complete, enterprise-grade Gmail automation system designed for high-volume teams. It classifies incoming emails, applies labels, generates AI-powered responses, and routes me
Domain Outbound Machine is an n8n workflow designed to fully automate the domain sales process: lead generation, email extraction, personalized outreach, and automated email sending. It also stores ex
Social Media Audio Extractor. Uses telegramTrigger, telegram, openAi, httpRequest. Event-driven trigger; 31 nodes.
Baby Chaganti. Uses httpRequest, googleDrive, youTube, openAi. Event-driven trigger; 23 nodes.
Monitor YouTube channels, fetch stats, classify videos as viral (≥ 1000 likes) or normal, and auto‑generate LinkedIn/email summaries with GPT‑4. Deliver via Gmail or SMTP. Clear node names, examples,