Implementing Stripe Connect in Rails: Part 2

Some time ago we wrote an article to explain how to implement Stripe Connect in a Rails application. That article covered mainly the connection part between Rails and Stripe. This one will cover the fun part, which is making transactions, charges, refunds, and more.

If you haven't checked out the first part yet I recommend you do so since this article will continue from where that one ended.

Frontend

Before diving into the Stripe API, one of the first things that you should implement is a form that captures the payment information (e.g. credit card). The simplest way to do this is using Stripe Checkout, but if you want a more customizable version you can use Stripe Elements. I recommend that you follow the official documentation of any of these options so you have everything ready to continue with the backend work.

Backend

Charges

Once you have your form ready to collect payment information you'll probably want it to execute a Charge when it's submitted.

# app/controllers/payments_controller.rb

class PaymentsController < ApplicationController
  # triggered after submit payment form
  def create
    # ...

    charge = StripeChargeService.charge!(params[:stripeToken])

    # ... (create Payment, store charge id in db, respond, etc.)
  end
end

There are a few different approaches to implement the Stripe Charge. Each implementation fits different needs, since in some cases the platform account should be the one that pays for the Stripe fee and in some other cases it would be the connected account. I recommend that you take a look at the official guides to make sure that you choose the one that fits better for you.

Example implementation:

# app/services/stripe_charge_service.rb

class StripeChargeService
  def self.charge!(stripe_token)
    # ...

    Stripe::Charge.create({
      amount: total_amount_cents, # total amount to charge,
      currency: "usd",
      source: stripe_token, # token generated by Stripe in the frontend
      application_fee_amount: platform_amount_cents, # portion that goes to the Stripe platform account
    }, stripe_account: user.stripe_user_id) # id of the Stripe connected account

    # ...
  end
end

In the example above, the amount will be split between the platform account and the connected account. The amount that the connected account will get would be total_amount_cents - platform_amount_cents.

It is recommended to also capture any Stripe exception that could happen during the communication with the API. You can do that by including:

rescue Stripe::CardError, Stripe::InvalidRequestError,
       Stripe::APIConnectionError, Stripe::RateLimitError,
       Stripe::AuthenticationError, Stripe::StripeError => error

An example implementation could be:

# app/services/stripe_charge_service.rb

class StripeChargeService
  def self.charge!(stripe_token)
    charge = Stripe::Charge.create({
      amount: total_amount_cents, # total amount to charge,
      currency: "usd",
      source: stripe_token, # token generated by Stripe in the frontend
      application_fee_amount: platform_amount_cents, # portion that goes to the Stripe platform account
    }, stripe_account: user.stripe_user_id) # id of the Stripe connected account

    {response: charge, status: "success"}

    rescue Stripe::CardError, Stripe::InvalidRequestError,
           Stripe::APIConnectionError, Stripe::RateLimitError,
           Stripe::AuthenticationError, Stripe::StripeError => error

      {response: error.message, status: "error"}
  end
end

Check out the API documentation to see all the available attributes that you can use.

Transfers

You can use Transfers to send money from the platform account to a connected account.

# app/services/stripe_transfer_service.rb

class StripeTransferService
  def self.transfer!
    # ...

    Stripe::Transfer.create({
      amount: amount,
      currency: "usd",
      destination: user.stripe_user_id,
    })

    # ...
  end
end

To undo a Transfer that was previously made (either entirely or partially) you can use the Transfer Reversal object.

If what you want is to transfer money the other way around (from a connected account to the platform account) you can use Account Debits, but keep in mind that there's an additional cost for using it.

Stripe::Transfer.create({
  amount: amount,
  currency: "usd",
  destination: "{PLATFORM_STRIPE_ACCOUNT_ID}",
  }, stripe_account: user.stripe_user_id)

Refunds

With Refunds you can undo any previous Charge that was made (either entirely or partially).

# app/services/stripe_refund_service.rb

class StripeRefundService
  def self.refund!
    # ...

    Stripe::Refund.create({
      charge: charge_id_token, # id of the Stripe Charge object
      amount: amount,
      refund_application_fee: true
    }, stripe_account: user.stripe_user_id)

    # ...
  end
end

By default it only refunds the portion of the Charge that went to the connected account, but you can set refund_application_fee: true to refund the platform account part too. Check out the API documentation to see all the available attributes that you can use. Also keep in mind that the Stripe fee that was paid by the platform account or connected account (depending on your configuration) is not refundable, so you will lose that part if you perform a refund.

Conclusion

This was an overview of some of the most popular Stripe objects that are available. The Stripe API is very powerful and has a lot more things that you can do. I recommend that you take a look at their guides for some things that were not covered in this article.

If you have any question feel free to leave a comment below.