Skip to content
Back to skills

Granola Webhooks Events

ASecurity

Handle Granola webhook events and build event-driven automations. Use when building custom integrations, processing meeting events, or creating real-time notification systems. Trigger with phrases like "granola webhooks", "granola events", "granola triggers", "granola real-time", "granola callbacks".

  • 2,688 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added February 7, 2026
developmentjavascriptpythonjavabashexpressflaskdebugginggitapiperformance

Works with

  • cli
  • api

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill granola-webhooks-events --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Granola Webhooks Events?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Granola Webhooks Events
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jeremylongshore-granola-webhooks-events/badge)](https://www.skillsdirectory.com/skills/jeremylongshore-granola-webhooks-events)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: granola-webhooks-events
description: |
  Handle Granola webhook events and build event-driven automations.
  Use when building custom integrations, processing meeting events,
  or creating real-time notification systems.
  Trigger with phrases like "granola webhooks", "granola events",
  "granola triggers", "granola real-time", "granola callbacks".
allowed-tools: Read, Write, Edit, Bash(curl:*)
version: 1.0.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
---

# Granola Webhooks & Events

## Overview
Build event-driven automations using Granola's Zapier webhooks and event triggers.

## Prerequisites
- Granola Pro or Business plan
- Zapier account
- Webhook endpoint (or Zapier as processor)
- Understanding of event-driven architecture

## Available Events

### Granola Zapier Triggers
| Event | Description | Payload |
|-------|-------------|---------|
| New Note Created | Meeting ended, notes ready | Full note data |
| Note Updated | Notes manually edited | Updated content |
| Note Shared | Notes shared with others | Share details |

## Event Payloads

### New Note Created
```json
{
  "event_type": "note.created",
  "timestamp": "2025-01-06T14:30:00Z",
  "data": {
    "note_id": "note_abc123",
    "meeting_title": "Sprint Planning",
    "meeting_date": "2025-01-06",
    "start_time": "2025-01-06T14:00:00Z",
    "end_time": "2025-01-06T14:30:00Z",
    "duration_minutes": 30,
    "attendees": [
      {
        "name": "Sarah Chen",
        "email": "sarah@company.com"
      }
    ],
    "summary": "Discussed Q1 priorities...",
    "action_items": [
      {
        "text": "Review PRs",
        "assignee": "@mike",
        "due_date": "2025-01-08"
      }
    ],
    "key_points": [
      "Agreed on feature freeze date",
      "Sprint velocity improving"
    ],
    "transcript_available": true,
    "granola_url": "https://app.granola.ai/notes/note_abc123"
  }
}
```

### Note Updated
```json
{
  "event_type": "note.updated",
  "timestamp": "2025-01-06T15:00:00Z",
  "data": {
    "note_id": "note_abc123",
    "changes": {
      "summary": {
        "old": "Discussed Q1 priorities...",
        "new": "Finalized Q1 priorities..."
      },
      "action_items": {
        "added": [{"text": "New action", "assignee": "@alex"}],
        "removed": []
      }
    },
    "updated_by": "user@company.com"
  }
}
```

## Webhook Processing

### Zapier Webhook Receiver
```yaml
# Create Catch Hook in Zapier
Trigger: Webhooks by Zapier
Event: Catch Hook
URL: https://hooks.zapier.com/hooks/catch/YOUR_HOOK_ID/

# Configure in Granola (via Zapier integration)
Granola → Zapier → Your Webhook
```

### Custom Webhook Endpoint
```javascript
// Express.js webhook handler
const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhook/granola', (req, res) => {
  const event = req.body;

  console.log(`Received event: ${event.event_type}`);

  switch (event.event_type) {
    case 'note.created':
      handleNewNote(event.data);
      break;
    case 'note.updated':
      handleNoteUpdate(event.data);
      break;
    default:
      console.log('Unknown event type');
  }

  res.status(200).json({ received: true });
});

async function handleNewNote(data) {
  // Process new meeting notes
  console.log(`New note: ${data.meeting_title}`);

  // Extract action items
  for (const action of data.action_items) {
    await createTask(action);
  }

  // Send notification
  await notifyTeam(data);
}

app.listen(3000);
```

### Python Webhook Handler
```python
from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/webhook/granola', methods=['POST'])
def granola_webhook():
    event = request.json

    event_type = event.get('event_type')
    data = event.get('data')

    if event_type == 'note.created':
        process_new_note(data)
    elif event_type == 'note.updated':
        process_note_update(data)

    return jsonify({'status': 'ok'}), 200

def process_new_note(data):
    print(f"Processing: {data['meeting_title']}")

    # Create issues for action items
    for action in data.get('action_items', []):
        create_github_issue(action)

    # Post to Slack
    post_to_slack(data)

if __name__ == '__main__':
    app.run(port=3000)
```

## Event Filtering

### Zapier Filters
```yaml
# Filter by meeting type
Filter Step:
  Condition:
    meeting_title contains "sprint"
    OR meeting_title contains "planning"
    OR attendees count > 3
  Action: Continue

# Filter by content
Filter Step:
  Condition:
    summary contains "decision"
    OR action_items exists
  Action: Continue
```

### Code-Based Filtering
```javascript
// Zapier Code Step
const data = inputData;

// Only process if has action items
if (!data.action_items || data.action_items.length === 0) {
  return { skip: true };
}

// Only process external meetings
const externalDomains = ['client.com', 'partner.org'];
const hasExternal = data.attendees.some(a =>
  externalDomains.some(d => a.email.includes(d))
);

if (!hasExternal) {
  return { skip: true };
}

return { process: true, ...data };
```

## Real-Time Processing Patterns

### Pattern 1: Immediate Notification
```yaml
Event Flow:
  Meeting Ends (T+0)
       ↓
  Notes Ready (T+2 min)
       ↓
  Webhook Fires (T+2.1 min)
       ↓
  Slack Notification (T+2.2 min)

Total Latency: ~2-3 minutes
```

### Pattern 2: Batch Processing
```yaml
Event Flow:
  Notes Created → Queue
       ↓
  Every 15 minutes:
    - Aggregate notes
    - Generate digest
    - Send single notification

Use Case: Reduce notification noise
```

### Pattern 3: Conditional Routing
```yaml
Event Received:
  │
  ├── If external attendee → CRM Update
  │
  ├── If action items > 3 → Create Project
  │
  ├── If duration > 60 min → Request Summary
  │
  └── Default → Standard Processing
```

## Error Handling

### Retry Logic
```javascript
async function processWithRetry(data, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await processEvent(data);
      return { success: true };
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error);

      if (attempt === maxRetries) {
        await notifyError(data, error);
        return { success: false, error };
      }

      // Exponential backoff
      await sleep(Math.pow(2, attempt) * 1000);
    }
  }
}
```

### Dead Letter Queue
```yaml
On Error:
  1. Log error details
  2. Store failed event in queue
  3. Alert ops team
  4. Retry after 1 hour
  5. If still failing, archive for manual review
```

## Monitoring & Observability

### Event Logging
```javascript
// Log all events for debugging
function logEvent(event) {
  const log = {
    timestamp: new Date().toISOString(),
    event_type: event.event_type,
    note_id: event.data.note_id,
    meeting_title: event.data.meeting_title,
    processing_time: Date.now()
  };

  console.log(JSON.stringify(log));
}
```

### Metrics to Track
| Metric | Description | Alert Threshold |
|--------|-------------|-----------------|
| Events/hour | Processing volume | > 100/hr |
| Latency | Time to process | > 30 seconds |
| Error rate | Failed events | > 5% |
| Queue depth | Pending events | > 50 |

## Resources
- [Zapier Webhooks](https://zapier.com/help/create/code-webhooks)
- [Webhook Best Practices](https://zapier.com/blog/webhook-best-practices)

## Next Steps
Proceed to `granola-performance-tuning` for optimization techniques.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.