phpstripe-paymentsstripe-tax

How to retain taxes collected in Platform Account - Stripe Connect


I am using Stripe Connect for my platform. My platform is responsible to ensure the appropriate amount of tax is charged, collected and paid out to the relevant tax authority. My problem is Stripe calculates the tax correctly, charges it to the customer correctly…but instead of transferring the collected tax to the Platform Account with the Application Fee, it transfers the collected tax to the Connected Account.

Here is my code to set up a Checkout Session

require APPPATH .'third_party/stripe-php/init.php'; // Include the Stripe PHP bindings library
        \Stripe\Stripe::setApiKey($this->CI->config->item('stripe_api_key')); // Set API key
        $reg_id = $this->input->post('reg_id'); 
        $stripe_price_id = $this->input->post('stripe_price_id');           //this gets connected account number 'inst' is creator id value hidden in button
        $stripeAccount = $this->Profiles_model->fetch_stripe_account_by_id($reg_id);
        $email = $this->session->userdata('email');
        $stripeCustomerID = $this->Profiles_model->fetch_stripe_customerID($email);
                
        $session = \Stripe\Checkout\Session::create([
            'customer' => $stripeCustomerID,
            'customer_update' => [
            'address' => 'auto',
            ],
            'payment_method_types' => ['card'],
            'mode' => 'subscription',
            'metadata' => ['creator_id' => $reg_id],  
            "line_items" => [
                ['price' => $stripe_price_id,
                'quantity' => 1,
                ],
            ],
             'automatic_tax' => [
                        'enabled' => true,
                ],
            'subscription_data' => [
    //      'application_fee_percent' => 25,
            'transfer_data' => [
                'destination' => $stripeAccount, 
                'amount_percent' => 75,
                ],
                ],
          'success_url' => 'https://example.com/purchasesuccess',
          'cancel_url' => 'https://example.com/privatemember',
        ]);

Stripe suggests I just increase my Application Fee to cover the tax amount, but how do I do that when the amount of tax charged varies based on customer location? I thought maybe I could get around it using something like:

'application_fee_amount' => ($fee+'line_items.data.amount_total'-'line_items.data.amount_subtotal'),

OR

'application_fee_amount' => ($fee+'amount_total'-'amount_subtotal'),

OR using

'amount_percent' => 75,

The Docs say the "amount_percent" is based on the Sub-Total, but it transfers 75% of the total (ie base price + tax).

Ideas?


Solution

  • So I was working with Stripe on this, and here is what they wrote:

    I understand your point that tax amount should be left to the platform, while the rest is transferred to the connected account, however at its core, that is not how the Billing and Connect product operate.

    When you create a subscription, the subscription object will generate invoices, which will generate payment_intents :

    Subscription Invoice - Payment_intent

    Invoice -Payment_intent

    The payment_intent contains an array of properties, which include the amount, the currency, the customer if there is one, etc. However, it has no notion of products, discounts, or taxes, as these are properties of the subscription and invoice objects.

    Connect charges (i.e. Direct, Destination and Separate charges and Transfers) are processed at payment_intent level, not subscription / invoice level. They too do not have a notion of products, discounts and taxes. When you set up a Connect process from the Checkout session

    • in your case, with the subscription_data.transfer_data attributes, the amount_percent cannot relate to that of the subtotal, as this subtotal amount does not exist at payment_intent level.

    And here is their suggested solution. I was able to implement this without too much trouble, so it works.

    -Create a Checkout session without any Connect attribute. There is a transfer_group parameter that can be set for Checkout sessions, but it isn't available for subscriptions. Nevertheless, omitting it doesn't prevent you from handling SCT later on.

    -Save the charge ID ch_xxx from your invoice's succeeded payment. You can receive this information from the charge.succeeded event or payment_intent.succeeded event. You may also want to listen for invoice.payment_succeeded or invoice.paid events to get the subtotal amount.

    -Create a transfer, with the connected account's acct_id as destination, the invoice's subtotal as amount, and the charge's ch_id as source_transaction : https://stripe.com/docs/connect/charges-transfers#transfer-availability The source_transaction parameter is crucial here - it will link the transfer to the charge, which will ensure funds are transferred even if they aren't available to your balance yet, and will create the missing transfer_group automatically.