Card deposits with Stripe
The app takes Stripe card deposits through Stripe's own payment sheet. It needs one publishable key in app_config.json that pairs with your server's secret key, and your server's gateway list decides whether Stripe is offered at all. Setup, going live, what customers see, and the server's refusals.
stripePublishableKey is the only payment key in app_config.json, and one
screen uses it: the fiat deposit screen, when the customer chooses Stripe.
The customer pays by card in Stripe's own payment sheet inside the app, and your
server credits their fiat wallet once it has read the payment back from Stripe.
Everything else about deposits — which currencies, which gateways, which fees — is set on your server, and the app shows what the server offers.
Two keys from one Stripe account
| Key | Where it goes | Looks like |
|---|---|---|
| Publishable key | stripePublishableKey in app_config.json |
pk_test_… or pk_live_… |
| Secret key | APP_STRIPE_SECRET_KEY in your server's .env |
sk_test_… or sk_live_… |
They must come from the same Stripe account and the same mode. Your
server creates each payment with its secret key, and the app completes it with
the publishable key, so a key from another account, or a test key paired with a
live one, cannot complete a payment. Stripe has no separate sandbox switch: the
_test_ or _live_ in the key decides whether real cards are charged.
Your server's APP_STRIPE_PUBLIC_KEY is for your website's checkout. The app
does not fetch it; its publishable key is packed into the build. Use the same
pk_… value in both places.
The secret key never goes into the app. Anyone can read app_config.json out of
a published app.
Whether Stripe is offered is your server's decision
When a customer picks a fiat currency to deposit, the app lists the gateways your server offers for that currency. Stripe is in the list only when all of these hold on your server:
- the Stripe gateway is switched on under Admin → Finance → Payment Systems → Payment Gateways;
- the currency is in the Stripe gateway's currency list;
APP_STRIPE_SECRET_KEYis set. Your server leaves out any gateway whose credentials are incomplete.
Fiat deposits as a whole appear in the app only while Fiat Wallets is on (Admin → System → Platform Settings → Wallet).
If your server offers Stripe and the app was built with an empty
stripePublishableKey, customers still see Stripe, enter an amount, and the
payment fails when the payment sheet should open. Either build the app with the
key, or switch the Stripe gateway off — which removes it from your website too.
Set it up
-
Configure Stripe on your server. Set
APP_STRIPE_SECRET_KEY(andAPP_STRIPE_PUBLIC_KEYfor your website) in.envand restart the backend. Switch the Stripe gateway on, choose its currencies, and press Test connection on its page. See Deposit gateways. -
Put the publishable key in the app. In
app_config.json, setstripePublishableKeyto thepk_…key from the same account and mode.{ "stripePublishableKey": "pk_test_..." } -
Build and test with test keys. Deposit a small amount with the card
4242 4242 4242 4242, any future expiry date and any CVC. It should land in the customer's fiat wallet within seconds. -
Go live with both keys together. Swap the server's secret key and the app's publishable key for their
_live_versions, restart the backend, and build the app again.
The publishable key is packed into the app. If you publish a build with a test key and later switch your server to a live secret key, every installed copy stops being able to pay until its user installs a build with the live key. Put the live key in before your first public release, and switch the server at the same time.
What the customer sees
- On the deposit screen (Deposit Funds), they choose Fiat Currency, then a currency.
- Stripe appears among the payment methods. Choosing it shows Stripe Payment — Secure payment via Stripe.
- They enter an amount and tap Pay with Stripe.
- Stripe's payment sheet opens, in the app's light or dark theme and colours,
with your app's name (
appName) as the merchant name. - After a successful payment the app asks your server to confirm it, and the deposit appears in their fiat wallet.
- Closing the payment sheet cancels quietly, with no error.
- A declined card or any other refusal from Stripe shows Stripe's own message.
- Fees. The Stripe gateway's fees, as you set them per currency on your server, apply to app deposits as they do on your website.
The app does not set up Apple Pay or Google Pay in the payment sheet.
When a deposit fails
Your server answers a Stripe deposit it cannot take with one of these. The app may report them only as a general payment failure. Your website's deposit form runs the same checks and shows the server's message, so if the app just says the payment failed, try the same currency on your website.
| Server message | Cause | Fix |
|---|---|---|
Stripe gateway not found |
The Stripe gateway is switched off | Switch it on under Payment Gateways |
Currency <code> is not supported by Stripe |
The currency is not in the Stripe gateway's list | Add it to the gateway's currencies, or deposit another currency |
Stripe API key is not set in environment variables. |
APP_STRIPE_SECRET_KEY is missing |
Set it and restart the backend |
Error creating payment intent: … |
Stripe refused to create the payment, followed by Stripe's reason | For example a wrong or revoked secret key. Press Test connection on the gateway |
Payment intent status: <status> |
The payment had not succeeded when the app asked your server to confirm it | Check the payment in your Stripe dashboard |
Transaction already exists |
Not a refusal: this payment was already credited, and the server answers with the existing deposit | Nothing: the deposit is in the wallet |
Payment intent does not belong to the authenticated user |
The payment being confirmed was created for another account | Nothing to fix in configuration |
A payment that fails inside the payment sheet — a publishable key from the wrong account or mode, or no key at all — is reported by Stripe in the sheet, not by your server.
What it deliberately does not do
- No other payment key. Stripe is the only payment provider with a key in
app_config.json. - No payment key from your server. The publishable key comes from the build, so changing it means a new build and a store update.
- No payment without your server. The app never charges a card on its own: every payment is created, and credited, by your server.
Declaring payment data in the stores' privacy forms is covered on Data safety and privacy.