Stripe

We use Stripe as 3rd party provider for our payments. We offer two ways of payment, which implementation are greatly different from one another:

  • Invoices

  • Credit cards

Both flows benefits from Stripe callbacks (using webhooks) thanks to this gem.

In the front-end, we also use two libraries: stripe-js & react-stripe-js to load "Stripe elements". This is initialized in the RecruiterContainer, in multiple places (go find them).

And in the OrderPage component, we import those:

import {
  CardNumberElement,
  CardExpiryElement,
  CardCvcElement,
  useStripe,
  useElements,
} from "@stripe/react-stripe-js";

PaymentIntents

The first way of paying is with PaymentIntent, which is credit cards payment.

A PaymentIntent is a record both in our DB and in Stripe.

Basically, we create the PaymentIntent and send it to Stripe. Stripe then process it, and when it's done, contact our server via Webhook.

Stripe will emit an event, that we will receive in the Billing::StripeCallbacksService

Based on the event, we will do some stuff on our side. For example, for a payment_intent_succeeded event, we will retrieve the linked PaymentIntent record in our DB to find the linked recruiter and create the credits he just bought.

Invoices

The flow is a bit similar, we'll create an Invoice record in our DB then send the information to Stripe. If successful, Stripe will emit an after_invoice_sent event and we'll create the credits at this point (no need to wait for the invoice to be paid).

How to test locally?

Stripe uses webhook, so you need to make your localhost contactable by Stripe.

This is doable by running this command in a bash terminal:

You might need to install the Stripe CLI first and run stripe login before though.

Dev VS Prod

Stripe offers a "dev" mode that is used by our localhost app, review apps and Staging app.

The "prod" mode is obviously only used for production and should be touched very lightly.

Just click on the "Test mode" switch
Check the "Developpers"

In the developer section, you can see the webhooks. We have 2:

  • One for Staging (still active)

  • One for an old review app (not active as this review app does not exist)

If you want to test Stripe on a review app, simply change the URL of this webhook to the one of your review app, no need to create a new one.

But wait, there is only 2? Where is production?

Remember, we're in the "test" section of Stripe, so we only see our "test applications".

RTFM

Stripe is extremely well documented, so while it's a bit hard to keep up with the implementation the doc is here to help you:

And some webhooks doc:

Stripe with Squarehub

Stripe also defines two other types of record: Prices & Product.

You probably want to read the doc further if you need to work on that, but basically a Product on Stripe can have multiple Prices.

Those record are also "duplicated" in our own DB, where a Price belongs to a Product, and each of them keep their Stripe equivalent with the stripe_id attribute.


On Squarehub, we also have a concept of ProductFamily. A ProductFamily is a record that contains an array of product IDs.

Every company signing up on Squarehub are linked to a ProductFamily, basically keeping track of the products they are allowed to see.

That means that two different companies might see different products & prices if they belongs to a different product_family.


For the moment, almost all companies are on the latest ProductFamily (check on a rails console in production if you want to discover it and see their products). If I recall correctly, only 2 companies are on a previous ProductFamily.

Keep a track on that when refactoring the Order component or every component linked to a pricing, it should still work for those companies (or suggest sales to update them to the latest ProductFamily so that everyone is on the same page).

You need to change the prices?

New pricing comes often, and you might need to implement a new one some day.

First, remember it's a money sensitive feature so it should be double triple tested on every environment (local, review app & staging).

0. Prepare your local setup

Working with Stripe means some setup to do, so take the time to do it right. It's ok if it takes you some time to be comfy, but it's completely worth it!

  • Locally: make sure the webhook are functional with the stripe listen… command

  • Review app: make sure the webhook are corretly pointing to your review app (this will be done in the "Test" mode > Developpers > Webhooks section on Stripe)

  • Staging: nothing to be done (webhooks are always up)

  • Production: same as Staging (oof)

Your local data should be good as well! So make sure you have all Prices & Products created in your local DB and that your companies have their product family. If this is a bit confusing, keep reading this section and come back to the setup later.

1. Create new prices & products

You cannot change a price on Stripe once it's been consumed once. So if you want to "change" the pricing, you're actually going to create new prices (and new product).

Prices belongs to a product on Stripe (a product can have for example one price in euros, another in dollar, etc)

If you create a new price, create a new product as well to keep track of the changes.

So you need to create new prices/products on Stripe, that's your first step.

Remember Stripe has two modes though, so you'll need to create them both in the "Test" mode and in the "Production" mode.

After they've been created in Stripe, you need to write a script to create them in the DB. You can look at the latest script in the codebase that did exactly that:

scripts/2023_02_09_fix_new_february_pricing.rb

2. Create a new product family

You'll need to create a new product family and put the IDs of the product you created in its product_ids attribute.

This was the creation of the latest product family, which is from the script mentioned above:

3. Use the new product family

To be effective, the new product family needs to be used! All companies have a product_family_id reference (they belongs_to a product_family), so you just need to set that with the new one to make it visible!

Two things to consider:

  • Update existing companies if you want them to see the new price

  • Change product family assigned during sign up

4. Adapt the front-end

Now you need to make sure the view is still good for:

  • Old companies that haven't migrated to the new pricing (if you haven't updated them all)

  • Old companies that have migrated to the new pricing

  • New companies sign-in up

5. Test the whole flow

After you're sure the views are good for everyone, test the actual purchase flow for the 3 cases stated above (you might have only 2 if you migrated every company to the new pricing).

Here is a very good doc on how to test with Stripe:

It'll show you what you can use to test, the most known is the Card Number 42424242424242 but there are a lot of other things you could use from there.

Last updated