Developer tools
Webhooks
Build webhooks

Build a webhook endpoint

Write the code that properly handles webhook notifications.

For a more immersive guide, check out our annotated code tutorial.

The first step to adding webhooks to your Stripe integration is to build your own custom endpoint. Creating a webhook 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 Ruby framework like Sinatra, you would add a new route with the desired URL.

Before looking at the code, there are several key considerations regardless of the technology involved. You should also review the best practices for using webhooks.

Key considerations

For each event occurrence, Stripe POSTs the webhook data to your endpoint in JSON format. The full event details are included and can be used directly after parsing the JSON into an Event object. Thus, at minimum, the webhook endpoint needs to expect data through a POST request and confirm successful receipt of that data. Beyond those two concepts, you should also…

Return a 2xx status code quickly

To acknowledge receipt of an event, your endpoint must return a 2xx HTTP status code to Stripe. All response codes outside this range, including 3xx codes, indicate to Stripe that you did not receive the event.

If Stripe does not receive a 2xx HTTP status code, the notification attempt is repeated. After multiple failures to send the notification over multiple days, Stripe marks the event as failed and stops trying to send it to your endpoint. After multiple days without receiving any 2xx HTTP status code responses, Stripe emails you about the misconfigured endpoint, and automatically disables your endpoint soon after if unaddressed.

Because properly acknowledging receipt of the webhook notification is so important, your endpoint should return a 2xx HTTP status code prior to any complex logic that could cause a timeout.

A URL redirection or a “Not Modified” response is treated as a failure. Stripe ignores any other information returned in the request headers or request body.

Test that your endpoint works

As your webhook endpoint is used asynchronously, its failures may not be obvious to you until it’s too late (e.g., after it’s been disabled). Always test that your endpoint works:

  • Upon initial creation
  • After taking it live
  • After making any changes

The test a webhook endpoint page explains how to test your endpoint, and the Stripe CLI makes testing simple.

The majority of webhook issues result in 4xx and 5xx HTTP status codes. 4xx indicates Stripe was able to contact your server, but the endpoint was not valid. Double-check that the endpoint URL is correct and able to receive POST requests. 5xx usually indicates an exception on your server was not handled properly.

Example code

require 'json' # Using Sinatra post '/webhook' do payload = request.body.read event = nil begin event = Stripe::Event.construct_from( JSON.parse(payload, symbolize_names: true) ) rescue JSON::ParserError => e # Invalid payload status 400 return end # Handle the event case event.type when 'payment_intent.succeeded' payment_intent = event.data.object # contains a Stripe::PaymentIntent # Then define and call a method to handle the successful payment intent. # handle_payment_intent_succeeded(payment_intent) when 'payment_method.attached' payment_method = event.data.object # contains a Stripe::PaymentMethod # Then define and call a method to handle the successful attachment of a PaymentMethod. # handle_payment_method_attached(payment_method) # ... handle other event types else puts "Unhandled event type: #{event.type}" end status 200 end