Taking a cut with Stripe Connect
There are several ways to take a cut, or collect a commission on the payments flowing through your Stripe integration. In the previous articles in this series, you learned how to decide between Standard, Express, and Custom accounts types, and about the different funds flows (also known as charge types) that you can implement with Stripe Connect. Here, you’ll learn approaches to collecting a portion of the proceeds as revenue for your platform.
There are four primary ways to earn money with your platform:
- Collecting application fees with direct or destination charges
- Withholding a small amount of the payment when transferring funds to the connected account with destination charges or separate charges and transfers
- Use Account debits to collect a one-off payment from a connected account
- Collecting a recurring payment from your users as customers of your platform
The first solution for taking a cut is to use application fees with direct or destination charges. Soon after the direct charges funds flow was released, Stripe added support for “fee splitting” with the
application_fee_amount parameter. The
application_fee_amount parameter can be included in an API call to create payment-related objects like a PaymentIntent or Checkout Session. Application fees are first class objects in the API and represent funds going from the connected account to the platform.
You can use the API to query for Application fees. Or you can view them from your platform dashboard – you’ll see the fees collected under Payments > All Payments > Collected fees.
Your users who have access to the Standard dashboard can see the breakdown of Stripe fees and application fees in their dashboard:
Direct charges with application fees
Here’s an example of adding an application fee of $3.21 to a direct charge for $40 to the connected account with ID
curl https://api.stripe.com/v1/payment_intents \ -u sk_test_abc123: \ -d amount=4000 \ -d currency="usd" \ -d payment_method=pm_card_visa \ -d confirm=true \ -d application_fee_amount="321" \ -H "Stripe-Account: acct_1LuN62ClUWl50Go4"
As soon as the direct charge is complete, application and stripe fees are collected from the amount and the connected account’s pending balance increases by the net amount:
Destination charges with application fees
Here’s an example of adding an application fee of $3.21 to a destination charge for $40 to the connected account with ID
curl https://api.stripe.com/v1/payment_intents \ -u sk_test_abc123: \ -d amount=4000 \ -d currency="usd" \ -d payment_method=pm_card_visa \ -d confirm=true \ -d application_fee_amount="321" \ -d "transfer_data[destination]=acct_1KPRf02R4eodYxfv"
Recall that a destination charge combines two actions: collecting payment on the platform account, then creating a transfer that moves money to the connected account. Here’s what the flow looks like with application fees:
From the platform account’s dashboard, you’ll find the collected fees in the same place as those collected with direct charges, here’s what it looks like in this scenario:
If your user has access to the Express dashboard, this is how they would see the fee when they log-in:
Separate charge and transfer application fees
Application fees are not supported for the separate charge and transfer funds flow. Instead, you’ll need to use one of the other approaches that we’ll outline next.
Reasons to consider using application fees to take a cut:
- You use direct charges
- Your users need to understand the amount the platform account collects and see that as a separate fee
- You need to query the API for the list of fees you’ve collected
Transfer a smaller amount
The second solution for taking a cut is to transfer an amount less than the total payment to the connected account. You can use this with destination charges or separate charges and transfers. This approach is less explicit about the fee being collected from the platform. No objects are explicitly created representing the amount you, the platform, are collecting. Furthermore, connected accounts will only see the amount transferred into their account without any breakdown of application fees.
Destination charge with smaller transfer
Here's an example of collecting a destination charge for $40 and then transferring $35 to the connected account with ID
curl https://api.stripe.com/v1/payment_intents \ -u sk_test_abc123: \ -d amount=4000 \ -d currency="usd" \ -d payment_method=pm_card_visa \ -d confirm=true \ -d "transfer_data[amount]=3500" \ -d "transfer_data[destination]=acct_1KPRf02R4eodYxfv"
Notice that instead of passing the
application_fee_amount, we include a new
transfer_data[amount] parameter with the amount we want transferred to the destination connected account.
From your platform dashboard, you’ll see links to the relevant transfer, the amount transferred, and the destination connected account where the transfer was sent:
The connected account will see that they received a payment of $35 and they don’t see any fees. Original charge amount is not shared, and this may make reporting more difficult as it does not create an application fee object.
Separate charge and transfer smaller amount
When using separate charges and transfers, you make the API call to create the payment related object, and the API call to create the transfer, so you can transfer less than the payment total. Since the most common use-case for SCT is to split payments across several connected accounts, for this example we’ll use a food delivery service example where we’ll collect a $40 payment, then send $10 to the driver’s connected account and $23 to the restaurant’s connected account.
First, we’ll collect a $40 payment from the end customer to our platform using a
curl https://api.stripe.com/v1/payment_intents \ -u sk_test_abc123: \ -d amount=4000 \ -d currency=usd \ -d payment_method=pm_card_visa \ -d confirm=true \ -d transfer_group=demo-03
The payment from the platform dashboard perspective appears as any payment collected outside of the context of Connect:
Then, using the ID of that payment intent’s latest charge as the source transaction, we’ll create a transfer for $10 to the driver’s connected account (
curl https://api.stripe.com/v1/transfers \ -u sk_test_abc123: \ -d amount=1000 \ -d currency=usd \ -d destination=acct_1KPRf02R4eodYxfv \ -d transfer_group=demo-04 \ -d source_transaction=ch_3MRIjjCZ6qsJgndJ0s4F8WUP
Next, we’ll send a second transfer of $23 to the restaurant’s connected account
curl https://api.stripe.com/v1/transfers \ -u sk_test_abc123: \ -d amount=2300 \ -d currency=usd \ -d destination=acct_1KP8JM2ROgShXwm9 \ -d transfer_group=demo-04 \ -d source_transaction=ch_3MRIjjCZ6qsJgndJ0s4F8WUP
Again from the platform dashboard, we can see the transfer:
Here’s a diagram of the food delivery use-case. Again, the end customer pays $40, then the driver receives $10 and the restaurant receives $23. After paying the Stripe fees, the platform keeps $5.54.
To understand what was included in the transfer, you’ll need to look under Balances > Transfers then drill into the specific transfer which has links to the source transaction and the payment created on the destination connected account. \
Reasons to consider transferring a smaller amount:
- You need to make transfers to several connected accounts
- You don’t want your users to see the application fee amounts or to know how much the original charge was for
- You do not need to query for the list of fees collected and will build your own reporting solution
Collect a one-time payment using account debits
There are a handful of use-cases where you might need to move money one-time from the connected account to your platform. You might need to recover funds for a previous refund, correct an error on the connected account’s balance, or as a one-time fee for your products or services. With Connect, your platform can debit the Stripe balance of an Express or Custom account using one of two methods: charge or transfer.
Collect a one-time payment from a connected account with a Charge
Using the lower-level Charges API (not PaymentIntents), you can use the connected account as the source and create a charge that will collect payment from the connected account to your platform:
curl https://api.stripe.com/v1/charges \ -u sk_test_1234: \ -d "amount"=1500 \ -d "currency"="usd" \ -d "source"="acct_1LuN62ClUWl50Go4"
Collect a one-time payment from a connected account with a Transfer
Recall that a Transfer moves money from one Stripe account to another. Most of the time, we use Transfers indirectly with destination charges, or directly with separate charge and transfer to move money from the platform to the connected account. In this scenario, we’ll create a Transfer to move money from the connected account back to the platform.
This time, we need to use the Stripe-Account header set to the ID of the connected account. This means we’re creating the Transfer on the connected account (
acct_1LuN62ClUWl50Go4) and the destination is the platform (
curl https://api.stripe.com/v1/transfers \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -H "Stripe-Account: acct_1LuN62ClUWl50Go4" \ -d "amount"=1500 \ -d "currency"="usd" \ -d "destination"="acct_1EceeUCZ6qsJgndJ"
Note that account debits only work for Express and Custom account types and there are several other restrictions you’ll need to review in the documentation.
Reasons to consider using account debits:
- One-off payments from the connected account to the platform
Collect recurring payments from your users as customers
While the title of the article references taking a cut or commission on payments you facilitate, you might want to monetize your platform without commissions. Let's say you want to collect $10 USD each month from your users, owners of the connected accounts with Stripe Billing. This is not possible if you only have the connected account. You’ll need to collect payment details, create a Customer, and create a Subscription instead.
When integrating with Stripe's Billing APIs for recurring payments, it's important to keep in mind that creating a Subscription requires having a Customer object, and you cannot use the connected account for this. A Customer and an Account are completely separate objects in Stripe's API, and there is no way to turn one into the other or "share" information between them.
The most common approach for platforms using Billing is to create a separate Customer object and handle all the Billing logic like payment method updates, handling payments, and proration using Subscriptions. To mitigate the confusion between the Account and the Customer objects for your users, you can use metadata on both the Customer and Account to track the association.
If you’re interested in taking this approach, take a look at the SaaS fundamentals series to get started.
Consider collecting payment from your users as customers if:
- You want to collect $N each month
- You do not want to collect a small part of each transaction
Your approach to taking a cut from payments your platform facilitates will depend on a number of factors. Here’s a summary of my recommendations:
If you want your users to see the fees collected, use application fees with the
application_fee_amount parameter for direct or destination charges.
If you want to obfuscate the charge or fee totals, use transfers with amounts less than the payment total.
If you want to charge a fixed monthly fee, or a usage-based amount every month, create platform customers for each of your users and charge them with a Stripe Billing subscription.