sendgrid-webhooks
>
Works with
---
name: sendgrid-webhooks
description: >
license: MIT
---
# SendGrid Webhooks
## When to Use This Skill
- Setting up SendGrid webhook handlers for email delivery tracking
- Debugging ECDSA signature verification failures
- Processing email events (bounce, delivered, open, click, spam report)
- Implementing email engagement analytics
## Essential Code
### Signature Verification (Manual)
SendGrid uses ECDSA (Elliptic Curve Digital Signature Algorithm) with public key verification.
```javascript
// Node.js manual verification
const crypto = require('crypto');
function verifySignature(publicKey, payload, signature, timestamp) {
// Decode the base64 signature
const decodedSignature = Buffer.from(signature, 'base64');
// Create the signed content
const signedContent = timestamp + payload;
// Create verifier
const verifier = crypto.createVerify('sha256');
verifier.update(signedContent);
// Add PEM headers if not present
let pemKey = publicKey;
if (!pemKey.includes('BEGIN PUBLIC KEY')) {
pemKey = `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`;
}
// Verify the signature
return verifier.verify(pemKey, decodedSignature);
}
// Express middleware
app.post('/webhooks/sendgrid', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.get('X-Twilio-Email-Event-Webhook-Signature');
const timestamp = req.get('X-Twilio-Email-Event-Webhook-Timestamp');
if (!signature || !timestamp) {
return res.status(400).send('Missing signature headers');
}
const publicKey = process.env.SENDGRID_WEBHOOK_VERIFICATION_KEY;
const payload = req.body.toString();
if (!verifySignature(publicKey, payload, signature, timestamp)) {
return res.status(400).send('Invalid signature');
}
// Process events
const events = JSON.parse(payload);
console.log(`Received ${events.length} events`);
res.sendStatus(200);
});
```
### Using SendGrid SDK
```javascript
const { EventWebhook } = require('@sendgrid/eventwebhook');
const verifyWebhook = new EventWebhook();
const publicKey = process.env.SENDGRID_WEBHOOK_VERIFICATION_KEY;
app.post('/webhooks/sendgrid', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.get('X-Twilio-Email-Event-Webhook-Signature');
const timestamp = req.get('X-Twilio-Email-Event-Webhook-Timestamp');
const isValid = verifyWebhook.verifySignature(
publicKey,
req.body,
signature,
timestamp
);
if (!isValid) {
return res.status(400).send('Invalid signature');
}
// Process webhook
res.sendStatus(200);
});
```
## Common Event Types
| Event | Description | Use Cases |
|-------|-------------|-----------|
| `processed` | Message has been received and is ready to be delivered | Track email processing |
| `delivered` | Message successfully delivered to recipient | Delivery confirmation |
| `bounce` | Message permanently rejected (includes type='blocked' for blocked messages) | Update contact lists, handle failures |
| `deferred` | Temporary delivery failure | Monitor delays |
| `open` | Recipient opened the email | Engagement tracking |
| `click` | Recipient clicked a link | Link tracking, CTR analysis |
| `spam report` | Email marked as spam | List hygiene, sender reputation |
| `unsubscribe` | Recipient unsubscribed | Update subscription status |
| `group unsubscribe` | Recipient unsubscribed from a group | Update group subscription preferences |
| `group resubscribe` | Recipient resubscribed to a group | Update group subscription preferences |
## Environment Variables
```bash
# Your SendGrid webhook verification key (public key)
SENDGRID_WEBHOOK_VERIFICATION_KEY="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..."
```
## Local Development
For local webhook testing, use Hookdeck CLI:
```bash
npx hookdeck-cli listen 3000 sendgrid --path /webhooks/sendgrid
```
No account required. Provides local tunnel + web UI for inspecting requests.
## Resources
- [overview.md](references/overview.md) - What SendGrid webhooks are, common event types
- [setup.md](references/setup.md) - Configure webhooks in SendGrid dashboard, get verification key
- [verification.md](references/verification.md) - ECDSA signature verification details and gotchas
- [examples/](examples/) - Complete implementations for Express, Next.js, and FastAPI
## Related Skills
- `webhook-handler-patterns` - Cross-cutting patterns (idempotency, retries, framework guides)
- [hookdeck-event-gateway](https://github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway) - Webhook infrastructure that replaces your queue — guaranteed delivery, automatic retries, replay, rate limiting, and observability for your webhook handlersMore API Design skills
lark-event
larksuite/cli
Lark/Feishu real-time event listening / subscribing / consuming: stream events as NDJSON via `lark-cli event consume <EventKey>` (covers IM messages/reactions/chat changes, Approval status changes, Task updates, VC meeting started/joined/ended, Minutes generated, Whiteboard updated, etc.). Use for Lark bots, real-time message processing, long-running subscribers, streaming webhook/push handlers. Supports `--max-events` / `--timeout` bounded runs and a stderr ready-marker contract — designed for AI agents running as subprocesses.
lark-contact
larksuite/cli
飞书 / Lark 通讯录:按姓名 / 邮箱解析成 open_id,或按 open_id 反查姓名 / 部门 / 邮箱 / 联系方式 / 个人状态 / 签名,以及按关键词搜索当前用户可见的机器人 / 智能体(agent)。当用户提到一个名字要下一步发消息 / 排日程,或拿到 open_id 想查具体信息时使用。不负责部门树遍历、按部门列员工、组织架构图,这类需求走原生 OpenAPI。
lark-openapi-explorer
larksuite/cli
飞书/Lark 原生 OpenAPI 探索:从官方文档库中挖掘未经 CLI 封装的原生 OpenAPI 接口。当用户的需求无法被现有 lark-* skill 或 lark-cli 已注册命令满足,需要查找并调用原生飞书 OpenAPI 时使用。

