Implement Vercel webhook handling with signature verification and event processing. Use when setting up webhook endpoints, processing deployment events, or building integrations that react to Vercel deployment lifecycle. Trigger with phrases like "vercel webhook", "vercel events", "vercel deployment.ready", "handle vercel events", "vercel webhook signature".
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: vercel-webhooks-events description: | Implement Vercel webhook handling with signature verification and event processing. Use when setting up webhook endpoints, processing deployment events, or building integrations that react to Vercel deployment lifecycle. Trigger with phrases like "vercel webhook", "vercel events", "vercel deployment.ready", "handle vercel events", "vercel webhook signature". allowed-tools: Read, Write, Edit, Bash(curl:*) version: 1.0.0 license: MIT author: Jeremy Longshore jeremy@intentsolutions.io compatible-with: claude-code, codex, openclaw tags: [saas, vercel, webhooks, events, integration]
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.
More by jeremylongshore
View allGenerate production-ready Google Cloud code examples from official repositories including ADK samples, Genkit templates, Vertex AI notebooks, and Gemini patterns. Use when asked to "show ADK example" or "provide GCP starter kit". Trigger with relevant phrases based on skill purpose.
Build production Firebase Genkit applications including RAG systems, multi-step flows, and tool calling for Node.js/Python/Go. Deploy to Firebase Functions or Cloud Run with AI monitoring. Use when asked to "create genkit flow" or "implement RAG". Trigger with relevant phrases based on skill purpose.
Validate production readiness of Vertex AI Agent Engine deployments across security, monitoring, performance, compliance, and best practices. Generates weighted scores (0-100%) with actionable remediation plans. Use when asked to validate a deployment, run a production readiness check, audit security posture, or verify compliance for Vertex AI agents. Trigger with "validate deployment", "production readiness", "security audit", "compliance check", "is this agent ready for prod", "check my ADK agent", "review before deploy", or "production readiness check". Make sure to use this skill whenever validating ADK agents for Agent Engine.
Deploy and orchestrate Vertex AI ADK agents using A2A protocol. Manages AgentCard discovery, task submission, Code Execution Sandbox, and Memory Bank. Use when asked to "deploy ADK agent" or "orchestrate agents". Trigger with phrases like 'deploy', 'infrastructure', or 'CI/CD'.
