AutomationFlowsData & Sheets › Store Retell Transcripts in Sheets, Airtable or Notion From Webhook

Store Retell Transcripts in Sheets, Airtable or Notion From Webhook

ByAgent Studio @agentstudio on n8n.io

This workflow stores the results of a Retell voice call (transcript, analysis, etc.) once it has ended and been analyzed. It listens for webhook events from Retell and stores the data in Airtable, Google Sheets, and Notion (choose based on your stack). Useful for anyone building…

Webhook trigger★★★★☆ complexity14 nodesAirtableGoogle SheetsNotion
Data & Sheets Trigger: Webhook Nodes: 14 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #3504 — we link there as the canonical source.

This workflow follows the Airtable → Google Sheets 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 →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "85898264-74e1-45c1-8b45-e03f0d840e85",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -760,
        200
      ],
      "parameters": {
        "path": "poc-retell-analysis",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "f0233dbd-d4db-4e95-afd7-a61ef932eba1",
      "name": "Set fields to export",
      "type": "n8n-nodes-base.set",
      "position": [
        -300,
        200
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "bb7a4126-5192-493a-8f26-82e8d7ed1163",
              "name": "Call ID",
              "type": "string",
              "value": "={{ $('Webhook').item.json.body.call.call_id }}"
            },
            {
              "id": "fbbbf26f-219a-45b8-96f9-e22da449e874",
              "name": "Start Datetime",
              "type": "string",
              "value": "={{ $('Webhook').item.json.body.call.start_timestamp.toDateTime('ms').toLocal().toISO() }}"
            },
            {
              "id": "6e429227-e075-439d-af9d-01cad9381fe5",
              "name": "End Datetime",
              "type": "string",
              "value": "={{ $('Webhook').item.json.body.call.end_timestamp.toDateTime('ms').toLocal().toISO() }}"
            },
            {
              "id": "e371b2e7-f288-4bef-bbcc-d6f5d68d5a07",
              "name": "Duration in seconds",
              "type": "number",
              "value": "={{ $('Webhook').item.json.body.call.call_cost.total_duration_seconds }}"
            },
            {
              "id": "42fd4ac0-d00a-4e77-93d6-fe5deb0e8bc4",
              "name": "Transcript",
              "type": "string",
              "value": "={{ $('Webhook').item.json.body.call.transcript }}"
            },
            {
              "id": "46022591-1c73-4796-b968-dbc94b4ef24b",
              "name": "Call Summary",
              "type": "string",
              "value": "={{ $('Webhook').item.json.body.call.call_analysis.call_summary }}"
            },
            {
              "id": "68ab7134-4275-4428-978c-61fb7f229b0e",
              "name": "User Sentiment",
              "type": "string",
              "value": "={{ $('Webhook').item.json.body.call.call_analysis.user_sentiment }}"
            },
            {
              "id": "096991f9-4814-4a89-b5db-771e2f1020fa",
              "name": "Phone Number",
              "type": "string",
              "value": "={{ $if($('Webhook').item.json.body.call.direction == 'outbound', $('Webhook').item.json.body.call.to_number, $('Webhook').item.json.body.call.from_number)  }}"
            },
            {
              "id": "210b3594-e40a-4316-b4ff-7e944172d960",
              "name": "Total Cost in Dollars",
              "type": "number",
              "value": "={{ $json.body.call.call_cost.combined_cost/100 }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "7918d67d-76ca-4425-975b-14a3d3772755",
      "name": "Save to Airtable",
      "type": "n8n-nodes-base.airtable",
      "position": [
        100,
        -40
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "appN4jeIrD8waWCfr",
          "cachedResultUrl": "https://airtable.com/appN4jeIrD8waWCfr",
          "cachedResultName": "Retell sample"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "tbljL3fmuOzAj1Nwo",
          "cachedResultUrl": "https://airtable.com/appN4jeIrD8waWCfr/tbljL3fmuOzAj1Nwo",
          "cachedResultName": "Transcripts"
        },
        "columns": {
          "value": {
            "Call ID": "={{ $json['Call ID'] }}",
            "Transcript": "={{ $json.Transcript }}",
            "Call Summary": "={{ $json['Call Summary'] }}",
            "End Datetime": "={{ $json['End Datetime'] }}",
            "Phone Number": "={{ $json['Phone Number'] }}",
            "Start Datetime": "={{ $json['Start Datetime'] }}",
            "User Sentiment": "={{ $json['User Sentiment'] }}",
            "Duration in seconds": "={{ $json['Duration in seconds'] }}",
            "Total Cost in Dollars": "={{ $json['Total Cost in Dollars'] }}"
          },
          "schema": [
            {
              "id": "Phone Number",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Phone Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "First Name",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "First Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Name",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Last Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Call ID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Call ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Start Datetime",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Start Datetime",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "End Datetime",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "End Datetime",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Duration in seconds",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Duration in seconds",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Transcript",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Transcript",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Call Summary",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Call Summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "User Sentiment",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "User Sentiment",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Cost in Dollars",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Total Cost in Dollars",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "dd353466-3e65-4673-8d87-9f1f872b33e1",
      "name": "Save to Excel",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        100,
        200
      ],
      "parameters": {
        "columns": {
          "value": {
            "Call ID": "={{ $json['Call ID'] }}",
            "Transcript": "={{ $json.Transcript }}",
            "Call Summary": "={{ $json['Call Summary'] }}",
            "End Datetime": "={{ $json['End Datetime'] }}",
            "Phone Number": "='{{ $json['Phone Number'] }}",
            "Start Datetime": "={{ $json['Start Datetime'] }}",
            "User Sentiment": "={{ $json['User Sentiment'] }}",
            "Duration in seconds": "={{ $json['Duration in seconds'] }}",
            "Total Cost in Dollars": "={{ $json['Total Cost in Dollars'] }}"
          },
          "schema": [
            {
              "id": "Phone Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Phone Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "First Name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "First Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Last Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Call ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Call ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Start Datetime",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Start Datetime",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "End Datetime",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "End Datetime",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Duration in seconds",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Duration in seconds",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Transcript",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Transcript",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Call Summary",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Call Summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "User Sentiment",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "User Sentiment",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Cost in Dollars",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Total Cost in Dollars",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "useAppend": true
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 311200653,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TYgk8PK5w2l8Q5NtepdyLvgtuHXBHcODy-2hXOPP6AU/edit#gid=311200653",
          "cachedResultName": "Transcripts"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1TYgk8PK5w2l8Q5NtepdyLvgtuHXBHcODy-2hXOPP6AU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TYgk8PK5w2l8Q5NtepdyLvgtuHXBHcODy-2hXOPP6AU/edit?usp=drivesdk",
          "cachedResultName": "Retell sample UserDB"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "7ce16b86-d7aa-4239-8513-1ccc9a25cdc9",
      "name": "Save to Notion",
      "type": "n8n-nodes-base.notion",
      "position": [
        100,
        440
      ],
      "parameters": {
        "title": "={{ $json['Call Summary'] }}",
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "1cea19b9-d484-8089-bda6-f3d7e05a818d",
          "cachedResultUrl": "https://www.notion.so/1cea19b9d4848089bda6f3d7e05a818d",
          "cachedResultName": "UserDB - Transcripts"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Call ID|rich_text",
              "textContent": "={{ $json['Call ID'] }}"
            },
            {
              "key": "Duration in seconds|number",
              "numberValue": "={{ $json['Duration in seconds'] }}"
            },
            {
              "key": "End Datetime|date",
              "date": "={{ $json['End Datetime'] }}"
            },
            {
              "key": "Phone Number|rich_text",
              "textContent": "={{ $json['Phone Number'] }}"
            },
            {
              "key": "Start Datetime|date",
              "date": "={{ $json['Start Datetime'] }}"
            },
            {
              "key": "Total Cost in Dollars|number",
              "numberValue": "={{ $json['Total Cost in Dollars'] }}"
            },
            {
              "key": "Transcript|rich_text",
              "textContent": "={{ $json.Transcript }}"
            },
            {
              "key": "User Sentiment|rich_text",
              "textContent": "={{ $json['User Sentiment'] }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bbb5b39c-8826-4f59-8c40-ff10529fa42f",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1520,
        -540
      ],
      "parameters": {
        "color": 7,
        "width": 601,
        "height": 1585,
        "content": "## Automatically store Retell transcripts in Google Sheets/Airtable/Notion from webhook\n\n## Overview\n- This workflow stores the results of a **[Retell](https://www.retellai.com/)** voice call (transcript, analysis, etc.) once it has ended and been analyzed.\n- It listens for `call_analyzed` webhook events from Retell and stores the data in **Airtable**, **Google Sheets**, and **Notion** (choose based on your stack).\n- Useful for anyone building Retell agents who want to keep a detailed history of analyzed calls in structured tools.\n\n## Who is it for\nFor builders of [Retell's](https://www.retellai.com/) Voice Agents who want to store call history and essential analytic data.\n\n## Prerequisites\n- Have a [Retell AI Account](https://www.retellai.com/)\n- [Create a Retell agent](https://docs.retellai.com/get-started/quick-start)\n- Associate a phone number with your Retell agent\n- Set up one of the following:\n  - An Airtable base and table (example: \"Transcripts\")\n  - A Google Sheet with a \u201cTranscripts\u201d tab\n  - A Notion database with columns to match the transcript fields\n- Templates:\n  - [Airtable](https://airtable.com/appN4jeIrD8waWCfr/shrsPtQLeqt8Sp3UZ)\n  - [Google Sheets](https://docs.google.com/spreadsheets/d/1TYgk8PK5w2l8Q5NtepdyLvgtuHXBHcODy-2hXOPP6AU/edit?usp=sharing)\n  - [Notion](https://www.notion.so/1cea19b9d4848089bda6f3d7e05a818d?v=1cea19b9d48481ea97ef000ccd20f210&pvs=4)\n\n## How it works\n- Receives a webhook POST request from Retell when a call has been analyzed.\n- Filters out any event that is not `call_analyzed` ([Retell sends webhooks](https://docs.retellai.com/features/webhook-overview#webhook-overview) for `call_started`, `call_ended` and `call_analyzed`)\n- Extracts useful fields like:\n  - Call ID, start/end time, duration, total cost\n  - Transcript, summary, sentiment\n- Stores this data in your preferred tool:\n  - Airtable\n  - Google Sheets\n  - Notion\n\n## How to use it\n1. Copy the webhook URL (e.g., `https://your-instance.app.n8n.cloud/webhook/poc-retell-analysis`) and paste it in your Retell agent under \"Webhook settings\" then \"Agent Level Webhook URL\".\n2. Make sure your Airtable, Google Sheet, or Notion databases are correctly configured to receive the fields.\n3. After each call, once Retell finishes the analysis, this workflow will automatically log the results.\n\n## Extension\n- If you use any \"Post-Call Analysis\" fields, you can add columns to your Airtable, Google Sheet, or Notion database.\n- Then fetch the data from the `call.call_analysis.custom_analysis_data` object.\n\n## Additional Notes\n- Phone numbers are extracted depending on the call direction (`from_number` or `to_number`).\n- Cost is converted from cents to dollars before saving.\n- Dates are converted from timestamps to local ISO strings.\n- You can remove any of the outputs (Airtable, Google Sheets, Notion) if you're only using one.\n\n\n#### \ud83d\udc49 Reach out to [us](mailto:hello@agentstudio.io) if you're interested in **analysing your Retell Agent conversations**."
      },
      "typeVersion": 1
    },
    {
      "id": "5281b143-7b27-4f8e-b55a-98e2a37fa1e8",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -820,
        60
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 300,
        "content": "POST Webhook receiving your Retell events"
      },
      "typeVersion": 1
    },
    {
      "id": "52a7c9ca-d612-4833-9e28-783878f92e92",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -580,
        60
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 300,
        "content": "Only keep the `call_analyzed` events (it contains all data points)"
      },
      "typeVersion": 1
    },
    {
      "id": "6b11df00-34c6-4c2f-b847-f4126d2aeffe",
      "name": "Filter - only call ended",
      "type": "n8n-nodes-base.filter",
      "position": [
        -520,
        200
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d81cb5cf-8fc0-43ff-b191-feec11250154",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.body.event }}",
              "rightValue": "call_analyzed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4c8cb9a2-35fe-42ae-825e-1aab42f152ad",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -340,
        60
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 300,
        "content": "Prepare your data to be sent to your preferred database.\nIf you add more data or post call analytics, you will add fields here."
      },
      "typeVersion": 1
    },
    {
      "id": "8a308e68-365c-4f0a-85f2-a857e7c8011c",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        40,
        -100
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 220,
        "content": "Save all fields from Retell to Airtable"
      },
      "typeVersion": 1
    },
    {
      "id": "c4e71141-8089-4b17-86c2-c290778c49e5",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        40,
        140
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 220,
        "content": "Save all fields from Retell to Google Sheets"
      },
      "typeVersion": 1
    },
    {
      "id": "dad436ca-68db-45c2-8b87-785c650424ca",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        40,
        380
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 220,
        "content": "Save all fields from Retell to Notion"
      },
      "typeVersion": 1
    },
    {
      "id": "57371198-2885-419a-9b12-9f1dfd1388f5",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        40,
        -240
      ],
      "parameters": {
        "color": 3,
        "width": 220,
        "height": 120,
        "content": "Remove the unnecessary tools\n# \ud83d\udc47 "
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Filter - only call ended",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Excel": {
      "main": [
        []
      ]
    },
    "Set fields to export": {
      "main": [
        [
          {
            "node": "Save to Excel",
            "type": "main",
            "index": 0
          },
          {
            "node": "Save to Airtable",
            "type": "main",
            "index": 0
          },
          {
            "node": "Save to Notion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter - only call ended": {
      "main": [
        [
          {
            "node": "Set fields to export",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow stores the results of a Retell voice call (transcript, analysis, etc.) once it has ended and been analyzed. It listens for webhook events from Retell and stores the data in Airtable, Google Sheets, and Notion (choose based on your stack). Useful for anyone building…

Source: https://n8n.io/workflows/3504/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Webhook Filter Export. Uses airtable, googleSheets, notion, stickyNote. Webhook trigger; 14 nodes.

Airtable, Google Sheets, Notion
Data & Sheets

Webhook Googlecalendar. Uses stickyNote, httpRequest, respondToWebhook, airtable. Webhook trigger; 33 nodes.

HTTP Request, Airtable, Google Sheets +1
Data & Sheets

View the YouTube video for this workflow here.

HTTP Request, Airtable, Google Sheets +1
Data & Sheets

This n8n workflow lets you control access to your internal Telegram bots and automation systems based on user roles and departments. It ensures that only authorized team members — defined in your empl

Telegram Trigger, Data Table, Slack Trigger +4
Data & Sheets

Kindwork Client Onboarding - Enterprise Edition. Uses slack, googleDrive, notion, sendGrid. Webhook trigger; 25 nodes.

Slack, Google Drive, Notion +3