# Stripe/PayPal secrets

> Set up your PayPal/Stripe keys.

Create a Stripe and/or PayPal account and read the [Stripe](https://docs.stripe.com/keys) and [PayPal](https://developer.paypal.com/api/rest/#link-getclientidandclientsecret) documentation on how to get the keys.

Each provider gives you two sets of keys, one for testing and one for real payments. Merx knows both under their own option names and picks between them with the [`production`](https://merx2.wagnerwagner.de/reference/options/config-options/production.md) option, so a server only ever needs the set it actually uses — see [Testing and production](https://merx2.wagnerwagner.de/guide/configuration/testing-and-production.md).

## Stripe keys

- [`stripe.test.publishable_key`](https://merx2.wagnerwagner.de/reference/options/config-options/stripe-test-publishable-key.md) and [`stripe.live.publishable_key`](https://merx2.wagnerwagner.de/reference/options/config-options/stripe-live-publishable-key.md) identify your account in the browser. They aren’t secret — the publishable key goes into your checkout template, see [Stripe Elements](https://merx2.wagnerwagner.de/guide/payment-gateways/stripe-elements.md).
- [`stripe.test.secret_key`](https://merx2.wagnerwagner.de/reference/options/config-options/stripe-test-secret-key.md) and [`stripe.live.secret_key`](https://merx2.wagnerwagner.de/reference/options/config-options/stripe-live-secret-key.md) are what actually charge money. Server only.
- [`stripe.webhook_signing_secret`](https://merx2.wagnerwagner.de/reference/options/config-options/stripe-webhook-signing-secret.md) verifies that a webhook really came from Stripe. There’s only one, so it holds the test secret while you’re testing and the live one afterwards. See [Stripe webhooks](https://merx2.wagnerwagner.de/guide/configuration/stripe-webhooks.md).

## PayPal keys

- [`paypal.sandbox.clientID`](https://merx2.wagnerwagner.de/reference/options/config-options/paypal-sandbox-client-id.md) and [`paypal.live.clientID`](https://merx2.wagnerwagner.de/reference/options/config-options/paypal-live-client-id.md) identify your PayPal app.
- [`paypal.sandbox.secret`](https://merx2.wagnerwagner.de/reference/options/config-options/paypal-sandbox-secret.md) and [`paypal.live.secret`](https://merx2.wagnerwagner.de/reference/options/config-options/paypal-live-secret.md) go with them. Server only.

## Where to put them

Kirby reads three config files, each overriding the one before it:

```
/site/config/config.php  →  config.[your-domain].php  →  env.php
```

`env.php` wins over both others and is meant for exactly this. Keep it out of your repository, put it on each server by hand, and give every environment its own.

```php title="/site/config/env.php — development machine or test server"
<?php

return [
  'wagnerwagner.merx.stripe.test.publishable_key' => 'pk_test_xxx…',
  'wagnerwagner.merx.stripe.test.secret_key' => 'sk_test_xxx…',
  'wagnerwagner.merx.stripe.webhook_signing_secret' => 'whsec_xxx…',
  'wagnerwagner.merx.paypal.sandbox.clientID' => 'xxx…',
  'wagnerwagner.merx.paypal.sandbox.secret' => 'xxx…',
];
```

```php title="/site/config/env.php — live server"
<?php

return [
  'wagnerwagner.merx.production' => true,
  'wagnerwagner.merx.license' => 'MERX2-XXXXXXX-XXXXXXX',
  'wagnerwagner.merx.stripe.live.publishable_key' => 'pk_live_xxx…',
  'wagnerwagner.merx.stripe.live.secret_key' => 'sk_live_xxx…',
  'wagnerwagner.merx.stripe.webhook_signing_secret' => 'whsec_xxx…',
  'wagnerwagner.merx.paypal.live.clientID' => 'xxx…',
  'wagnerwagner.merx.paypal.live.secret' => 'xxx…',
];
```

[`production`](https://merx2.wagnerwagner.de/reference/options/config-options/production.md) belongs in the same file, because a live server with live keys but without it reads the *test* keys — which are not there — and every payment fails. Keeping it here rather than in `config.php` is also what stops your development machine from charging real cards.

The signing secret appears in both, with a different value: there is one option for it, and the webhook you create in Stripe’s test mode has a different secret from the live one.

```gitignore title="/.gitignore"
/site/config/env.php
```

> [!CAUTION]
> Anyone who has your live secret key can charge cards and issue refunds on your account. Never commit it, never send it through a chat or a ticket, and if it does end up somewhere it should not, roll it in the provider’s dashboard rather than hoping nobody noticed.

[Kirby docs: multi-environment setup](https://getkirby.com/docs/guide/configuration#multi-environment-setup__deployment-configuration)

Next, learn how to use these keys to create [Stripe](https://merx2.wagnerwagner.de/guide/payment-gateways/stripe-elements.md) or [PayPal](https://merx2.wagnerwagner.de/guide/payment-gateways/paypal.md) payments.
