Webhooks
A reverse API call. The other side calls you when something happens.
The basic idea
Your app uses Stripe for payments. When a payment succeeds, you need to know. You have to ship the order, send a receipt, and update your database.
You could poll Stripe's API every minute and ask "any new payments?" That is wasteful and laggy.
Instead, you give Stripe a URL on your server. Something like https://yourapp.com/webhooks/stripe. When something happens (a payment succeeds, a refund is issued, a dispute opens), Stripe sends an HTTP POST to that URL with the event details.
That POST is a webhook. It is just an HTTP request, but in the unusual direction. The other side calls you.
How it works step by step
1. You go to Stripe's dashboard. You configure a webhook endpoint, like https://yourapp.com/webhooks/stripe. You choose which events you care about, such as payment_intent.succeeded or charge.refunded.
2. Stripe gives you a signing secret. You store it.
3. When an event happens on Stripe's side, they POST a JSON payload to your URL with the event details. They include a signature header.
4. Your server checks the signature using the shared secret. If it is valid, you know the request really came from Stripe and not from someone faking a POST. You handle the event.
5. You return 200 OK within a few seconds. If you return an error or time out, Stripe retries. The retries can go on for hours or days.
This pattern is everywhere. Stripe. GitHub. Slack. Twilio. Shopify. Zoom. Every API that emits events does it through webhooks.
What can go wrong
Duplicate deliveries. If you take too long to respond, the sender retries. You get the same event twice. Make your handler idempotent so that processing the same event ID more than once does no harm.
Out-of-order delivery. A "payment succeeded" and a "refund issued" can arrive in either order. Look at the timestamps in the payload, not the order they showed up in.
Lost deliveries. If your endpoint is down and the sender gives up after retries, you missed an event. Run a periodic reconciliation job that polls the API to catch anything you might have missed.
Spoofing. Anyone on the internet can POST to your webhook URL. Always check the signature. Reject anything unsigned.
Slow handlers. Webhooks usually time out in 5 to 30 seconds. Do not do slow work inside the handler. Acknowledge the webhook. Put the work on a queue. Do it in the background.
Compared to polling and WebSockets
Polling. Your server asks the other side every so often, "anything new?" Wasteful when nothing has changed. Laggy. Simple to build.
Webhooks. The other side tells you instantly. Efficient. You need a public URL.
WebSockets. A long-lived two-way connection. Overkill for occasional events. Built for streams of updates.
For "tell me when something happens," webhooks are the standard. Every modern API offers them.
Webhooks are also how you wire systems together without polling. Your CRM can be hooked to Stripe with a webhook. Stripe can be hooked to Slack with a webhook. Slack can be hooked to a database with a webhook. Each system pushes events. The others react. The whole modern SaaS world runs on this.