Using a Stripe Webhook to transfer tax to the platform account
Last updated
Last updated
Please note this feature requires the use of backend workflows. You will need to be on a paid Bubble plan to use backend workflows.
As mentioned in the previous section of the plugin documentation, if you're using Stripe Tax when creating a Destination charge you will need to transfer the tax component of the payment back to the platform account.
There are a number of ways to do this, but the most robust (which is recommended by Stripe) is to use a Transfer Reversal when the checkout.session.completed event is fired.
To use this approach with your Bubble app, you can create a Stripe Webhook that triggers a backend workflow whenever a Checkout Session is completed.
This is an intermediate/advanced setup. Some familiarity with backend workflows and Stripe Webhooks is recommended.
You can implement this approach by following these steps:
Enable backend workflows
Navigate to Settings -> API and check the 'Enable Workflow API and backend workflows' option:
Create a new backend workflow
Navigate to the backend workflows tab and create a new API endpoint. It is recommended to use only lowercase letters and no spaces in the endpoint name.
Change the Parameter definition field to Detect request data and click on the Detect data button. You should see a screen like the below appear:
Copy the URL presented to you to your clipboard.
Create a webhook in your Stripe dashboard
In your Stripe dashboard, navigate to:
Developers -> Webhooks
and create a new endpoint. If you haven't previously created a webhook in Stripe, you may be presented with the option to 'Create an event destination' (click this). You'll then be presented with a screen that looks like this:
Paste the URL you were presented with in step #2 into the Endpoint URL field.
This is also a good time to add authentication to your backend workflow. When you initially created the API endpoint in your Bubble app, you may have noticed the 'This workflow can be run without authentication' option:
If you leave this unchecked (which it is recommended you do) the Stripe webhook will trigger the backend workflow unless we provide it with something that lets it prove to Bubble that it is authenticated.
You can do this by navigating to:
Settings -> API
and generating a new API token (you can name it whatever you want):
API tokens can be used to exploit your platform if they fall into the hands of a bad actor, so be very careful in using them.
Navigate back to your stripe dashboard and append the api_token to the end of your endpoint URL (after adding a '?'):
Use the default 'Events on your account' for the Listen to option and choose checkout.session.completed for the event to listen to:
Click on add endpoint to create your Stripe Webhook.
Initialize the webhook
The webhook has now been created, but you still need to initialize it. To do this, ensure you have the Detecting Request Data popup open in your Bubble editor (it will not work otherwise):
Then create a Checkout Session from your app and submit the payment form. Once the Checkout Session has been completed, navigate back to the backend workflows tab and you should see the data associated with the workflow coming through.
Most of the default field types Bubble assigns to the data are ok, but it is recommend you change the following fields from 'number' to 'date (UNIX)':
created
object created
object expires_at
Remove 'initialize' from the endpoint URL in Stripe
After successfully initlializing the webhook, you'll need to remove 'initialize' from the endpoint URL in Stripe:
Your backend workflow in Bubble should now be triggered whenever a Stripe Checkout Session is completed.
Save down the payment intent ID associated with a transaction
In order to transfer the tax component of a transaction back to the platform account, you can use the Stripe Connect - Reverse a Transfer action that comes with the Stripe Connect - Marketplace plugin. However, in order to run this action we'll first need to save down the amount of tax that was part of the transaction and also get the Transfer ID associated with the transaction.
It is recommended you start off by saving down the Payment Intent ID as this will be needed later.
It is assumed you have added a 'transaction' data type to your database with the following fields.
Amount (cents) (number)
Charge ID (text)
Checkout Session ID (text)
Payment Intent ID (text)
Seller Account ID (text)
Total Tax (number)
Transfer ID (text)
Add a 'Make Changes to a Thing' action to your backend workflow and 'Search for transactions: first item'. Add in a constraint so that you're searching for the first (and only) transaction in your database where the:
Checkout Session ID = Request Data's object id
This will ensure you're updating the 'transaction' that was created for the Checkout Session whose completion triggered the backend workflow.
You can get the Payment Intent ID using the 'Stripe Connect - Retrieve Checkout Session Details' call that comes with the plugin.
Save down the total tax associated with a transaction
You can also get the Total Tax by using the 'Stripe Connect - Retrieve Checkout Session Details' call. However, it is strongly recommended to do this in a separate backend workflow that you then trigger from the first (that we used to get the Payment Intent ID).
This approach is recommended as you'll need to get a few difference pieces of information and putting everything into separate backend workflows helps ensure all the data is available before the next action is triggered.
Create a new backend workflow called 'get_tax_component' (or similar) and pass through the checkout_session_id as a key:
You can search for the correct transaction to update by using the 'checkout session id':
Save down the total tax to your 'transaction' data type using the 'Stripe Connect - Retrieve Checkout Session Details' call. Use the total_details amount_tax value:
Go back to your first backend workflow and trigger the get_tax_amount backend workflow as the last step. Make sure to pass through the Checkout Session ID as a parameter:
Save down the Charge ID associated with a transaction
Create another backend workflow (call this one something like 'get_charge_id') and add a key called 'payment_intent_id':
You can search for the correct transaction entry to update using the 'payment_intent_id':
Save down the Charge ID to your 'transaction' data type using the 'Stripe Connect - Retrieve Payment Details' call. Use the latest_charge value to get the Charge ID:
Go back to your 'get_tax_component' backend workflow and trigger the get_charge_id backend workflow as the last step in it:
Save down the Transfer ID associated with a transaction
When you create a Destination charge with Stripe you automatically make a transfer from the platform account to the connected account. You'll need to get the ID associated with this transfer event as we'll be partially reversing this transfer to transfer the tax component back to the platform account.
Create another backend workflow called 'get_transfer_id' and add a key called 'charge_id':
You can use the Charge ID to search for the relevant transaction to update:
Save down the Transfer ID to your 'transaction' data type using the 'Stripe Connect - Retrieve Charge' call. Use the transfer value to get the Transfer ID:
Go back to your 'get_charge_id' backend workflow and trigger the 'get_transfer_id' backend workflow as the last step in it:
Transfer the tax component of the transaction to the platform account
You now have all the necessary info to trigger the transfer reversal.
Create another backend workflow called 'reverse_transfer'. This one will be used to transfer the tax to the platform account using the 'Stripe Connect - Reverse a Transfer' action. Add two 'keys' to this backend workflow:
amount: this will represent the value of the tax to be transferred to the platform account
transfer_id: this will represent the Transfer ID
Add the 'Stripe Connect - Reverse a Transfer' action to the backend workflow:
Go back to your 'get_transfer_id' backend workflow and trigger the reverse_transfer backend workflow as the last step in it:
That's it! Now when you process a transaction where tax is collected with Stripe Tax, the tax should be automatically transferred back to your platform account. For example, in the below Checkout Session:
The product sold cost €100
The platform fee was 20% (€20)
The VAT (sales tax) charged was €18.70
After the payment has been made, the platform collects €20 as a platform fee (see the Transactions -> Collected fees section of the Stripe dashboard):
The €18.70 in tax is transferred back to the platform account as transfer reversal: