I am currently working on stripe webhooks for my rails application and am encountering a problem. All events except for checkout.session.completed
are working.
My main goal is to change the payment status booking.paid
to true
when the event checkout.session.completed
happens. The stripe webhooks logs give me a 500 internal server error for the event checkout.session.completed
. I think the problem is in my Webhook controller but I just can't figure out what's wrong. Any help would be amazing!
This is my Webhooks_controller:
class WebhooksController < ApplicationController
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
def create
payload = request.body.read
sig_header = request.env['HTTP_STRIPE_SIGNATURE']
event = nil
begin
event = Stripe::Webhook.construct_event(
payload, sig_header, Rails.application.credentials[:stripe][:webhook]
)
rescue JSON::ParserError => e
status 400
return
rescue Stripe::SignatureVerificationError => e
# Invalid signature
puts "Signature error"
p e
return
end
# Handle the event
case event.type
when 'checkout.session.completed'
# session = event.data.object
# @booking.session.client_reference_id.paid = true
booking = Booking.find_by(checkout_session_id: event.data.object.id)
booking.update(paid: true)
end
render json: { message: 'success' }
end
end
CodePudding user response:
I think the issue might lie in the Booking.find_by
method. Try adding a line to inspect the value of booking
prior to updating its status.
CodePudding user response:
I just happen to be writing the exact same feature as you so I'm glad this popped up in my queue.
From taking a quick look at the code nothing stands out much. If we know that the only event that doesn't work is checkout.session.completed
, and that's the only one we're even processing, that narrows the problem down a bit... so here's what I did:
- I copied your implementation into a controller in my Rails API project, then used the Stripe CLI to listen for, and forward Stripe events to the new endpoint:
stripe listen --forward-to http://localhost:3000/webhook_events
I commented out the actual handling of the event so it was only processing the event.
I then used the Stripe CLI in a new terminal to trigger a
checkout.session.completed
event:
$ stripe trigger checkout.session.completed
- Once I did this, my API responded with a
201
and Stripe was happy.
So after all of that, as the previous answer suggests, I think the issue lies with your updating the Booking
model, so I have a few suggestions to make working with webhooks in general easier:
- Ideally, your controller should respond with a
2xx
to Stripe as soon as you've verified the authenticity of the event with the Stripe gem. - Once you've completed that, I would immediately move the processing of the event to a background job using ActiveJob.
- In the background job, you know that your event is valid and that the session completed successfully, so now you can start to update your
Booking
model. The arguments to the job could be as simple as just the Stripe checkout session ID. - Finally, splitting the responsibilities like this will make writing tests much easier (and will catch what the actual problem is!).
I hope this helps, good luck!