WooCommerce: Multiple Stripe Accounts (Solved)

The WooCommerce plugin fully integrates with the WooCommerce Stripe Payment Gateway plugin, developed by Automattic itself. With this free plugin, Stripe payment gateway can be enabled via the WooCommerce settings and once your Stripe “Live Publishable Key” and “Live Secret Key” are set, your WooCommerce shop is ready to take credit card payments powered by Stripe.

Now, there is some documentation online which explains, with a little bit of code, how to switch Stripe account programmatically and conditionally i.e. for a given product ID or product category slug – same as what we’ve seen recently with PayPal Standard (here’s the tutorial for using different PayPal accounts inside a single WooCommerce installation). For example, you may want to use a Stripe account for digital sales and a different one for physical products.

Unlike PayPal Standard, however, online documentation and snippets are quite out of date and require, often, to create a custom Class which is always a difficult task in PHP programming. Thankfully, there are new WooCommerce Stripe hooks and therefore it’s possible to use different / multiple Stripe accounts in a single WooCommerce installation.

Please read the disclaimer below and – only then – enjoy!

My goal is to use my Stripe keys for all payments apart from a given product ID which will need to deposit funds into a different Stripe account.

PHP Snippet: Use Different Stripe Account For a Product ID @ WooCommerce Checkout

Disclaimer: the snippet below MAY CAUSE side effects – use at your own risk. For example, it can mess with Stripe refund handling (better if you manually create refunds from Stripe as opposed to using WooCommerce order admin) or generate other unknown errors. Customizing payment gateways is very dangerous and should be done only if you are aware of the potential consequences. Please test this thoroughly.
Please note: the snippet below looks for a Product ID inside the order and switches Stripe keys if successful. In case the order contains several products you’d need to find a workaround, for example by allowing only 1 product in the Cart.
/**
 * @snippet       Switch Stripe Account @ WooCommerce Checkout
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli, BusinessBloomer.com
 * @testedwith    WooCommerce 4.6
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */

// -------------------
// 1. Create function to find Product ID

function bbloomer_product_id_in_cart( $id ) {
	$product_cart_id = WC()->cart->generate_cart_id( $id );
	$in_cart = WC()->cart->find_product_in_cart( $product_cart_id );
	if ( $in_cart ) return true;
	return false;
}

// -------------------
// 2. Change Stripe keys on the go

add_filter( 'wc_stripe_params', 'bbloomer_conditional_publishable_key', 9999 );

function bbloomer_conditional_publishable_key( $params ) {

	// PRODUCT ID HERE
	if ( ! bbloomer_product_id_in_cart( 12345 ) ) return $params;

	// STRIPE Live Publishable Key HERE
	$params[ 'key' ] = 'pk_live_................';

	return $params;
}

add_filter( 'wc_stripe_payment_request_params', 'bbloomer_conditional_publishable_key_request', 9999 );

function bbloomer_conditional_publishable_key_request( $params ) {

	// PRODUCT ID HERE
	if ( ! bbloomer_product_id_in_cart( 12345 ) ) return $params;

	// STRIPE Live Publishable Key HERE
	$params[ 'stripe' ][ 'key' ] = 'pk_live_................';

	return $params;
}

add_filter( 'woocommerce_stripe_request_headers', 'bbloomer_conditional_private_key_headers', 9999 );

function bbloomer_conditional_private_key_headers( $headers_args ) {

	// PRODUCT ID HERE
	if ( ! bbloomer_product_id_in_cart( 12345 ) ) return $headers_args;

	// STRIPE Live Secret Key HERE
	$headers_args[ 'Authorization' ] = 'Basic ' . base64_encode( 'sk_live_..........' . ':' );

	return $headers_args;
}

Where to add this snippet?

You can place PHP snippets at the bottom of your child theme functions.php file (delete "?>" if you have it there). CSS, on the other hand, goes in your child theme style.css file. Make sure you know what you are doing when editing such files - if you need more guidance, please take a look at my free video tutorial "Where to Place WooCommerce Customization?"

Does this snippet (still) work?

Please let me know in the comments if everything worked as expected. I would be happy to revise the snippet if you report otherwise (please provide screenshots). I have tested this code with Storefront theme, the WooCommerce version listed above and a WordPress-friendly hosting on PHP 7.3.

If you think this code saved you time & money, feel free to join 14,000+ WooCommerce Weekly subscribers for blog post updates or 250+ Business Bloomer supporters for 365 days of WooCommerce benefits. Thank you in advance :)

