Skip to content

Latest commit

 

History

History
126 lines (87 loc) · 4.71 KB

1_overview.md

File metadata and controls

126 lines (87 loc) · 4.71 KB

Using Pay with Stripe

Stripe has multiple options for payments

Prices & Plans

Stripe introduced Products & Prices to support more payment options. Previously, they had a concept called Plan that was for subscriptions. Pay supports both Price IDs and Plan IDs when subscribing.

@user.payment_processor.subscribe(plan: "price_1234")
@user.payment_processor.subscribe(plan: "plan_1234")

See: https://stripe.com/docs/api/subscriptions/create

Stripe Checkout

Stripe Checkout allows you to simply redirect to Stripe for handling payments. The main benefit is that it's super fast to setup payments in your application, they're SCA compatible, and they will get improved automatically by Stripe.

📝 Warning: You need to configure webhooks before using Stripe Checkout otherwise your application won't be updated with the correct data.

stripe checkout example

How to use Stripe Checkout with Pay

Choose the checkout button mode you need and pass any required arguments. Read the Stripe Checkout Session API docs to see what options are available. For instance:

class SubscriptionsController < ApplicationController
  def checkout
    # Make sure the user's payment processor is Stripe
    current_user.set_payment_processor :stripe

    # One-time payments (https://stripe.com/docs/payments/accept-a-payment)
    @checkout_session = current_user.payment_processor.checkout(mode: "payment", line_items: "price_1ILVZaKXBGcbgpbZQ26kgXWG")

    # Or Subscriptions (https://stripe.com/docs/billing/subscriptions/build-subscription)
    @checkout_session = current_user.payment_processor.checkout(
      mode: 'subscription',
      locale: I18n.locale,
      line_items: [{
        price: 'price_1ILVZaKXBGcbgpbZQ26kgXWG',
        quantity: 4
      }],
      subscription_data: {
        trial_period_days: 15,
        pay_name: "base" # Optional. Overrides the Pay::Subscription name attribute
      },
      success_url: root_url,
      cancel_url: root_url
    )

    # Or Setup a new card for future use (https://stripe.com/docs/payments/save-and-reuse)
    @checkout_session = current_user.payment_processor.checkout(mode: "setup")

    # If you want to redirect directly to checkout
    redirect_to @checkout_session.url, allow_other_host: true, status: :see_other
  end
end

Alternatively, you can use Pay & Stripe.js to render a button that will take the user to Stripe Checkout instead of redirecting immediately.

<%= render "pay/stripe/checkout_button", session: @checkout_session, title: "Checkout" %>

The session_id param will be included on success and cancel URLs automatically. This allows you to lookup the checkout session on your success page and confirm the payment was successful before fulfilling the customer's purchase.

https://stripe.com/docs/payments/checkout/custom-success-page

Stripe Customer Billing Portal

Customers will want to update their payment method, subscription, etc. This can be done with the Customer Billing Portal. It works the same as the other Stripe Checkout pages.

First, create a session in your controller:

class SubscriptionsController < ApplicationController
  def index
    @portal_session = current_user.payment_processor.billing_portal
  end
end

Then link to it in your view:

<%= link_to "Billing Portal", @portal_session.url %>

Or redirect to it in your controller:

redirect_to @portal_session.url, allow_other_host: true, status: :see_other

Fulfilling orders after Checkout completed

For one-time payments, you'll need to add a webhook listener for the Checkout stripe.checkout.session.completed and stripe.checkout.session.async_payment_succeeded events. Some payment methods are delayed so you need to verify the payment_status == "paid". The async payment succeeded event fires when delayed payments are complete.

For subscriptions, Pay will automatically create the Pay::Subscription record for you.

Pay::Webhooks.delegator.subscribe "stripe.checkout.session.completed", FulfillCheckout.new
Pay::Webhooks.delegator.subscribe "stripe.checkout.session.async_payment_succeeded", FulfillCheckout.new

class FulfillCheckout
  def call(event)
    object = event.data.object

    return object.payment_status != "paid"

    # Handle fulfillment
  end
end

That's it!

Next

See Credentials