title: Stripe webhook error 400 bad request when using Heroku web address
body: <p><a href="https://i.stack.imgur.com/x5SlW.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/x5SlW.png" alt="enter image description here" /></a>I have integrated Stripe in my Ruby on Rails website. If I test it with ngrok, everything works fine but when I use my heroku website address as stripe webhook, it throws a 400 bad request error. If I look up the documentation it says a required parameter is missing. Could this be because I don't have a ssl certificate? I am on the free tier on Heroku but nevertheless the heroku web address starts with https... is that not secure? I have entered the publishable, secret and signing key on the heroku website.</p>
  <p>Routes.rb</p>
  <pre><code>Rails.application.routes.draw do
  
    mount StripeEvent::Engine, at: '/stripe-webhooks'
  
    devise_for :users, controllers: {
      sessions: 'users/sessions',
      passwords: 'users/passwords',
      registrations: 'users/registrations'
    }
  
    scope '(:locale)', locale: /en|de/ do
      root to: 'pages#home'
      get '/about', to: 'pages#about', as: 'about'
      get '/shipping', to: 'pages#shipping', as: 'shipping'
      get '/privacypolicy', to: 'pages#privacypolicy', as: 'privacypolicy'
      get '/termsandconditions', to: 'pages#termsandconditions', as: 'termsandconditions'
      get '/success', to: 'pages#success'
  
      get 'contact', to: 'contacts#new', as: 'contact'
  
  
      resources :contacts, only: [:new, :create]
  
  
      get 'cart', to: 'carts#show', as: 'cart'
      delete 'carts', to: 'carts#destroy'
      delete 'cart_items/:id', to: 'cart_items#destroy', as: 'cart_items'
  
      resources :cart_items, only: [:create, :destroy] do
        member do
          get :add_quantity
          get :reduce_quantity
        end
      end
  
      post 'without-login', to: 'orders#without_login'
  
      resources :users
      resources :products do
        resources :cart_items, only: [:create]
      end
      resources :categories
      resources :orders, only: [:new, :show, :create] do
        resources :payments, only: :new
      end
    end
  end
  </code></pre>
  <p>schema:</p>
  <pre><code>create_table &quot;orders&quot;, force: :cascade do |t|
      t.string &quot;product_sku&quot;
      t.integer &quot;amount_cents&quot;, default: 0, null: false
      t.string &quot;checkout_session_id&quot;
      t.bigint &quot;user_id&quot;
      t.datetime &quot;created_at&quot;, precision: 6, null: false
      t.datetime &quot;updated_at&quot;, precision: 6, null: false
      t.string &quot;first_name&quot;
      t.string &quot;last_name&quot;
      t.string &quot;street_name&quot;
      t.string &quot;house_number&quot;
      t.string &quot;postal_code&quot;
      t.string &quot;city&quot;
      t.string &quot;country&quot;
      t.string &quot;email&quot;
      t.text &quot;comment&quot;
      t.integer &quot;price_cents&quot;, default: 0, null: false
      t.boolean &quot;termsandconditions&quot;
      t.string &quot;status&quot;, default: &quot;pending&quot;
      t.index [&quot;user_id&quot;], name: &quot;index_orders_on_user_id&quot;
    end
  </code></pre>
  <pre><code>class PaymentsController &lt; ApplicationController
      skip_before_action :authenticate_user!
  
   def new
      if current_user
        @order = current_user.orders.where(status: 'pending').find(params[:order_id])
      else
        @order = Order.find(params[:order_id])
      end
      gon.order_amount = @order.amount_cents.to_f/100
      gon.order_id = @order.id
    end
  
  end
  </code></pre>
  <pre><code>class OrdersController &lt; ApplicationController
    skip_before_action :authenticate_user!
  
    def new
      @order = Order.new
      @cart = current_cart
      # Storing the two constants in a gon variable to send data to the JS file
      gon.ceilings = Product::ORDER_CEILINGS
      gon.prices = Product::SHIPPING_PRICES
    end
  
    def create
      @order = Order.new(order_params)
      @cart = current_cart
      @cart.cart_items.each { |item| @order.cart_items &lt;&lt; item }
      @order.amount = @cart.total_price
  
      shipping_costs = calculate_shipping_costs(params[:order][:country], @order.amount)
      @order.amount += Monetize.parse(shipping_costs)
  
      @order.user = current_user if current_user
      @order.email = current_user.email if current_user
  
      if @order.save
        save_user_address if params[:save_address].to_i == 1
        trigger_stripe(shipping_costs)
        cleanup_cart
        redirect_to new_order_payment_path(@order)
      else
        @cart = @current_cart
        render :new
      end
    end
  
    def show
      if current_user
        @order = current_user.orders.find(params[:id])
      else
        @order = Order.find(params[:id])
      end
  
      mail = OrderMailer.with(order: @order).confirmation
      mail.deliver_now
      # may need to change this for guest users- must check that their email address is saved to the database
    end
  
    def index
      @orders = current_user.orders
    end
  
    def without_login
      session[:without_login] = true
      redirect_to new_order_path
    end
  
    def submit
    end
  
  
    private
  
    def order_params
      params.require(:order).permit(:first_name, :last_name, :email, :street_name, :house_number, :postal_code, :city, :country, :comment)
    end
  
    def trigger_stripe(shipping_costs)
      stripe_session = Stripe::Checkout::Session.create(
        payment_method_types: ['card'],
        customer_email: customer_email,
        locale: I18n.locale.to_s,
        line_items: stripe_line_items(@order.cart_items, shipping_costs),
        success_url: order_url(@order),
        cancel_url: order_url(@order)
      )
      @order.update(checkout_session_id: stripe_session.id)
    end
  
    def cleanup_cart
      @cart.cart_items.each { |item| item.update(cart_id: nil) }
      Cart.destroy(session[:cart_id])
      session[:cart_id] = nil
    end
  
    def stripe_line_items(order_items, shipping_costs)
      all_items = []
  
      order_items.each do |item|
        item_hash = {
          name: item.product.title,
          amount: (item.total_price.amount * 100).to_i / item.quantity,
          quantity: item.quantity,
          currency: 'eur'
         }
         all_items.push(item_hash)
      end
  
      shipping_item_hash = {
        name: &quot;Delivery&quot;,
        amount: (shipping_costs * 100).to_i,
        quantity: 1,
        currency: 'eur'
      }
      all_items.push(shipping_item_hash)
  
      return all_items
    end
  
    def customer_email
      current_user ? current_user.email : nil
    end
  
    def save_user_address
      if @order.user != nil
        current_user.attributes = @order.attributes.except(&quot;id&quot;, &quot;email&quot;, &quot;status&quot;, &quot;comment&quot;, &quot;amount_cents&quot;, &quot;amount_currency&quot;, &quot;checkout_session_id&quot;, &quot;user_id&quot;, &quot;updated_at&quot;, &quot;created_at&quot;)
        current_user.save
      end
    end
  </code></pre>
  <pre><code>class StripeCheckoutSessionService
    def call(event)
      order = Order.find_by(checkout_session_id: event.data.object.id)
      order.update(status: 'paid')
    end
  end
  </code></pre>
  <p>payments new.html.erb:</p>
  <pre><code>&lt;script src=&quot;https://js.stripe.com/v3/&quot;&gt;&lt;/script&gt;
  &lt;script&gt;
    const paymentButton = document.getElementById('pay-stripe');
    paymentButton.addEventListener('click', () =&gt; {
      const stripe = Stripe('&lt;%= ENV['STRIPE_PUBLISHABLE_KEY'] %&gt;');
      stripe.redirectToCheckout({
        sessionId: '&lt;%= @order.checkout_session_id %&gt;'
      });
    });
    &lt;/script&gt;
  </code></pre>
  <p>initializers stripe</p>
  <pre><code>Rails.configuration.stripe = {
    publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
    secret_key:      ENV['STRIPE_SECRET_KEY'],
    signing_secret:  ENV['STRIPE_WEBHOOK_SECRET_KEY']
  }
  
  Stripe.api_key = Rails.configuration.stripe[:secret_key]
  
  StripeEvent.signing_secret = Rails.configuration.stripe[:signing_secret]
  
  StripeEvent.configure do |events|
    events.subscribe 'checkout.session.completed', StripeCheckoutSessionService.new
  end
  
  </code></pre>