Working with Stripe Payouts API

The Wedding Favor lets engaged couples start a fundraising page to help pay for the wedding of their dreams, so it’s no surprise that managing payments is very important to us. Our goal is to make it as easy and as secure as possible for couples to receive money.

We’ve tried everything. Our first iteration used PayPal, but to optimize that experience and avoid credit card aggregation, we required the person gifting money to also have a PayPal account.

Amazon FPS, used by Kickstarter, is even worse. The couple would have to create a special Amazon account, a lengthy process that also asks them to identify their “business.” Their business is Gettin' Hitched LLC, I guess.

WePay provides a friendlier API and interface, but it required an IFRAME strategy that, again, left something to be desired from a flow standpoint. It also requires that our user learn about WePay — a confusing experience for them, as they are just getting to know The Wedding Favor.

Then came Balanced Payments and it all seemed too good to be true. Move money from one bank account, pop a fee on top, and send the balance into another bank account. Perfect!

But I was truly disturbed by how much their dashboard and documentation looked, at least in spirit, like Stripe’s. It was as if some higher-up printed out Stripe’s website, dropped the papers on a young developer-designer’s desk, and ordered, “Do this.”

Still we pressed forward, learning the ins and outs of Balanced’s API. It was fairly easy to get up to speed. After it all, it was just like Stripe’s, just a bit less developer-friendly.

Not satisfied, I shot Stripe an e-mail. To my surprise, they invited me to access a pre-release version of their new Payouts API. Here are the results.

Developer Relations

Both Balanced and Stripe have reached out to me personally, but only Stripe provided me with direct access to a member of their development team and responded to feedback. Amber even offered me access to her Gtalk while she ironed out documentation edge cases. I am always impressed by Stripe’s transparent, accessible developer communications, but they really blew the lid off during this sprint.


Stripe’s API is beautiful. The payouts component is no exception. It’s well-documented and easy to understand. More importantly, it is demonstrably easier to maintain. Switching to Stripe Payouts led to 140 additions but over 200 deletions in our repo. Less code means fewer things go wrong.

It starts with ensuring the recipient has securely provided us their bank account information and persisting a recipient ID, so that we know where to send transferred funds later. Here we are responding in our controller to a form POST.

recipient = Stripe::Recipient.create(
    name: "#{}",
    type: 'individual',
    bank_account: {
        country: 'US',
        routing_number: params[:routing_number],
        account_number: params[:account_number]


With a recipient_id stored on our User model, we enable the Gift button on their wedding page. When a gift is sent to the user, we generate a Gift model with a simple Stripe::Charge call. Here it’s business as usual if you’re familiar with Stripe.

def save_with_charge(token)
    # This is where we tack on our service fee.
    amount = self.amount + fee

        charge = Stripe::Charge.create(
            amount: (amount * 100), # Stripe expects pennies
            currency: 'usd',
            card: token,
            description: "Wedding gift to #{}"
        self.charge_id =

Whenever a gift is successfully created in our database, we automatically trigger an update to the engaged couple’s balance. This ensures we have a record of what is owed to them, since our internal Stripe balance will include additional service fees to cover processing.

Like any money received from Stripe, the payment will need to clear. You can choose to allow payouts earlier than that, provided your Stripe balance can cover it. When our couples request a payout to their bank account, we create a new Payout model so that we have a record of the request.

class Payout < ActiveRecord::Base
    before_save :transfer
    def transfer
        transfer = Stripe::Transfer.create(
            amount: wedding.balance, # Always deduct the total
            currency: 'usd',
            recipient: wedding.recipient_id, # Identifies their bank account
            statement_descriptor: 'Wedding registry payout'

        self.status = 'pending'
        self.transfer_id =

Here we are initiating the bank account transfer and making sure to empty the user’s balance. Later Stripe’s web hooks will contact our callback with an event POST. We need to respond to that event and let the user know their money transfer is complete.

event = JSON.parse(
case event['type']
when 'transfer.paid'
    payout = Payout.find_by_transfer_id(event['data']['object']['id'])
    payout.status = 'paid'

You can view a sample registry page (payments are disabled). Clicking on the Gift button will reveal a Stripe form, formatted and validated by jQuery.payment.

Have a Plan

Working with the API is simple, but it’s important to understand the flow of funds, its impact on your Stripe’s balance, and ways to increase transparency to your users. People need to understand how much money they have and its state of transfer. Make sure you are promising the right turnaround times. We chose to simplify the process and allowing users to deduct only their total balance, but you could easily provide them an option to do a partial withdrawal.

What’s Next

When we first conceived of The Wedding Favor, elegant tools for managing money between multiple parties didn’t exist. We had to bend our user experience into all sorts of shapes and sizes to make it work, and even then the result was not what we wanted. Along the way new vendors got us a little closer, but Stripe is the first company to do it right.

That’s the story at Stripe. Their core product, enabling developers to charge credit cards, wasn’t the first to the market. It is, instead, the best.