Recently I’m seeing more and more WordPress plugins adopt Stripe Connect, including, but not limited to, EDD, Gravity Forms, and most recently Restrict Content Pro.

Each one of them touts the ease of use of Stripe Connect, but they neglect to mention this fairly important point that also comes with using Connect that you cannot opt out of to the best of my knowledge: they will be able to see all the transactions that have happened, ever, and will happen on your account with all of their details.

Gravity Forms does make a passing note of this, but I feel like they play down the extent of the access:

Screenshot of the FAQ on Gravity Forms Stripe's page.
Screenshot taken at 00:44 GMT on 7th December 2019 from https://docs.gravityforms.com/faq-authenticating-with-stripe/.
“As with all integrators with Stripe Connect, we are provided access to  Stripe’s reporting portal which shows transactions that pass through our  plug-in. Like all Stripe transactions, this data is stored and secured  by Stripe, and is not transmitted to us in any way for any other  purposes. Gravity Forms does not use any unique transaction data from  this source, and we only review aggregate volume data occasionally to  monitor performance of the add-on. Additionally, we have limited access  to Stripe’s reporting portal to our company principals only.”

Here’s what’s happening behind the scenes, with screenshots:

The anatomy of a Stripe Connect relationship

In order to use Stripe Connect (SC from now on), we need two accounts:

  1. the main account – this is the one the others will connect to
  2. the sub account – this is usually yours; the one you’re using to take your your own customers’ money with

To illustrate this, I’m going to walk y’all through creating / configuring a main account, then connecting a sub account, all while setting up a minimal example to demonstrate what’s happening. All the accounts will be tests, but because Stripe is awesome, the same happens on live too.

The process of connecting a sub account to a main account happens via OAuth, where the important bits are:

  1. you, the sub account holder, click a link that takes you to Stripe’s domain that identifies the main account
  2. Stripe will then show you info about the main account, what access they need, and present you with two choices: Accept / Deny.
  3. When you click either, you’re taken to a page that the main account holder controls with a code appended as a query string, and they will exchange that code for your account info that they need
  4. [optional] You then may be taken to the page where you clicked the link originally from in step 1).

Let’s get implementing!

Setting up a main account

I will use my secondary dummy account to show you how to set up Connect so you can offer other Stripe accounts to connect to yours.

First off, log in to your account, go to the dashboard, make sure you’re on test view and click on the Connect menu option on the left.

Screenshot of Stripe dashboard with an arrow pointing at the Connect menu option on the left sidebar.

Clicking on the Get Started button will take you to a popup modal – here you need to select how much control you want over the connected accounts. Let’s select extension for now because it’s a lot less intrusive as the other one.

Screenshot of Stripe Connect selector: extension is selected.

We’re almost there, just one more settings page to go:

Stripe dashboard, now with Connect enabled.

From here, click on the blue Edit button, which will take you to a fairly short list of settings we need for the OAuth flow to work, some branding bits, and some explanation at the top. Let’s start with the explanation, because this is important.

Screenshot of Stripe Connect Application settings displaying the Integration capabilities.

According to the above screenshot, our master account:

  • will be able to read data from existing Stripe accounts
  • will NOT be able to create new accounts for users
  • will NOT be able to create new payments on behalf of users
  • will NOT be able to send funds and pay out users.

The term “user” here means any other connected Stripe account.

The settings we need to set:

Screenshot of Stripe Connect application settings showing the redirect URI part, and the top of the Branding part.

We need to set the redirect URI to at least one valid place on the internet that we control. Once the users, I mean sub account holders, initiate a connection to Stripe and they’re taken to Stripe’s OAuth page and either approve or deny the connection, they will be redirected to wherever we set this setting. Stripe will also give us a code to identify the OAuth connection ID so that we can fetch the freshly connected account’s data ID, which we could use to do things as them.

In my example minimal implementation, I’m using the official Stripe PHP API via composer and the Monolog library and will print the code and the account id into a log file as I don’t actually need them to show you what I want here.

Now that those settings are done and saved, I also need a link which sends people to the Stripe OAuth page to begin the connection. For the record, this is just a link, i.e.: an <a href="">link text</a>, and nothing else, nothing special. This can live anywhere on the internet, including your WordPress dashboard on your own site.

The only important page that I need to control as the main account holder is the redirect page.

That’s all I needed to configure. Next step: setting up my minimal website to facilitate the connection and purchase demos.

Minimal implementation website

All the code is here: https://github.com/javorszky/stripe-connect-demo.

I have two pages: an index.html page that has the link to start the Stripe connection request, and a stripe.php file which is set as my redirect URI that will exchange the code for the account info.

I got the link from visiting this link in Stripe’s documentation: https://stripe.com/docs/connect/standard-accounts#integrating-oauth while signed in with the Stripe account that I’m going to be using as the main one. One modification I’m going to do there is to replace the scope=read_write with scope=read_only.

The link therefore points to:

https://connect.stripe.com/oauth/authorize?response_type=code&client_id=ca_GJKC2lkVSzC4m5vRJTnrXE3DjnFfXvjf&scope=read_only

There are some other considerations the document mentions that I’d do in a live environment but will omit here because it’s not needed here, like the state parameter.

Let’s get connecting!

Okay, next step is to fire up a browser where I’m not logged into the main Stripe account, and visit my site at https://scdemomain.test and actually begin to establish the connection. Here goes:

Screenshot of SCDemoMain.test showing one link to connect to Stripe.

Clicking on that Connect to Stripe link will take me to the beginning of the OAuth flow at Stripe:

Screenshot of OAuth question at Stripe. Do I authorize the connection?

