gem 'stripe'

rails credentials:edit
# add two keys from test env
stripe_publishable_key: pk_test_I...
stripe_secret_key: sk_test_g...

# config/initializers/stripe.rb
Stripe.api_key = Rails.application.credentials.stripe_secret_key

checkout.js is deprecated and now we use stripe.js You can use as module but PCI compliant requires to load from <script src=""></script>

There are two kind of intergrations, using redirection or iframe.

Checkout redirection

Server generate session and client redirects to checkout page on stripe

# app/controllers/pages_controller.rb

  def checkout
    @stripe_session = Stripe::Checkout::Session.create(
      client_reference_id: 'my_reference',
      customer_email: '[email protected]',
      line_items: [{
        price_data: {
          currency: 'usd',
          product_data: {
            name: 'T-shirt',
          unit_amount: params[:amount].presence || 123,
        quantity: 1,
      mode: 'payment',
      success_url: pages_success_checkout_url + '?session_id={CHECKOUT_SESSION_ID}',
      cancel_url: pages_cancel_url,

  def success_checkout
    @stripe_session = Stripe::Checkout::Session.retrieve(params[:session_id])
    @stripe_payment_intent = Stripe::PaymentIntent.retrieve(@stripe_session.payment_intent)

# app/views/pages/checkout.js.erb
stripe = Stripe('<%= Rails.application.credentials.stripe_publishable_key %>')
  sessionId: '<%= %>'
}).then(function (result) {

You need to use session_id to check amount that is received and status of the payment. Note that redirection success_url can use placeholder to mark that we need session_id ?session_id={CHECKOUT_SESSION_ID} so we can retrieve Session. Use client_reference_id to fetch payment from db and update logs with status, customer (stripe customer id), amount_received from PaymentIntent. Params Real world will use webhooks.

Iframe using Elements

  def iframe
    amount = params[:amount].presence || 123
    @stripe_payment_intent = Stripe::PaymentIntent.create(amount: amount, currency: 'usd')
    payment = Payment.create! payment_intent_id:, user_id: 1, amount: amount, status: :initiated
    # we need to check since payment could be made and redirection fails
    CheckPaymentIntentJob.set(wait: 1.minute).perform_later payment
var stripe = Stripe('pk_test_Ib1l2OSfSQv8DieeTjCHsNoU');
var elements = stripe.elements()
var card = elements.create("card")//, { style: style });
var clientSecret = '<%= @stripe_payment_intent.client_secret %>';

  .confirmCardPayment(clientSecret, {
    payment_method: {
      card: card
  .then(function(result) {
    if (result.error) {
      // Show error to your customer
    } else {
      // The payment succeeded!
      // orderComplete(;

When checking PaymentIntent status should be successfull Sample ids = "pi_1H3JL1Cmrv971Cndt8fOYDud"

and this can be used for stripe url

Find or create Stripe customer

You can create stripe customer on signup (if email column has uniq index). In case when users does not have uniq index on email column (can be created without email) than signup flow could create multiple same stripe customers. In this case you need to search if there exists stripe customer.

Example using subscriptions

Stripe ruby mock is a nice way to mock all API calls. To mock js calls you need to override js or mock params

You can find on github

  def stub_stripe(status, plan_id: nil)
    stripe_helper = StripeMock.create_test_helper
    token = stripe_helper.generate_card_token(last4: '1234')
    script = "document.token_id = '#{token}'"
    stripe_helper.create_plan(id: plan_id) if plan_id.present?
    yield if block_given?
    # note that you should make assertion before the block finish

Testing Stripe

Test numbers 4242424242424242 or some of declined cards:

  • incorrect_number 424242424242424241
  • incorrect cvc is just use two digits or 4000000000000127 or 4000000000000101
  • can attach card but attempts to charge fails 4000000000000341
  • 3D secure is required 4000000000003220

Demo app but Rails 4 can be found

You can test using server or using mocking library