I've been having this issue for a while and decided to work on other projects instead. However, I revisited this project today and the issue is still unresolved.
This is the current flow that I'm working on:
- User submits screenplay form
- Redirects to Stripe Checkout
- Webhooks listen for checkout.session.completed
- When the session is completed, the is_paid field is updated to TRUE
1 and 2 works. 3 and 4 don't. Whenever I go through the above flow I get the following errors:
[400] POST http://localhost:3000/webhooksCompleted 400 Bad Request
I figured this may be an issue with the webhook secret. But I'm definitely using the correct one. I copy and pasted the exact webhook signing secret that Stripe CLI gives you when you stripe listen --forward-to localhost:3000/webhooks. So I'm not sure what the issue is. Also, when I run stripe trigger checkout.session.completed the trigger succeeds. Which is why I thought I may have just had the wrong webhook secret. But it's the right one. So I have no idea what's wrong. If someone could point me in the right direction it would be much appreciated. Here's the relevant code:
create method in ScreenplaysController
def create
@screenplay = current_user.screenplays.new(screenplay_params)
if @screenplay.save
session = Stripe::Checkout::Session.create({
line_items: [{
price: "notrealforobviousreasons",
quantity: 1,
}],
mode: "payment",
metadata: { screenplay_id: @screenplay.id },
customer_email: current_user.email,
success_url: dashboard_url,
cancel_url: dashboard_url,
})
redirect_to session.url, allow_other_host: true
else
render :new, status: :unprocessable_entity
end
end
WebhooksController
class WebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
def create
event = nil
sig_header = request.env["HTTP_STRIPE_SIGNATURE"]
payload = request.body.read
endpoint_secret = Rails.application.credentials.dig(:stripe, :webhook_secret)
begin
event = Stripe::Webhook.construct_event(
sig_header, payload, endpoint_secret
)
rescue JSON::ParserError => e
head 400
return
rescue Stripe::SignatureVerificationError => e
head 400
return
end
case event.type
when "checkout.session.completed"
session = event.data.object
@screenplay = Screenplay.find_by(id: session.metadata.screenplay_id)
@screenplay.update(is_paid: true)
end
end
end
Development credentials
stripe:
publishable_key: notrealforobviousreasons
secret_key: notrealforobviousreasons
webhook_secret: notrealforobviousreasons