vercel-webhooks-events
Guide to verifying Vercel webhook signatures using HMAC to handle deployment events securely.
Install
mkdir -p .claude/skills/vercel-webhooks-events && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/1201" && unzip -o skill.zip -d .claude/skills/vercel-webhooks-events && rm skill.zipInstalls to .claude/skills/vercel-webhooks-events
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Implement Vercel webhook handling with signature verification and eventKey capabilities
- →Register a webhook in the Vercel dashboard and obtain a secret.
- →Verify incoming webhook signatures using HMAC-SHA1 and `crypto.timingSafeEqual`.
- →Handle various Vercel deployment events like `deployment.created` and `deployment.ready`.
- →Implement idempotency to prevent duplicate processing of retried webhook deliveries.
- →Send Slack notifications for production deployments and errors.
- →Test webhooks locally using `localtunnel` and `curl` with signature generation.
How it works
This skill provides code examples for setting up a Vercel webhook endpoint, verifying the HMAC signature of incoming requests, and processing different Vercel deployment events. It includes mechanisms for idempotency and notifications.
Inputs & outputs
When to use vercel-webhooks-events
- →Implementing webhook signature verification
- →Handling Vercel deployment events
- →Securing webhook endpoints
- →Processing Vercel integration callbacks
About this skill
Vercel Webhooks & Events
Overview
Handle Vercel webhook events (deployment.created, deployment.ready, deployment.error) with HMAC signature verification. Covers both integration webhooks (Vercel Marketplace) and project-level deploy hooks.
Prerequisites
- HTTPS endpoint accessible from the internet
- Webhook secret from Vercel dashboard or integration settings
cryptomodule for HMAC signature verification
Instructions
Step 1: Register a Webhook
In the Vercel dashboard:
- Go to Settings > Webhooks
- Add your endpoint URL (must be HTTPS)
- Select events to subscribe to
- Copy the webhook secret for signature verification
Or for Integration webhooks, configure in the Integration Console at vercel.com/dashboard/integrations.
Step 2: Verify Webhook Signature
// api/webhooks/vercel.ts
import type { VercelRequest, VercelResponse } from '@vercel/node';
import crypto from 'crypto';
const WEBHOOK_SECRET = process.env.VERCEL_WEBHOOK_SECRET!;
function verifySignature(body: string, signature: string): boolean {
const expectedSignature = crypto
.createHmac('sha1', WEBHOOK_SECRET)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
// Get raw body for signature verification
const rawBody = JSON.stringify(req.body);
const signature = req.headers['x-vercel-signature'] as string;
if (!signature || !verifySignature(rawBody, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the event
const event = req.body;
await handleEvent(event);
res.status(200).json({ received: true });
}
Step 3: Handle Deployment Events
// lib/webhook-handlers.ts
interface VercelWebhookEvent {
id: string;
type: string;
createdAt: number;
payload: {
deployment: {
id: string;
name: string;
url: string;
meta: Record<string, string>;
};
project: {
id: string;
name: string;
};
target: 'production' | 'preview' | null;
user: { id: string; email: string; username: string };
};
}
async function handleEvent(event: VercelWebhookEvent): Promise<void> {
switch (event.type) {
case 'deployment.created':
console.log(`Deployment started: ${event.payload.deployment.url}`);
// Notify Slack, update status board, etc.
break;
case 'deployment.ready':
console.log(`Deployment ready: ${event.payload.deployment.url}`);
// Run smoke tests against the deployment URL
// Notify team of successful deploy
if (event.payload.target === 'production') {
await notifyProductionDeploy(event);
}
break;
case 'deployment.error':
console.error(`Deployment failed: ${event.payload.deployment.id}`);
// Alert on-call engineer
// Create incident ticket
await notifyDeploymentError(event);
break;
case 'deployment.canceled':
console.log(`Deployment canceled: ${event.payload.deployment.id}`);
break;
case 'project.created':
console.log(`New project: ${event.payload.project.name}`);
break;
case 'project.removed':
console.log(`Project removed: ${event.payload.project.name}`);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
}
Step 4: Idempotency — Prevent Duplicate Processing
// lib/idempotency.ts
// Vercel may retry webhook delivery — track processed event IDs
const processedEvents = new Set<string>(); // Use Redis in production
async function processWebhookIdempotent(
event: VercelWebhookEvent,
handler: (e: VercelWebhookEvent) => Promise<void>
): Promise<boolean> {
if (processedEvents.has(event.id)) {
console.log(`Skipping duplicate event: ${event.id}`);
return false;
}
await handler(event);
processedEvents.add(event.id);
return true;
}
Step 5: Slack Notification Example
// lib/notifications.ts
async function notifyProductionDeploy(event: VercelWebhookEvent): Promise<void> {
const { deployment, project, user } = event.payload;
await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `Production deploy complete`,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: [
`*${project.name}* deployed to production`,
`By: ${user.username}`,
`URL: https://${deployment.url}`,
`Commit: ${deployment.meta?.githubCommitMessage ?? 'N/A'}`,
].join('\n'),
},
},
],
}),
});
}
async function notifyDeploymentError(event: VercelWebhookEvent): Promise<void> {
await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `Deployment FAILED for ${event.payload.project.name} — ${event.payload.deployment.id}`,
}),
});
}
Step 6: Test Webhooks Locally
# Use the Vercel CLI to test webhook signatures
# Or use a tunnel service for local testing
npx localtunnel --port 3000
# Gives you a public URL like https://xxx.loca.lt
# Send a test webhook payload
curl -X POST http://localhost:3000/api/webhooks/vercel \
-H "Content-Type: application/json" \
-H "x-vercel-signature: $(echo -n '{"type":"deployment.ready","id":"test"}' | openssl dgst -sha1 -hmac 'your-secret' | awk '{print $2}')" \
-d '{"type":"deployment.ready","id":"test"}'
Webhook Event Types
| Event | Trigger |
|---|---|
deployment.created | New deployment started building |
deployment.ready | Deployment build completed successfully |
deployment.error | Deployment build failed |
deployment.canceled | Deployment was canceled |
project.created | New project created |
project.removed | Project deleted |
domain.created | Domain added to project |
integration.configuration.removed | Integration uninstalled |
Output
- Webhook endpoint with HMAC signature verification
- Event handlers for deployment lifecycle events
- Idempotent processing preventing duplicates
- Slack notifications for production deploys and failures
Error Handling
| Error | Cause | Solution |
|---|---|---|
401 Invalid signature | Wrong webhook secret or body mismatch | Verify secret matches dashboard, use raw body for HMAC |
| Webhook not received | Endpoint not publicly accessible | Ensure HTTPS, check firewall rules |
| Duplicate processing | Webhook retried by Vercel | Implement idempotency with event ID tracking |
504 timeout on webhook endpoint | Handler takes too long | Return 200 immediately, process async in background |
Missing x-vercel-signature | Not a real Vercel webhook | Reject requests without the signature header |
Resources
Next Steps
For performance optimization, see vercel-performance-tuning.
Prerequisites
Limitations
- →The webhook endpoint must be publicly accessible via HTTPS.
- →Long-running tasks in the handler can cause timeouts; background processing is recommended.
How it compares
This skill provides a secure and reliable method for handling Vercel webhooks with signature verification and idempotency, unlike simply accepting unverified POST requests.
Compared to similar skills
vercel-webhooks-events side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| vercel-webhooks-events (this skill) | 3 | 26d | Caution | Intermediate |
| juicebox-prod-checklist | 1 | 26d | Caution | Beginner |
| vercel-rate-limits | 0 | 26d | Review | Intermediate |
| stellar-dev | 0 | 3mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
juicebox-prod-checklist
jeremylongshore
Execute Juicebox production deployment checklist. Use when preparing for production launch, validating deployment readiness, or performing pre-launch reviews. Trigger with phrases like "juicebox production", "deploy juicebox prod", "juicebox launch checklist", "juicebox go-live".
vercel-rate-limits
jeremylongshore
Implement Vercel rate limiting, backoff, and idempotency patterns. Use when handling rate limit errors, implementing retry logic, or optimizing API request throughput for Vercel. Trigger with phrases like "vercel rate limit", "vercel throttling", "vercel 429", "vercel retry", "vercel backoff".
stellar-dev
Carts1024
End-to-end Stellar development playbook. Covers Soroban smart contracts (Rust SDK), Stellar CLI, JavaScript/Python/Go SDKs for client apps, Stellar RPC (preferred) and Horizon API (legacy), Stellar Assets vs Soroban tokens (SAC bridge), wallet integration (Freighter, Stellar Wallets Kit), smart acco
backend-development
hoadh
Build backends with Node.js, Python, Go (NestJS, FastAPI, Django). Use for REST/GraphQL/gRPC APIs, auth (OAuth, JWT), databases, microservices, security (OWASP), Docker/K8s.
apollo-security-basics
jeremylongshore
Apply Apollo.io API security best practices. Use when securing Apollo integrations, managing API keys, or implementing secure data handling. Trigger with phrases like "apollo security", "secure apollo api", "apollo api key security", "apollo data protection".
juicebox-security-basics
jeremylongshore
Apply Juicebox security best practices. Use when securing API keys, implementing access controls, or auditing Juicebox integration security. Trigger with phrases like "juicebox security", "secure juicebox", "juicebox API key security", "juicebox access control".