Stripe Connect accounts
When a school is onboarded to Stripe Connect, we tie that Stripe Connect account to the provider's Payer in our database. By doing so, any InvoicePayments that are recorded to/from that Payer are then reflected in Stripe as well.
For example, if a school with a Stripe Connect account receives a $10 student payment, we make a request to Stripe to move $10 from the Dreambound Stripe account into the school's Stripe Connect account automatically.
Onboarding
We can (and should) onboard schools to Stripe Connect through the Admin portal on the school's Payer page. Once onboarding is complete, money is ready to flow.
Note: Eventually, we will expose this to schools to use as self-serve option, but we are limiting it to admins for now.
Watching Stripe webhooks
In order to make sure that we're updating our internal Dreambound balance properly, we watch Stripe's webhooks for Connect-related events (transfer, payout, topup, etc.).
Because these events can either be initiated within our system or within Stripe itself, we need a way to differentiate between the two and react accordingly. The main way that we watch for this is through the Stripe transfer_group property.
Stripe payments initiated in Dreambound
When we call the Stripe API internally to create a payment, we attach the InvoiceCharge ID it's related to as the transfer_group in the request. Stripe passes this property through to the webhook events.
When we receive the webhook for that payment, we look at the transfer_group, lookup charges with that ID, and then log a final InvoicePayment completing the loop and marking the charge as complete.
Stripe payments initiated in Stripe
When an action is taken in Stripe directly (e.g. someone in the Stripe dashboard manually sends a payment from the Dreambound Stripe account to a school's Stripe Connect account), we won't a value in the transfer_group property, because that movement of money didn't happen to complete an existing InvoiceCharge. It still needs to recorded, however, so that we can reflect that movement of money in our Dreambound balances.
When we receive the webhook of a payment without a transfer_group ID, we immediately create a matching InvoiceCost/InvoiceCharge/InvoicePayment set to reflect that money movement.
Failures
There are multiple reasons why a Stripe operation might fail after being initiated. If Stripe webhooks fail for any reason, we reverse any previous steps taken for that transaction.
Payouts
Payouts happen automatically on a daily basis to the school's bank account on file.
Edge cases
Schools with multiple locations
We have received requests from certain schools that have multiple locations but want to use a shared Stripe Connect account to receive their payments. In order to support this, we made it possible to transfer balances between Payers.
We attach the Stripe Connect account to the Payer record for one of the schools, and then use the /payer/{id}/create_balance_transfer form to transfer money between locations.
Once this payment is made to the Stripe Connect-enabled school, their Dreambound balances will be updated, the transferred money will flow into Stripe and be paid out to the shared bank account.