DEV Community

Ivanka Todorova
Ivanka Todorova

Posted on • Updated on

Laravel Cashier: Multiple Stripe accounts based on Billable's property

If your application bills customers internationally, sometimes you need multiple Stripe Accounts for all your companies.

Laravel Cashier doesn't support charging customers from different Stripe accounts out-of-the box, but achieving this is pretty easy.

I will not go through the whole setup of Cashier for a single Stripe account, because Laravel's documentation is fantastic: thorough and easy to follow: Laravel Cashier. The account you setup here, will be the fallback/default account if the Billable model (usually App\Models\User) can't be used to resolve the correct Stripe account.

After you're done setting Cashier up, create a new trait called MyBillable. I tend to keep my traits in a folder inside where they are used. Meaning MyBillable trait will go inside traits folder located in app/models.

After creating the App\Models\Traits\MyBillable, add this as content:

<?php
namespace App\Models\Traits;


use Laravel\Cashier\Billable;
use Laravel\Cashier\Cashier;

trait MyBillable
{
    use Billable;


    /**
     *  Override stripe configuration based on User's country preference
     *
     * @param  array  $options
     * @return \Stripe\StripeClient
     */
    public function stripe(array $options = [])
    {

        return Cashier::stripe($options);
    }
}
Enter fullscreen mode Exit fullscreen mode

The code above does nothing for now, but we will expand the App\Models\Traits\MyBillable::stripe() method later.

If you have followed the setup instructions from the official documentation, your billable model (usually App\Models\User) has the Laravel\Cashier\Cashier\Billable trait used. Go ahead and replace it with our new one MyBillable (which also leverages all provided functionality in Cashier by use-ing it inside).

Verify your application is working properly, as if we haven't made any changes after the Cashier setup.

Inside your App\Models\Traits\MyBillable::stripe() method you can use $this to access your User model and write your own logic to determine which of your Stripe accounts is correct for that customer.

In my case, my users belongsTo countries and each country has country code which I use to get previously set .env variables with my stripe secret, stripe key and currency for Cashier.

To do so, create a new config file billing.php inside config/ folder:

return [
    'stripe' => [
        'bg' => [
            'key' => env('BG_STRIPE_KEY'),
            'secret' => env('BG_STRIPE_SECRET'),
            'currency' => env('BG_CASHIER_CURRENCY'),
        ],
        'pl' => [
            'key' => env('PL_STRIPE_KEY'),
            'secret' => env('PL_STRIPE_SECRET'),
            'currency' => env('PL_CASHIER_CURRENCY'),
        ]
    ],
];
Enter fullscreen mode Exit fullscreen mode

Modify your .env key and add:

# Bulgaria Cashier Setup
BG_STRIPE_KEY=
BG_STRIPE_SECRET=
BG_CASHIER_CURRENCY=
Enter fullscreen mode Exit fullscreen mode
# Poland Cashier Setup
PL_STRIPE_KEY=
PL_STRIPE_SECRET=
PL_CASHIER_CURRENCY=
Enter fullscreen mode Exit fullscreen mode

Lastly, update the method in your MyBillable trait to:

public function stripe(array $options = [])
{
    if (!is_null($this->country)) {
        // Get country specific cashier key
        $config = config('billing.stripe');
        if (array_key_exists($this->country->code, $config)) {
            // Update cashier's config
            config(['cashier.key' => $config[$this->country->code]['key']]);
            config(['cashier.secret' => $config[$this->country->code]['secret']]);
            config(['cashier.currency' => $config[$this->country->code]['currency']]);
        }
    }
    // use default config
    return Cashier::stripe($options);
}
Enter fullscreen mode Exit fullscreen mode

The method above is called every time Cashier needs an instance of StripeClient (provided by Cashier's dependency: stripe-php), so by altering Cashier's config we are getting an instance of the StripeClient for the specified Stripe account.

That's it! You are now creating customers in the appropriate Stripe account based on your logic.

What's next? Cashier also provides webhooks to tell your application about changes made outside of it (related to your customers, subscriptions, payments, etc).

In my next post I will explain how to create different endpoints in your application to handle the calls issued by your multiple Stripe accounts.

Discussion (2)

Collapse
maneeshmk profile image
Maneesh MK

Minor correction. It should be "stripeOptions" instead of "stripe"

public function stripeOptions(array $options = [])
{
if (!is_null($this->country)) {
// Get country specific cashier key
$config = config('billing.stripe');
if (array_key_exists($this->country->code, $config)) {
// Update cashier's config
config(['cashier.key' => $config[$this->country->code]['key']]);
config(['cashier.secret' => $config[$this->country->code]['secret']]);
config(['cashier.currency' => $config[$this->country->code]['currency']]);
}
}
// use default config
return Cashier::stripeOptions($options);
}

Collapse
fakeheal profile image
Ivanka Todorova Author • Edited on

Thank you for your comment!

Laravel's Cashier latest version (as of writing of this comment) is 13 and I am setting config() variables before calling the following method: Cashier::stripe().