Laravel Cashier: Multiple Stripe accounts based on Billable's property
Tags: laravel, cashier
Published: 2021-08-06 12:59:42

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](https://laravel.com/docs/8.x/billing#introduction). 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
<?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);
    }
}
```

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 `use`d. 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:

```php
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'),
        ]
    ],
];
```

Modify your `.env` key and add:
```
# Bulgaria Cashier Setup
BG_STRIPE_KEY=
BG_STRIPE_SECRET=
BG_CASHIER_CURRENCY=
```

```
# Poland Cashier Setup
PL_STRIPE_KEY=
PL_STRIPE_SECRET=
PL_CASHIER_CURRENCY=
```

Lastly, update the method in your `MyBillable` trait to:

```php
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);
}
```

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](https://stripe.com/docs/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~~

Check out the comments below to see a way of handling webhooks.