Need Help with WooCommerce?

Check out these free video tutorials. You can learn how to customize WooCommerce without unnecessary plugins, how to properly configure the WooCommerce plugin settings and even how to master WooCommerce troubleshooting in case of a bug!

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza.

27 thoughts on “WooCommerce: Multiple Stripe Accounts (Solved)

  1. Hi,
    I used this snipped to send paiment to different accounts according to the country the products in the cart are related to.
    It worked great with standard payment method but I had to add “woocommerce gateway stripe” module to add Google Pay as payment method, and it doesn’t work anymore with this payment. The functions are just not called when Google Pay is used. But it still work with the other payment methods.
    Maybe just adding another filter would work, but I don’t know witch one…any ideas?

    Thanks

    1. Can’t really help without looking at your code – can you post it here or send it on to my email please?

  2. Hi there – is there a way to add another product ID? E.g.

    // -------------------
    // 2. Change Stripe keys on the go
     
    add_filter( 'wc_stripe_params', 'bbloomer_conditional_publishable_key', 9999 );
     
    function bbloomer_conditional_publishable_key( $params ) {
     
       // PRODUCT ID HERE
       if ( ! bbloomer_product_id_in_cart( 10241, 10242 ) ) return $params;
     
       // STRIPE Live Publishable Key HERE
       $params[ 'key' ] = 'pk_test_51J0WfbF5J9vPfugSzUg1gSJYYeGpW08Q1tOkUjMcsZ3zEyXw1eSLqOT72dhYHiu5Gr3c2zA8BQcQQxE4zNMmDCPO00blAgAaVp';
     
       return $params;
    }
     
    add_filter( 'wc_stripe_payment_request_params', 'bbloomer_conditional_publishable_key_request', 9999 );
     
    function bbloomer_conditional_publishable_key_request( $params ) {
     
       // PRODUCT ID HERE
       if ( ! bbloomer_product_id_in_cart( 10241, 10242 ) ) return $params;
     
       // STRIPE Live Publishable Key HERE
       $params[ 'stripe' ][ 'key' ] = 'pk_test_51J0WfbF5J9vPfugSzUg1gSJYYeGpW08Q1tOkUjMcsZ3zEyXw1eSLqOT72dhYHiu5Gr3c2zA8BQcQQxE4zNMmDCPO00blAgAaVp';
     
       return $params;
    }
     
    add_filter( 'woocommerce_stripe_request_headers', 'bbloomer_conditional_private_key_headers', 9999 );
     
    function bbloomer_conditional_private_key_headers( $headers_args ) {
     
       // PRODUCT ID HERE
       if ( ! bbloomer_product_id_in_cart( 10241, 10242 ) ) return $headers_args;
     
       // STRIPE Live Secret Key HERE
       $headers_args[ 'Authorization' ] = 'Basic ' . base64_encode( 'sk_test_51J0WfbF5J9vPfugS565HQlYeowCa3Rf5K5C0yLeqiKBhFNzrTkH0jQQkMx9dxjlspAE0FBECh8Q3rCeAhybKUfGZ00UnTyhYvN' . ':' );
     
       return $headers_args;
    }
    1. To follow on from this – could an Array be used to store multiple product ID’s and then the function looks for one of the ID’s and continues on?

      Hope that makes sense as I am a php noob

      thanks!

      1. Hi Kev, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  3. Note to others: This of course works exactly the same with TEST keys.

    For OP:

    First of all, THANK YOU !

    I made two business accounts in my Stripe account, each giving me uniques publishable and secret keys. Made one default and the other one I squeezed in for one product’s ID as the code intends and for a single purchase it works perfectly.

    Though I’m not sure I understand it correctly, the problem I stumbled upon is the following (note I’m testing it out in Test Mode).

    Let’s call a product using a default API keys DP (and DP1, DP2,… if need be) and the one using swapped API keys SP.

    If a new customer adds DP to cart, proceeds to checkout, payment goes through OK. Going back to the store and trying to redo everything the same again (ie purchasing DP or any other DPX) outputs error notification: `Sorry, we are unable to process your payment at this time.` If instead (or afterwards) we go back to the store and try to add SP instead of DP the error outputted is `No such source: ‘src_1IvSJ6HobZQAt8z5fZe2Lphl’`.

    Exactly the same scenario occurs if we swap SP and DP roles. So if a NEW customer purchases SP first it goes through fine. Changing to DP after purchase yields the same Source Error.

    At least in Test Mode (WP and Stripe.com) it often (and normally according to Stripe Support) duplicates the customer within a business account. If I try deleting both (of the same) customer(s) and retry payment, a customer is recreated in Stripe account, but WP front-end yields a new error `Sorry, we are unable to process your payment at this time. Please retry later.`

    Stripe allows you to have two customers with the same email in your business account, implying each of them has their own unique identifier. I think it naturally follows that same rules apply, if you have two customers with the same email address in different business accounts.

    So my question is: “Should there be more to this snippet to fetch and use customer source (UUID) and has anybody experienced similar issues and knows how to fix them?”

    Thanks in advance.

    1. Thanks for your feedback, I don’t think I’m able to reply to your questions though – customizing payment gateways is always a delicate operation

  4. I’m trying to use this snippet with a variable product, but it’s not working. I tried using the “master” ID for the product, and also de product IDs for the individual variations. Is there anything I should adjust to make this work with a variable product? Thanks!

    1. Hi Kavier, apparently the bbloomer_product_id_in_cart() function only works for simple products. Try this snippet alternative instead: https://www.businessbloomer.com/woocommerce-easily-check-product-id-cart/

  5. HI, first of all, thanks for your snippet.
    I try to adapt the snippet to look for a product tag in cart and not product ID.
    But can not complete the order, I get the notice error :

    No such source: 'src_xxx'
    

    and stripe error :

    {
      "error": {
        "code": "resource_missing",
        "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
        "message": "No such source: 'src_xxx'",
        "param": "",
        "type": "invalid_request_error"
      }
    

    I could not fix it with the explanations of @Roel Broersma as I need code example (sorry for my coding level).

    Maybe I missed something, here is my code :

    add_filter( 'wc_stripe_params', 'conditional_publishable_key', 9999 );
     
    function conditional_publishable_key( $params ) {
    
       // set our flag to be false until we find a product in that tag
       $tag_check = false;
               
       // check each cart item for our category
       foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {      
             // If Cart has tag "formation-diplomante", set $tag_check to true
              if ( has_term( 'formation-diplomante', 'product_tag', $cart_item['product_id'] ) ) {
                  $tag_check = true;
                  break;
              }
       }
    
       if ( $tag_check ) {
          // STRIPE Live Publishable Key HERE
          $params[ 'key' ] = 'pk_test_';
       }
     
       return $params;
    }
     
    add_filter( 'wc_stripe_payment_request_params', 'conditional_publishable_key_request', 9999 );
     
    function conditional_publishable_key_request( $params ) {
    
       // set our flag to be false until we find a product in that tag
       $tag_check = false;
               
       // check each cart item for our category
       foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {      
             // If Cart has tag "formation-diplomante", set $tag_check to true
              if ( has_term( 'formation-diplomante', 'product_tag', $cart_item['product_id'] ) ) {
                  $tag_check = true;
                  break;
              }
       }
    
       if ( $tag_check ) {
          // STRIPE Live Publishable Key HERE
          $params[ 'stripe' ][ 'key' ] = 'pk_test_';
       }
     
       return $params;
    }
     
    add_filter( 'woocommerce_stripe_request_headers', 'conditional_private_key_headers', 9999 );
     
    function conditional_private_key_headers( $headers_args ) {
    
       // set our flag to be false until we find a product in that tag
       $tag_check = false;
               
       // check each cart item for our category
       foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {      
             // If Cart has tag "formation-diplomante", set $tag_check to true
              if ( has_term( 'formation-diplomante', 'product_tag', $cart_item['product_id'] ) ) {
                  $tag_check = true;
                  break;
              }
       }
    
       if ( $tag_check ) {
          // STRIPE Live Secret Key HERE
          $headers_args[ 'Authorization' ] = 'Basic ' . base64_encode( 'sk_test_' . ':' );
       }
     
       return $headers_args;
    }
    
    1. Hi David, thanks so much for your comment! Yes, this is definitely fixable, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  6. Hi,

    thanks for the information. I am working on kinda the same problem – but instead of different accounts based on products in the cart, we use different accounts based on the shipping country.
    Sadly this makes it way more complex, since STRIPE precalculates CDATA on the page rendering. On the checkout page, when you change the country, this leads to a problem that the sources are not correctly registered at the different STRIPE endpoints leading to an error. So far all my efforts to manipulate the data during page runtime through js were useless, since the STRIPE js doesn’t take new data upon the “purchase” button press, but instantiates upon page load.
    I’m currently in contact with the STRIPE support team to figure out if there is a better way to achieve a correct behaviour, but I think I have to split up the billing/shipping information page and the payment page in order to have the correct pubkeys on pageload.

    All the best, J

      1. Hello @J and @rodolfo,
        I have faced the same issue on the checkout page, where I want to switch stripe account data on country change.
        But, it’s not changing on country change. it is changing on page reload. Can you please help me to do this point.?
        @J have you get any response from Stripe for the WooCommerce plugin?

        Thank you for reading my question.

        1. HI @rodolfo,
          Kindly look into my query. it is urgent for me. Also, if you have any alternative way then please let me know.

          Waiting for your response.

          Thank you,
          //Sagar

          1. Hi all,

            I’m facing a similar issue. I need to change the Stripe keys depending on a checkout custom field. If you can guide me with something I would appreciate it.

            Also, thanks for all the snippets and solutions you post, they are very helpful in so many cases.

            Thank you,
            Byron

        2. You could force a reload on country change?

  7. Hi Rodolfo,

    Thanks for writing this.
    Last year I made a plugin (named: ‘Stripe Supporter’) which will get the vendor ID of the product which is in the Cart (only 1 item in the cart is supported). Then it looks up the Stripe Keys for that Vendor (I extended the Vendor Edit form so vendors can edit their own Stripe Keys in here)

    It will then use the Vendor’s Stripe keys to do the Checkout.
    This way many people can built real open-source sharing platforms of I think is the future ๐Ÿ™‚ Money is not flowing through the platform anymore but directly from customer to vendor.

    However, while testing my plugin I noticed that when the payment is done and the customer is redirected to Woocommerce (return URL), Woocommerce sends some requests to Stripe with it’s master-Stripe account. Stripe then responds with 400-errors and

    {
      "error": {
        "code": "resource_missing",
        "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
        "message": "No such token: 'src_xxxxxxxxxxxxxxxxxxxxxxxxx",
        "param": "source",
        "type": "invalid_request_error"
      }
    

    which is normal because the payment is made under a Vendor’s Stripe account and the Master Stripe account is not aware of this.

    Note: I already fixed the issue that on the return URL, there is no IN_CART object anymore, so you have to look at the ORDER-ID in the return url, i.e.: https://www.xxxxxxx.com/checkout/order-received/22045/?client_secret=src_client_secret_xxxxxxx&key=wc_order_xxxx… (in this case 22045) and then lookup the product vendor for this order.

    Have you also experienced some problems when using 2 Stripe accounts?

    PS. I will freely donate my plugin as open-source to the community once it’s v1.0 ๐Ÿ™‚

    1. I have fixed the issue. The problem was that Stripe notices the woocommerce webhook and then there is no order object or in_cart object. So it need to look at the json content that Stripe request/posts to the webhook. Sometimes there is not even an ->metadata->orderid so you can use the source_id and look that up in the order table.

      1. Good to know!

        1. If you have the code to fix the bug, feel free to share it here!

  8. Hey this does work anymore.

    Stripe requires you to pass the account number within the headers and Stripe js object initialization. As well as setting up a Connected accounts/Account platform.

    1. I find this strange, it’s a snippet I coded quite recently. Maybe your theme (or another plugin) is messing/conflicting with my snippet.

      To troubleshoot, disable all plugins but WooCommerce and also switch temporarily to “Twentytwenty” theme (load the snippet there in functions.php) as explained here: https://www.businessbloomer.com/lesson/trwm4l01/

      Once you do that, does it work? If yes, you have a problem with your current theme or one of the plugins.

      Hope this helps!

  9. The multiple Stripe accounts functionality comes so close to being what I need for an organization I work with. However, they would like multiple Stripe accounts to be included in a SINGLE form. This would allow donors to give to various causes within a single form, with the funds for each cause they donate to going to their respective Stripe accounts. Any chance this is a possibility with GiveWP?

    1. Not sure, did you ask GiveWP?

  10. Hey,
    Your content is rich, thank you, how if there are more than 1 product in cart?

    Thank you

    1. Good question, I recommend you force the cart to max one item: https://www.businessbloomer.com/woocommerce-allow-1-product-cart/

Questions? Feedback? Support? Leave your Comment Now!
_____

If you are writing code, please wrap it between shortcodes: [php]code_here[/php]. Failure to complying with this (as well as going off topic, not writing in English, etc.) will result in comment deletion. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining BloomerArmada to get blog comment reply priority, ask me 1-to-1 WooCommerce questions and enjoy many more perks. Thank you :)

Your email address will not be published.