Jumpstart uses the Pay gem for handling payments and billing.
Jumpstart Pro supports using Stripe, Braintree, or a combination of the two for payments and is configured for monthly and yearly subscriptions out of the box. PayPal is supported through the Braintree integration and may be used entirely on its own or in combination with the Braintree credit card form.
Each subscription is attached to a Account, which allows us to offer multiple subscriptions like GitHub, should you wish to use that.
You may also use the payments functionality in Jumpstart Pro to process one-time payments instead. In fact, that's what we're using on our website to sell Jumpstart Pro!
If you remove all payment providers, the Pricing and Billing pages will be disabled for users.
Jumpstart and the Pay gem payments using Stripe are Strong Customer Authentication (SCA) compatible. We provide authentication for setting up new cards and will email customers when a subscription payment requires additional authentication.
We use the Stripe CLI to use webhooks to keep subscriptions and payments up-to-date in our application now. This is required to handle SCA payments that require authentication.
Subscriptions in Jumpstart Pro are billed against a Account, not a User. This allows you to handle various different billing situations.
To subscribe an individual, they just need to be logged in as their personal account and the subscription will be billed to them.
Account billing allows you to share resources and billing functionality with the entire account and allows any member to manage the subscription. It's much easier to start with account billing support than adding it later, so we've got you covered even if you don't need it right away.
For more information on how accounts work in Jumpstart Pro, check out the Accounts documentation.
Plans can be defined in the Plans Admin and allows for changes without deploying code. Each plan should be defined with the price amount in cents.
The Stripe and Braintree IDs are used to subscribe the user to the matching plan defined inside Stripe or Braintree.
Stripe IDs may either be a Plan ID or a Price ID.
There are two types of "free" plans:
For users who use your app for free, they don't need a plan or a subscription. These are just regular users of your app. If they're subscribed, they can access the premium features. If not, they can have access to any free features you want. Technically, they're not subscribed to a "free plan", but you can make the app look and feel like it.
For users who get free access to paid features, you can assign them a subscription to a free plan. Jumpstart Pro comes with a free plan that can be used for this purpose and is applied automatically to Admin users who are created in the Jumpstart Config area.
# Ensure Jumpstart free plan exists for admin users
Plan.where(name: "Free").first_or_create(hidden: true, amount: 0, currency: :usd, interval: :month, trial_period_days: 0, fake_processor_id: :free)
# Create a fake subscription for the admin user so they have access to everything by default
account = user.accounts.first
account.set_payment_processor :fake_processor, allow_fake: true
account.payment_processor.subscribe
Generic trials are trials without a card or subscription plan. These can be configured in app/models/account.rb
by uncommenting the before_create
block. You can check if an account is on generic trial with account.on_generic_trial?
.
Subscription trials are trials that require both a card upfront and a subscription plan selected. You can simply add trial_period_days
when creating a Plan in the admin. When the subscription is created, the trial_period_days
will be passed along to Stripe and Braintree for adding a trial to the subscription.
require_subscription!
is a method defined within the SubscriptionStatus
module under the Accounts
module. This method is intended to be used as a before_action
filter in Rails controllers to ensure that only subscribed users can access certain actions.
When require_subscription!
is called, it checks whether the current user is signed in and whether they are subscribed. If the user is not subscribed, they will be redirected to the pricing page.
require_subscription!
uses Pay.default_product_name
. If you would like to check for a specific product you can create your own method in SubscriptionStatus
.
In this example, the premium_features
action can only be accessed by users who are subscribed. If a user who is not subscribed tries to access this action, they will be redirected to the pricing page.
class ProductsController < ApplicationController
before_action :require_subscription!, only: [:premium_features]
def index
# ...
end
def premium_features
# Only accessible by subscribed users
end
# ...
end
Processing payments with Stripe is as simple as adding your Stripe credentials, enabling the Stripe configuration, and adding plans with Stripe IDs on them.
The /webhooks/stripe
endpoint is available in your application for handling webhooks from Stripe. You can add the webhook to Stripe to have it process activity from your Stripe account.
Jumpstart now requires webhooks to support SCA. You must use the Stripe CLI to forward webhooks to your local Rails server to process subscriptions and payments with SCA.
stripe login
stripe listen --forward-to localhost:5000/webhooks/stripe
Once stripe CLI is running it should display your signing secret. Add it to your credentials to make sure your server can receive stripe events.
Alternatively, you can use ngrok or localtunnel to expose your Rails server to the internet so it can receive webhooks.
Processing payments with Braintree is as simple as adding your Braintree credentials, enabling the Braintree configuration, and adding plans with the Braintree IDs on them. We handle all the heavy lifting such as calculation proration discounts to allow users to swap between monthly and yearly plans which Braintree does not support out of the box.
Before using Braintree, you will need to define a plan-credit
discount in your Braintree control panel. This discount will be used to properly prorate subscriptions that change from yearly to monthly billing, or from monthly to yearly billing.
The discount amount configured in the Braintree control panel can be any value you wish, as Pay will override the defined amount with our own custom amount each time we apply the coupon. This coupon is needed since Braintree does not natively support prorating subscriptions across subscription frequencies.
The /webhooks/braintree
endpoint is available in your application for handling webhooks from Braintree. You can add the webhook to Braintree to have it
PayPal is supported out of the box using Braintree for processing.
To enable PayPal in Jumpstart, you'll first need to enable it in your Braintree account under the Processing Options section.
Jumpstart supports two PayPal configurations:
The Braintree Drop-In UI is a widget like Stripe elements that handles all the various enabled payment options. If you wish to process both credit cards and PayPal through Braintree, this is the best option.
The Standalone PayPal button is designed for users who want to use PayPal with Stripe or by itself. This embeds a PayPal checkout button in the form without using the Braintree Drop-In UI. It still uses the Braintree Javascript to do this, but without the credit card form.
If you want to sell products that are one-time purchases, you can use the payment forms from Jumpstart Pro to do this.
The easiest way to do this is to have a user put their card in first and then show them the checkout form.
An example from the Jumpstart Pro website when purchasing a license: We check if the current account has a card on file, if so we let you purchase a license. If not, we display the card form.
<% if !current_account.payment_processor&.default_payment_method %>
<p>First, add a payment method to your account:
<%= render 'payment_methods/forms/stripe' if Jumpstart.config.stripe? %>
<%= render 'payment_methods/forms/braintree' if Jumpstart.config.braintree? %>
<%= render 'payment_methods/forms/paypal' if Jumpstart.config.paypal? %>
<% else %>
<%= render 'form', license: @license %>
<% end %>
Then on the LicenseController create action, we use current_account.charge(amount)
from Pay to issue the charge before creating the license.
A user cannot switch payment processors during their subscription. For example, switching from Stripe to Braintree. They must cancel and resubscribe to switch payment providers.