Webhook is an HTTP request, usually a POST with a JSON body, that one system sends automatically to a URL registered by another when a specific event occurs, so the receiver does not have to poll for changes. Unlike an API callback tied to a single request, a webhook is a standing subscription that delivers every event of the chosen types. Payment providers use it for events that finish after the API call returns, such as settled bank transfers, completed 3DS challenges, chargebacks and payouts. The receiver must answer with a 2xx status within seconds or the provider retries. Messages are signed, commonly with HMAC-SHA256, and delivery is at least once, so receivers must discard duplicates by event ID.
Webhook vs API callback
The terms overlap, and many providers use them interchangeably. The usual distinction: an API callback is a URL supplied with a single request, called once when that request finishes, such as a redirect or a callback URL passed during a 3DS flow. A webhook is a standing subscription configured once for an account, which then receives every event of the chosen types, from any request, indefinitely. A callback belongs to one transaction; a webhook belongs to the integration.
Both reverse the direction of a normal REST API call, where the client asks and the server answers.
How do payment webhooks work
Payments are full of events that complete after the API call has returned: a bank transfer settling hours later, a 3DS challenge finishing on the customer's phone, a chargeback filed weeks after the sale, a payout landing. The PSP records each event, then sends a POST to the merchant's endpoint with the event type, a timestamp and the object ID. The merchant must reply with a 2xx status within a few seconds. If it does not, the PSP retries with increasing gaps; Stripe, for example, keeps retrying for up to three days.
Security: signatures and replay
A webhook endpoint is a public URL, so anyone could post fake "payment succeeded" events to it. Providers sign each message, commonly with an HMAC-SHA256 of the body and a timestamp using a shared secret, and the receiver recomputes the signature before trusting the payload. Rejecting messages with timestamps older than a few minutes blocks replays of captured requests.
Delivery is at least once, not exactly once
Webhooks can arrive twice, late or out of order. A "refunded" event may land before "captured" if the first delivery failed. Well-built receivers store the event ID and ignore duplicates, and fetch the current object state from the API rather than trusting the event order. These are the same principles behind an idempotency key.
A numeric example
A merchant receives 50,000 webhook events a day. If its endpoint is down for 20 minutes during a deploy, about 700 events fail their first delivery. With retries, they arrive later; without duplicate handling, any event delivered twice during recovery could ship an order twice or credit a wallet twice.