Interacting with a third-party API like Stripe's can introduce two problems:
- Services not directly responsible for making an API request may still need to know the response of that request
- Some events, like disputed charges and many recurring billing events, are not the result of a direct API request
Webhooks solve these problems by letting you register a URL that we will notify anytime an event happens in your account. When the event occurs—for example, when a successful charge is made on a customer's subscription, Stripe creates an
Event object. This object contains all the relevant information about what just happened, including the type of event and the data associated with that event. Stripe then sends the
Event object to any URLs in your account's webhooks settings via an HTTP POST request. You can find a full list of all event types in the API docs.
You might use webhooks as the basis to:
- Update a customer's membership record in your database when a subscription payment succeeds
- Email a customer when a subscription payment fails
- Check out the Dashboard if you see that a dispute was filed
- Make adjustments to an invoice when it's created (but before it's been paid)
- Log an accounting entry when a transfer is paid
Understand that you only need to use webhooks for behind-the-scenes transactions. The results of most Stripe requests—including charge attempts and customer creations—are reported synchronously to your code, and don't require webhooks for verification. (For example, with a charge request, the charge will immediately succeed and a
Charge object returned, or the charge will immediately fail and an exception will be thrown.)
Configuring your webhook settings
Webhooks are configured in the webhooks settings section of the Dashboard. Clicking Add endpoint reveals a form to add a new URL for receiving webhooks.
Stripe supports two webhook types: Account and Connect. You'll likely want to create an account webhook, unless you've created a Connect application.
You can enter any URL you'd like to have events sent to, but this should be a dedicated page on your server, coded per the instructions below. The mode determines whether test events or live events are sent to this URL; if you want to send both live and test events to the same URL, you need to create two separate settings. You may add as many URLs as you like, and basic access authentication is supported.
You can also choose to be notified of all event types, or only specific ones.
Receiving a webhook notification
Creating a webhoook endpoint on your server is no different from creating any page on your website. With PHP, you might create a new .php file on your server; with a framework like Sinatra, you would add a new route with the desired URL.
Webhook data is sent as JSON in the POST request body. The full event details are included and can be used directly, after parsing the JSON into an Event object.
Receiving webhooks with a CSRF-protected server
If you're using Rails, Django, or another web framework, your site may automatically check that every POST request contains a CSRF token. This is an important security feature that helps protect you and your users from cross-site request forgery attempts. However, this security measure may also prevent your site from processing legitimate webhooks. If so, you may need to exempt the webhooks route from CSRF protection.
Receiving webhooks with an HTTPS server
If you use an HTTPS URL for your webhook endpoint, Stripe will validate that the connection to your server is secure before sending your webhook data. For this to work, your server must be correctly configured to support HTTPS with a valid server certificate. See our guide on SSL/TLS for details on setting this up.
Responding to a webhook
To acknowledge receipt of a webhook, your endpoint should return a
2xx HTTP status code. Any other information returned in the request headers or request body is ignored. All response codes outside the this range, including
3xx codes, will indicate to Stripe that you did not receive the webhook. This does mean that a URL redirection or a "Not Modified" response will be treated as a failure.
If a webhook is not successfully received for any reason, Stripe will continue trying to send it once an hour for up to 3 days. Webhooks cannot be manually retried after this time, though you can query for the event to reconcile your data with any missed events.
When viewing a specific event information through the Dashboard, you can check how many times we've attempted to send an event to an endpoint by clicking on that endpoint URL in the Webhook details section. This will show you the latest response we received from your endpoint, along with a list of all attempted webhooks and the respective HTTP status codes we received.
Before going live, test that your webhook is working properly. You can do so by sending dummy test events from the webhooks settings pane. Understand that as these are fake, test events, they will not map to real customers, invoices, charges, or other objects in your account.
If your webhook script performs complex logic, or makes network calls, it's possible the script would timeout before Stripe sees its complete execution. For that reason, you may want to have your webhook endpoint immediately acknowledge receipt by returning a
2xx HTTP status code, and then perform the rest of its duties.
Webhook endpoints may occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you've processed, and then not processing already-logged events.
For optimum security, you can confirm the event data with Stripe before acting upon it. To do so:
- Parse the JSON data as above.
- Grab the received
Eventobject ID value.
- Use the
Eventobject ID in a retrieve event API call.
- Take action using the returned
Webhooks and API versions
The structure of an
Event object sent in a webhook is dictated by the API version in your account settings at the time of the event's occurrence. For example, if your account is set to an older API version, such as 2015-02-16, and you change the API version for a specific request via versioning, the
Event object generated still aligns with the 2015-02-16 API version.
Event objects will never be changed after the fact. Subsequent updates to your account's API version do not retroactively alter existing
Event objects. Fetching older events using a newer API version also has no impact on the event's structure.