---
title: Stripe
description: Connect Stripe to NexCMP for card payments, Apple Pay, Google Pay, Link and Alipay — API keys, webhook, domain registration and a test payment.
url: https://nexcmp.com/docs/billing/stripe/
applies_to: NexCMP 1.6.1
updated: 2026-11-02
---

# Stripe

> **Where in the admin:** Finance › Payment channels › Stripe (`/payments/stripe`). Switches and fees: Finance › Payment channels › Fees & limits (`/payments/fees`).

## What it does

Stripe takes card payments for wallet top-ups. With the same account you can also offer **Apple Pay**, **Google Pay**, **Link** and **Alipay**, and let customers **save a card** for [automatic top-up](https://nexcmp.com/docs/billing/auto-top-up/). Use it as the primary channel for international customers.

## Requirements

| Item | Requirement |
|---|---|
| Stripe account | A Stripe account that can accept payments in **USD**. Alipay is charged in JPY and has to be activated by Stripe for your account. |
| Keys | A secret key (`sk_live_...` or `sk_test_...`) and a publishable key (`pk_live_...` or `pk_test_...`). The form only accepts keys with these prefixes. |
| Network | Your panel must be reachable over HTTPS from the Internet (Stripe calls the webhook) and must reach `api.stripe.com` on port 443. |
| Domain (wallets only) | The customer-facing domain has to serve `/.well-known/apple-developer-merchantid-domain-association` — NexCMP does this for you. |
| Dependencies | None. |

::: info Shared Stripe accounts
NexCMP only processes webhook events for payments it created itself, so you can use a Stripe account that also serves another application.
:::

## Prepare the infrastructure

On the Stripe side:

1. Sign in to the [Stripe Dashboard](https://dashboard.stripe.com). Switch **Test mode** on or off to decide whether you are doing a trial run or going live. Keys of one mode never work with the other.
2. Open **Developers › API keys**. Copy the **Publishable key** and reveal and copy the **Secret key**. Keep the secret key private.
3. (Optional) Open **Settings › Payment methods** and activate **Alipay** if you want to offer it.
4. You do **not** have to create the webhook by hand — NexCMP can create it for you (see step 5 below). If you prefer to do it manually, create an endpoint in **Developers › Webhooks** with the URL and events listed in [Webhook](#webhook).

## Connect in NexCMP

1. Open **Finance › Payment channels › Stripe** (`/payments/stripe`).
2. In the **API keys** card choose **Mode** (`live` or `test`), paste the **Secret key** and the **Publishable key**.
3. Click **Save**. The keys are written to a configuration file on the server that only the NexCMP service account can read. They are never sent back to the browser; afterwards the page shows only the last 4 characters.
4. Click **Check**. A dialog reports the connection, mode, available and pending balance, account ID, whether charges are enabled, whether a webhook exists and whether Alipay is available. A red line means that part needs attention.
5. In the **Webhook** card click **Create webhook** and confirm. NexCMP asks Stripe to create the endpoint with every required event and fills **Webhook signing secret** (`whsec_...`) automatically. The URL pre-filled in the field is `https://<your-domain>/v1/billing/stripe/webhook`, for example `https://cloud.example.com/v1/billing/stripe/webhook`.
6. Open **Fees & limits** (`/payments/fees`), keep **Card (Stripe)** on, set **Stripe fee %** and **Stripe fixed fee (cents)** to your real tariff and click **Save channels & fees**. See [Payment channels](https://nexcmp.com/docs/billing/payment-channels/#switches-and-fees-fees-limits).

![Stripe page with the mode, secret key and publishable key filled in with example values](https://nexcmp.com/docs/images/billing/stripe-01-keys.webp)


### Webhook

The red banner "Missing webhook_secret" stays until a signing secret is saved. Without it Stripe top-ups are **not recorded**, even though Stripe took the money.

| Item | Value |
|---|---|
| URL | `https://<your-domain>/v1/billing/stripe/webhook` |
| Events | `checkout.session.completed`, `payment_intent.succeeded`, `payment_intent.payment_failed`, `charge.refunded`, `charge.dispute.created`, `charge.dispute.closed`, `radar.early_fraud_warning.created`, `refund.updated`, `refund.failed` |
| Signature | Stripe `Stripe-Signature` header, HMAC-SHA256, 300 seconds tolerance. Requests with a bad signature get HTTP 400. |
| Idempotency | Each event ID is stored once; a repeated delivery never credits twice. |

If you upgraded from a release that registered fewer events, click **Create webhook** again — the old endpoint is kept, so delete it by hand in the Stripe Dashboard afterwards.

The **24h events** and **Latest event** rows in the Webhook card tell you whether Stripe is reaching the panel. Individual events are listed in **Payment channels › Gateway events** (`/payments/events`, tab Stripe), where each event can be viewed (**Payload**) or replayed (**Replay**).

### Apple Pay, Google Pay and Link

1. In the **Wallets (Apple Pay · Google Pay · Link) & Alipay** card, the field **Customer app Domain registered with Stripe** is pre-filled with your site's host name (for example `cloud.example.com`).
2. Click **Register / verify domain** and confirm. NexCMP registers the domain in Stripe's payment method domains and asks Stripe to validate it.
3. The result shows the status of **Apple Pay**, **Google Pay** and **Link**. Apple Pay shows only when the status is `active`.
4. In **Fees & limits** keep **Apple Pay · Google Pay · Link** on.

![Wallet card showing the registered domain and the Apple Pay, Google Pay and Link statuses](https://nexcmp.com/docs/images/billing/stripe-03-wallets.webp)

::: tip Apple Pay stays inactive
Apple Pay needs the domain-association file to answer HTTP 200 on your public domain. If you put Cloudflare or another proxy in front, do not block `/.well-known/`.
:::

### Alipay

Alipay is optional. Activate it in **Stripe Dashboard › Settings › Payment methods**, click **Check** and wait until the dialog shows that Alipay is available, then turn on **Alipay (Stripe, JPY display)** in **Fees & limits**. Set **Alipay fee %**, **Alipay fixed fee**, the **¥/USD rate** (50–500) and the **FX spread %** (0–20). Update the ¥/USD rate regularly; the page warns when it is older than 7 days.

## Verify

1. In test mode, sign in to the portal as a test customer, open **Billing**, click **Deposit**, choose **Card** and pay the minimum with the Stripe test card `4242 4242 4242 4242` (any future date, any CVC).
2. The balance rises within seconds and the payment appears under **Finance › Billing › Top-ups** with the status *Completed*.
3. Open **Payment channels › Gateway events › Stripe**: you should see `checkout.session.completed` or `payment_intent.succeeded` with a processed time.
4. Back on the Stripe page, **24h events** is above 0.

Before going live, switch **Mode** to `live`, paste the live keys and click **Create webhook** again (webhooks of test and live mode are separate).

## Limits & notes

- **Amounts and currency.** Wallets are in USD. Card, wallet and link payments are charged in USD; Alipay is shown to the customer in JPY and converted at your rate.
- **Fees.** Stripe's real fee is not read back automatically; the fee percentage you set decides what the customer sees and what the wallet is credited. Choose **Customer pays top-up fee** in *Fees & limits* to charge the fee on top.
- **Saved cards.** When the customer ticks *Save card for auto top-up* the card is stored at Stripe, not on your server. See [Saved payment methods](https://nexcmp.com/docs/billing/saved-payment-methods/).
- **Refunds.** Refunding to the card is a two-step process: an admin creates a refund request for a completed payment (**Finance › Billing › Top-ups**, refund action on the payment) and then approves it under **Finance › Payouts › Card refunds** (`/billing/payouts`). Alipay refunds are asynchronous; a failed one (`refund.failed`) returns the held amount to the wallet.
- **Disputes.** On `charge.dispute.created` NexCMP blocks the customer's account, stops their prepaid services (nothing is deleted) and sends an admin alert. If you win (`charge.dispute.closed`), the amount is credited back to the wallet.
- **Waiting payments.** If a webhook never arrives, NexCMP checks payments that stayed pending for more than 10 minutes against Stripe on its own and completes them. Payments older than 7 days are ignored.
- **Resellers** can connect their own Stripe account (webhook `https://<their-domain>/v1/billing/stripe/webhook/r/<id>`); see [Resellers](https://nexcmp.com/docs/customers/resellers/).

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| "Secret key must start with sk_live_/sk_test_" | Wrong key pasted | Paste the secret key from **Developers › API keys**. |
| "Secret key does not match live/test mode" | Mode and key disagree | Make the **Mode** match the prefix of the key. |
| "Publishable key must start with pk_" | Wrong key | Use the publishable key. |
| Check says the connection failed | Wrong key, key revoked, or the server cannot reach `api.stripe.com` | Re-paste the key; test with `curl -I https://api.stripe.com` from the server. |
| Red banner "Missing webhook_secret" | The signing secret is not saved | Click **Create webhook** or paste the `whsec_...` secret from the Stripe Dashboard and **Save**. |
| Money taken but the balance did not change | Webhook not delivered or signature failing | Check the URL ends with `/v1/billing/stripe/webhook`, the secret matches the endpoint, and replay the event in **Gateway events**. In Stripe, open the endpoint and look at the delivery attempts (HTTP 400 means a wrong signing secret). |
| "Create webhook" fails | The URL is not HTTPS or not reachable | Use your public `https://` domain. |
| Apple Pay status not active | Domain not validated | Click **Register / verify domain** again after the domain-association file answers 200. |
| Alipay not available in the Check dialog | Not activated at Stripe | Activate it in the Stripe Dashboard, then click **Check**. |
| Customer sees no card form | **Card (Stripe)** is off or no secret key | Turn it on in **Fees & limits** and save keys. |
