What Are Webhooks (and Why Should You Care)?
A webhook is a URL in your app that another service calls when something happens. Stripe calls your webhook when a customer pays. GitHub calls it when someone opens a pull request. Instead of polling an API every few seconds asking "anything new?", the event comes to you.
For vibe-coded apps, webhooks unlock the features that make products feel alive: instant payment confirmations, real-time notifications, automated workflows triggered by external events. Without them, your app is an island.
💡 The One-Liner Explanation
API call: Your app asks another service for data.
Webhook: Another service tells your app something happened.
Receiving Webhooks: The Basic Pattern
Every webhook receiver follows the same structure: create an endpoint, parse the incoming payload, verify it's legitimate, and process the event. Here's the pattern in Next.js (the framework most vibe coding tools generate):
// app/api/webhooks/stripe/route.ts
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: NextRequest) {
const body = await req.text();
const sig = req.headers.get('stripe-signature')!;
// Verify the webhook is really from Stripe
const event = stripe.webhooks.constructEvent(
body, sig, process.env.STRIPE_WEBHOOK_SECRET!
);
// Handle different event types
switch (event.type) {
case 'checkout.session.completed':
// Activate the user's subscription
break;
case 'invoice.payment_failed':
// Send a friendly nudge email
break;
}
return NextResponse.json({ received: true });
}The key detail most tutorials skip: always verify the signature. Without verification, anyone can send fake events to your endpoint. Every major service (Stripe, GitHub, Clerk, Resend) includes a signature header — use it.
Sending Webhooks From Your App
If you're building a SaaS, your users may want to receive webhooks from you — "notify my Slack when a new report is ready." The pattern is straightforward:
- →Let users register a webhook URL in their settings
- →When an event occurs, POST a JSON payload to their URL
- →Include a signature header so they can verify it's from you
- →Implement retries with exponential backoff for failed deliveries
Testing Webhooks Locally
The biggest friction point for vibe coders is testing. Your local dev server isn't accessible from the internet, so Stripe can't reach it. Three solutions:
Stripe CLI
Run stripe listen --forward-to localhost:3000/api/webhooks/stripe to tunnel Stripe events locally.
ngrok
Creates a public URL that tunnels to your local server. Works with any webhook provider.
Svix Play
Free webhook testing tool — send test payloads to your endpoint and inspect the request/response.
Common Webhook Patterns for Vibe-Coded Apps
| Use Case | Provider | Key Event |
|---|---|---|
| Payment processing | Stripe | checkout.session.completed |
| User sign-up | Clerk / Auth0 | user.created |
| Email events | Resend / SendGrid | email.delivered / email.bounced |
| Form submissions | Typeform / Tally | form_response |
| CI/CD triggers | GitHub | push / pull_request |
🎯 Vibe Coder Tip
When prompting your AI coding assistant, say: "Add a webhook endpoint at /api/webhooks/stripe that verifies the Stripe signature, handles checkout.session.completed events, and activates the user's subscription in the database." Specific prompts produce working webhook code on the first try.
