# Multiple accounts

The `Paymongo` facade uses the account whose secret key is in `PAYMONGO_SECRET_KEY`. When one app takes payments for several PayMongo accounts, such as a marketplace where each merchant has their own, call `Paymongo::withSecretKey()` for a copy that uses another account's key:

```php
use Luigel\Paymongo\Facades\Paymongo;

$merchantSecretKey = 'sk_test_merchant_account'; // e.g. decrypt($merchant->paymongo_secret_key)

$paymongo = Paymongo::withSecretKey($merchantSecretKey);

$intent = $paymongo->paymentIntents()->create([
    'amount' => 150050,
    'currency' => 'PHP',
    'payment_method_allowed' => ['card', 'gcash'],
]);

// Paymongo::paymentIntents() still uses PAYMONGO_SECRET_KEY.
```

- `withSecretKey()` returns a new, separate `PaymongoManager` with every service, `paymentIntents()` through `payouts()`. Pass that account's public key as the optional `publicKey:` argument if you use `retrieveUsingClientKey()`; without it, the copy has no public key. The timeout, retries and idempotency settings still come from your config.
- The facade itself is unchanged, so one merchant's key never leaks into a request made for another. Keep the copy in a variable for as long as you work with that account.
- Store each merchant's secret key encrypted, for example with Laravel's `encrypted` cast.
- `Paymongo::fake()` fakes the copies too, and `Paymongo::assertSent()` sees their requests. Check which account a request was made for with its `Authorization` header, which is HTTP Basic auth with the secret key as the username.

## Webhooks for several accounts

Each account registers its own webhook endpoints, and each endpoint has its own secret. Register them with the copy for that account, for example `Paymongo::withSecretKey($key)->webhooks()->create(...)`, then give each endpoint a route with its own named secret. See [More than one endpoint](/webhooks.md#more-than-one-endpoint).

A named secret lives in `config/paymongo.php`, so this suits a handful of accounts known up front. For accounts that come and go, register a route of your own that finds the account from the URL, and check each delivery against that account's secret with `Luigel\Paymongo\Webhooks\SignatureVerifier`:

```php
use App\Models\Merchant;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Luigel\Paymongo\Events\WebhookReceived;
use Luigel\Paymongo\Exceptions\InvalidWebhookSignatureException;
use Luigel\Paymongo\Webhooks\SignatureVerifier;
use Luigel\Paymongo\Webhooks\WebhookEvent;

// routes/api.php: register each merchant's endpoint as https://example.com/webhooks/paymongo/{merchant id}
Route::post('webhooks/paymongo/{merchant}', function (Request $request, Merchant $merchant) {
    try {
        (new SignatureVerifier(tolerance: 300))->verify(
            $request->getContent(),
            $request->header('Paymongo-Signature'),
            $merchant->paymongo_webhook_secret,
            livemode: (bool) config('paymongo.livemode'),
        );
    } catch (InvalidWebhookSignatureException) {
        abort(401);
    }

    event(new WebhookReceived(WebhookEvent::fromArray($request->all())));

    return response()->json(['received' => true]);
});
```

`verify()` throws an `InvalidWebhookSignatureException` for a delivery that fails the checks described under [Signature verification](/webhooks.md#signature-verification). Dispatching `WebhookReceived` hands the event to the same listeners as `Route::paymongoWebhooks()`. This route does not drop repeat deliveries, so make those listeners idempotent.
