{
  "id": "50m5IQ7jh5DnUkuB",
  "name": "Zoom Meeting to Notion Summary",
  "tags": [],
  "nodes": [
    {
      "id": "d93e9690-a1ed-4a26-83a8-602d9fce4055",
      "name": "Zoom Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -640,
        128
      ],
      "parameters": {
        "path": "transcribe-zoom-meeting",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "d786e6c9-f47b-4b75-9b61-cea0ea4c6ab2",
      "name": "Url validation",
      "type": "n8n-nodes-base.if",
      "position": [
        -368,
        128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5a1e56bf-e698-426a-8434-915f7d56ca92",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.body.event }}",
              "rightValue": "endpoint.url_validation"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2013f8d6-77e0-4aa2-bf8d-1346178dca38",
      "name": "Compute Zoom CRC",
      "type": "n8n-nodes-base.crypto",
      "position": [
        -64,
        32
      ],
      "parameters": {
        "type": "SHA256",
        "value": "={{ $json.body.payload.plainToken }}",
        "action": "hmac",
        "secret": "YOUR_CREDENTIAL_HERE",
        "dataPropertyName": "encryptedToken"
      },
      "typeVersion": 1
    },
    {
      "id": "e736eb79-6c35-4935-999d-64359a272b93",
      "name": "Zoom CRC Response",
      "type": "n8n-nodes-base.set",
      "position": [
        144,
        32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1b86fa30-5eac-4fd2-aaa5-9467b8c5673f",
              "name": "plainToken",
              "type": "string",
              "value": "={{ $json.body.payload.plainToken }}"
            },
            {
              "id": "d4607b21-1f55-4aae-85e7-5a143d5cf644",
              "name": "encryptedToken",
              "type": "string",
              "value": "={{ $json.encryptedToken }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "96bd0fa9-bb6e-4b6e-a751-e3fc9d27a122",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        368,
        32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.4
    },
    {
      "id": "02925d16-92c7-4061-b791-9d1a2e05fd25",
      "name": "Respond 200 (acknowledge)",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -64,
        272
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "ok"
      },
      "typeVersion": 1.4
    },
    {
      "id": "1b9a04d7-9012-4274-add5-700f86361906",
      "name": "Extract Audio File",
      "type": "n8n-nodes-base.code",
      "position": [
        160,
        272
      ],
      "parameters": {
        "jsCode": "const body = $input.first().json.body;\nconst obj = body.payload.object;\nconst files = obj.recording_files || [];\n\nconst audio = files.find(f => f.file_type === 'M4A')\n  || files.find(f => f.file_type === 'MP4')\n  || files[0];\nreturn [{\n  json: {\n    topic: obj.topic,\n    start_time: obj.start_time,\n    host_email: obj.host_email,\n    download_url: audio ? audio.download_url : null,\n    download_token: body.download_token\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "438a72b8-b8e7-4f49-920d-32e1453d94fa",
      "name": "Download Recording",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        368,
        272
      ],
      "parameters": {
        "url": "={{ $json.download_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $json.download_token }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4736ee60-d90f-4c63-a0cf-56313a1f3448",
      "name": "Transcribe audio",
      "type": "n8n-nodes-smallestai.smallestai",
      "position": [
        576,
        272
      ],
      "parameters": {
        "resource": "stt",
        "additionalOptions": {}
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "cc98742a-16dc-429b-9103-62698f1d835c",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        752,
        272
      ],
      "parameters": {
        "text": "=Meeting: {{ $('Extract Audio File').item.json.topic }}\n\nTranscript:\n{{ $json.transcription }}",
        "options": {
          "systemMessage": "You are a meeting assistant. From the transcript, produce: (1) a 3-sentence summary, then (2) a bulleted list of action items, each with an owner if one is mentioned. Be concise and clear."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "aa87a323-538a-4df6-b99d-95255604272c",
      "name": "Create a Notion page",
      "type": "n8n-nodes-base.notion",
      "position": [
        1088,
        272
      ],
      "parameters": {
        "title": "={{ $('Extract Audio File').item.json.topic }}",
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $json.output }}"
            }
          ]
        },
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "388498f3-71cb-80cd-a524-f1867f3399ab",
          "cachedResultUrl": "https://app.notion.com/p/388498f371cb80cda524f1867f3399ab",
          "cachedResultName": "Meetings"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "ce1d132e-293b-47c2-a650-d7696c3f676a",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        752,
        496
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "8bb89b2a-60cc-4a58-8153-0d5cb975cc63",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1392,
        -80
      ],
      "parameters": {
        "width": 656,
        "height": 544,
        "content": "## Zoom Meeting to Notion Summary\n\n### How it works\nThis workflow automates meeting documentation by listening for Zoom recording webhooks. When a meeting ends, it automatically handles Zoom's URL challenge validation (CRC check) to keep the webhook active. For recording events, it extracts the appropriate audio file download URL, securely downloads the recording using Zoom's download token, and transcribes the audio via Smallest.ai. An AI Agent powered by Google Gemini then summarizes the transcript and lists action items before creating a structured summary page inside your Notion database.\n\n### Setup steps\n* Configure a **Zoom Webhook** app (e.g., Event Notifications for \"Recording Completed\") pointing to this workflow's webhook URL.\n* Set your Zoom verification token as the secret value inside the **Compute Zoom CRC** node.\n* Connect your **Smallest.ai** API credentials to the transcription node.\n* Authenticate your **Google Gemini** API account within the LangChain Chat Model node.\n* Link your **Notion** account and select the target database where meeting summaries should be created.\n\n### Customization\nYou can tweak the system prompt inside the **AI Agent** node to enforce corporate styles, extract specific tables, or flag urgent follow-ups. You can also modify the **Create a Notion page** properties mapping to sync extra meeting metadata like host email or date fields."
      },
      "typeVersion": 1
    },
    {
      "id": "50a888bf-69f6-411b-9f3e-a3df3c1e1c5e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -672,
        32
      ],
      "parameters": {
        "color": 7,
        "width": 464,
        "height": 272,
        "content": "## Zoom Webhook & CRC Validation\n."
      },
      "typeVersion": 1
    },
    {
      "id": "4811c904-638a-4bfb-9dbb-67e8ff148a9e",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 480,
        "content": "## Audio Extraction & Download\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d6ed4509-18bd-4e7d-97da-53c00819da76",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 480,
        "content": "## Speech-to-Text Transcription\n"
      },
      "typeVersion": 1
    },
    {
      "id": "3c83a118-68f5-4f90-b0ea-f47c37f85147",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 272,
        "content": "## AI Insights & Notion Export\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "ee43c5b7-a202-44a6-9a32-7107d6b6d965",
  "nodeGroups": [],
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Create a Notion page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Zoom Webhook": {
      "main": [
        [
          {
            "node": "Url validation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Url validation": {
      "main": [
        [
          {
            "node": "Compute Zoom CRC",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond 200 (acknowledge)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compute Zoom CRC": {
      "main": [
        [
          {
            "node": "Zoom CRC Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transcribe audio": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Zoom CRC Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Recording": {
      "main": [
        [
          {
            "node": "Transcribe audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Audio File": {
      "main": [
        [
          {
            "node": "Download Recording",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Respond 200 (acknowledge)": {
      "main": [
        [
          {
            "node": "Extract Audio File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}