What Is a Webhook? Explained for Beginners
A webhook is how another service tells your app that something happened — a payment went through, a form was submitted, a file finished processing. How webhooks differ from normal API calls, what you need to receive one, and the three safety rules every webhook handler must follow.
Your app takes payments through Stripe. A customer pays. How does your app find out?
It could keep asking Stripe, "Has anyone paid yet? How about now? Now?" That's wasteful and slow. Instead, Stripe tells your app the moment it happens. That message is a webhook.
The one-sentence version
A webhook is an automatic message one service sends to your app when something happens.
Webhooks vs API calls
With a normal API call, your app asks another service for something. (What Is an API?)
With a webhook, it's reversed: the other service contacts your app.
Think of waiting for a parcel:
- API polling: you walk to the post office every hour and ask if it's arrived.
- Webhook: you give the post office your phone number, and they text you when it arrives.
You give a service the URL of a page in your app — like https://yourapp.com/api/webhooks/stripe — and tell it which events you care about. When one happens, it sends a request to that URL with details of the event, usually as JSON. (What Is JSON?)
Where you'll use webhooks
- Payments — Stripe, Paddle, and others tell you when a payment succeeds, fails, or a subscription is cancelled.
- Code — GitHub tells your tools when code is pushed or a pull request opens.
- Forms and scheduling — Typeform, Calendly, and similar notify you of new submissions or bookings.
- Email — your email provider tells you when a message bounced.
- Automation tools — Zapier and Make are built largely on webhooks.
What you need to receive one
- An endpoint in your app — a backend route that accepts the webhook request. It must run on a server; a frontend-only app can't receive webhooks. (Frontend vs Backend)
- A public URL — the sending service must be able to reach it over the internet.
localhostwon't work. (What Is Localhost?) - Registration — in the other service's dashboard, you add your URL and choose which events to send.
The three safety rules
Webhook endpoints are public URLs. Anyone who finds one can send it requests. So every webhook handler must follow three rules.
1. Verify it's really from who it claims
A fake "payment succeeded" message could give someone your product for free. Services sign their webhooks with a secret shared only with you, and your handler must check that signature before trusting anything. Stripe, GitHub, and most serious services provide a function in their library to do this.
If your AI-built webhook handler doesn't verify signatures, it's accepting orders from strangers. (How to Add Stripe Payments Without Getting Burned shows exactly how for Stripe.)
2. Expect the same message more than once
If your app doesn't respond quickly, or a network hiccup occurs, the service retries — so you may receive the same event twice. If your handler does "add 100 credits" every time, a retry gives the user 200.
Make handlers safe to run twice: record each event's ID and skip ones you've already processed.
3. Respond fast, work later
Services expect a quick "got it" (a 200 response) — usually within seconds. If your handler does something slow first, like generating a PDF and sending three emails, the service may give up and retry. Record the event, respond, and do the slow work afterwards — ideally as a background job. (Your App Needs Background Jobs)
Testing webhooks while you build
Because webhooks need a public URL, testing on your own computer takes a small trick:
- The service's own CLI tool — Stripe's CLI, for example, can forward webhooks to your localhost (
stripe listen --forward-to localhost:3000/api/webhooks/stripe). - A tunnel — tools like Cloudflare Tunnel or ngrok give your local app a temporary public URL.
- The dashboard — most services show every webhook they've sent, the response they got, and let you re-send one. It's the first place to look when a webhook "didn't arrive."
The classic launch-day mistake
Everything works in testing. You go live. Payments succeed, but nobody gets access to what they paid for. The cause, almost always: the live webhook was never set up — or it still points at a test URL or localhost, or uses the test mode's signing secret.
Before launch, check in each service's live dashboard that the webhook exists, points at your real domain, subscribes to the right events, and that your app has the live signing secret in its environment variables. Then make one real test transaction.
The summary
- A webhook is a service telling your app that something happened.
- It needs a backend endpoint with a public URL.
- Verify signatures. Handle duplicates. Respond quickly.
- Check the live webhook setup before launch.
EasySpawn runs your app's backend at a real public URL with HTTPS on your own domain — exactly what webhooks need — with signing secrets kept in server-side environment variables. See how it works for AI-built apps or join the waitlist.
Related: What Is an API? · How to Add Stripe Payments to an AI-Built App · Handling Webhooks Reliably · What Are WebSockets?
Keep reading
What Is an API? Explained Without the Jargon
APIs are how apps talk to each other — how your app takes a payment, sends an email, or asks an AI model a question. What an API actually is, what requests and responses look like, what an API key does, and the few terms you'll keep running into.
What Is a Tech Stack? How to Choose One When AI Writes the Code
Your tech stack is the set of tools your app is built from: language, framework, database, and hosting. Even if AI writes the code, the choice matters — for how well the AI performs, what it costs, and who can help you later. A beginner's guide with a safe default.