Here we have the main account’s site name that we set previously. Normally you won’t have the Switch account bit. I have multiple Stripe accounts under my profile. Click on the Connect my Stripe Account button, and we’re taken back to the redirect URI set previously.

Screenshot of the local site at the redirect URI address showing connected account details.

And we have a connection! Ideally this should now show up on the main account’s Stripe Connect / Accounts menu:

Screenshot of the main account’s Connect / Accounts page showing my other account being connected.

Neat. Pay attention to the date connected: December 6 (of 2019), i.e.: today. Or yesterday, depending on when I’ll finish writing this article.

What data can they actually see?

Now that we have the two accounts connected, let’s see what data I can find from my main Dummy 2 account and view, that technically belongs to my other, connected, account.

Clicking into the account, or on the actual row will take us to this page:

Screenshot of connected account overview.

Had to double check a few things on this page. First that I was indeed on the main Stripe account’s page: yes, top left corner shows Dummy Acco..., and I’m still in the Firefox private session that I exclusively used while writing this article.

Then that the other account was indeed the connected one: also yes, see the rectangled bit near the top.

Still viewing test data, so good on that front as well.

So then why am I seeing payouts from the past? And by past, I mean from the time earlier than my connection to the main account? The arrow points to a payout of £9.51 on 26th November (of 2019).

This is already a lot of information that I, personally, would not be comfortable with another party seeing if they don’t necessarily need it. Gravity Forms, EDD, and Restrict Content Pro definitely do not need it.

Let’s dig further though: payments!

Screenshot of connected account activity / payments listing several transactions from 22nd November.

Those are actual transactions that my test account did while I was working on a client site on the connected Stripe account. Okay, freaky. What’s behind View all payments?

Screenshot of connected account / all payments. There are 2921 results.

That opened a new tab. I am looking at the connected account’s payments, in view only mode because that’s the scope that I requested. I can see probably ALL the transactions my connected account has ever done in test mode.

Let me find one that wasn’t for a client project and see what details I can see for the actual transaction. I’m on page 2, and found one:

Screenshot of payments list with arrow pointing to a payment that was not for a client.

Clicking into that reveals an astounding level of detail:

Screenshot of payment details, part 1 of 3. Timeline and payment details are visible.
Screenshot of payment details, part 2 of 3. Payment method and session info are visible.
Screenshot of payment details, part 3 of 3. Metadata, receipt history, logs, and events are visible.

To recap, as the main account you can see all the details of a payment that happened before the connection was made. And by all the details, I mean

  • who the actual customer is with full contact details, including address, email address, phone number if that was provided
  • the amount that was paid
  • the type of card that was used and the last 4 digits of said card and expiry date
  • what the risk evaluation was
  • what fees the connected account paid on that order
  • which order it was
  • session details, which includes the browser they used, the IP address they used at the time which is even geolocated and shown on a map for convenience
  • any metadata the site included, in this case the order id, that it's a recurring order, the site url, the customer’s name, and their email address

Reason I’m comfortable putting all of this here is because that payment was me using mostly false data anyways and a test card number.

There was talk about commission?

I made a purchase with my connected account after the connection, about 10 minutes ago. There wasn’t any money moved into the main Stripe account itself without modifying anything on the actual payment request.

Previously however I did have the opportunity to work on a project where Connect actually made sense, and we incorporated application fees into the request. What we’ve done there is if something cost $10, we split that into a $9 purchase and a $1 application fee. That way the connected account paid the fee on the $9, the main account got the $1. See Stripe documentation’s page on creating direct charges. You do need to customize the data sent to Stripe in order to take advantage of that, and it’s not straightforward.

Out of the box Stripe does not give you a cut from the connected account’s transactions.

I don’t know whether that’s the same if you’re a Partner or a Verified Partner, because I’m neither. According to their documentation on partners, they do not offer revenue share on that program.

This is a lot of data. GDPR? CCPA?

If you’re a main account, you now have access to the personally identifiable information of the customers of the accounts that are connected to yours. That opens you up to be a data controller for a LOT of people. Are you prepared to take that burden on?

For folks who connected their Stripe accounts

Ask these questions from the Stripe account holders to whom you connected yours:

  • have they declared that they WILL see these details on your account?
  • are YOU okay with it?
  • have you let your customers know that their details are also visible to someone they aren’t even in a business relationship with? Are they okay with it?

Here’s where to disconnect your Stripe account

If you decide you no longer want the other party to see all of these details, you can sever the connection between yours and the main account. This will also break the link between you and Stripe, and depending on the plugin you’re using, you might not have an easy way to supply your trusty API key and secret instead.

Some plugins flat out do not offer that authentication method any more.

Make sure that you can still take payments, or can still configure your plugin if you do decide to sever the Connect connection.

However if you still want to go ahead with disconnecting it, go to your settings and Authorized applications. In there you can revoke the connection to the account you’re connected to.

Screenshot of settings with an arrow pointing to the authorized applications item.

When does it make sense to use Connect?

When the main account legitimately needs to see the transactions and their data. My accounting software for example – it pulls in data from Stripe so it can generate payment links on invoices and know when someone paid the invoice via Stripe.

Another example is when there’s an umbrella corporation, but each franchise has their own accounts, because they are separate from each other. There’s a coffee shop in Oxford that has shops in Bath and Bristol. They are each their own entities with their own payroll, accounting, sales and costs, but they belong to one small chain who has direct control over them. In that case the chain would have the main account and each location would be a separate connected account.

It also makes sense for Shopify where the customer pays Shopify first, and then Shopify pays you (less their own fees).

It does not make sense in a self hosted world where you’re supposed to own all your data and plugin vendors don’t provide anything besides code, and support for the plugin.

At least I don’t think it does for them.

Photo by israel palacio on Unsplash