Setting Up Billing for Your Users
Enable subscriptions and payments for the organizations using your kuploy-cloud platform. This guide walks you through connecting Stripe and creating the plans your end users will subscribe to.
The plans you configure here are instance plans — the subscriptions your customers (organizations) pay to you. These are separate from your platform plan at kuploy.app.
You control the pricing, limits, and names of instance plans.
All payments — Stripe cards, Apple/Google Pay, and mobile money — flow through the Payment Gateway on Business+ plans, which runs on ePay. This guide stops at creating a Stripe account and defining your plans; wiring up the keys and webhook happens once, on the Payment Gateway admin page, not per rail.
1. Create a Stripe Account
If you don't have a Stripe account yet:
- Go to stripe.com and click Start now
- Enter your email and create a password
- Verify your email address
- Complete business verification (can be done later for testing)
Stripe provides a Test mode for development. Toggle "Test mode" in the top-right of the Stripe Dashboard. Test mode uses fake money and test card numbers - perfect for setup and testing.
2. Get Your API Keys
- In Stripe Dashboard, click Developers in the left sidebar
- Click API keys
- You'll see two keys:
- Publishable key (
pk_test_...orpk_live_...) - safe to expose - Secret key (
sk_test_...orsk_live_...) - keep private!
- Publishable key (
- Click Reveal test key to copy your secret key
Never share your secret key. Never commit it to git. Only enter it in secure settings.
3. Stripe Products Are Created Automatically
You do not need to create Products or Prices in Stripe by hand. When you save a priced plan at /admin/plans, kuploy-cloud creates (or updates) the matching Stripe Product and Price on your own Stripe account, using the price you just entered.
/admin/plans (you) Stripe (your account)
┌───────────────────────┐ ┌─────────────────────────────┐
│ slug: "pro" │ │ Create/update Product │
│ price: 2000 │──on save──► │ Create/update Price │
│ currency: "cad" │ │ (archive the old Price) │
│ cycle: monthly │ └─────────────────────────────┘
└───────────────────────┘
Change a plan's price and the next save updates the Stripe Price. Existing subscriptions are not changed retroactively — only new checkouts use the updated price.
A plan priced at 0 has nothing to charge, so no Stripe Product or Price is created for it. That is normally your default plan — the one new organizations land on without any payment step.
4. Connect Stripe via the Payment Gateway
Your Stripe credentials live on a Provider record inside your epay-gateway deployment, not in a kuploy-cloud-only settings screen. This keeps one source of truth for every payment rail.
Follow the Payment Gateway setup guide to:
- Connect kuploy-cloud to your epay-gateway deployment
- Create a Stripe provider record on the gateway with your secret key (
sk_test_.../sk_live_...) and webhook signing secret (whsec_...) - Point the Stripe webhook endpoint at the gateway (not directly at kuploy-cloud — the old
/api/webhooks/stripekuploy-cloud endpoint was removed in the cutover)
Once the gateway is connected, the Payment Gateway panel at Admin → Payment Gateway lights up "configured", and plan checkouts / billing portal / invoice listing all work without extra setup.
5. Define Your Plans
Plans live in your instance, at Admin → Plans (/admin/plans). You set every name, price, quota and feature toggle yourself; kuploy.app never pushes a catalog down.
A fresh install seeds only free and internal. From there you can Suggest paid plans to get a Starter / Growth / Business ladder as hidden drafts to edit, or build each one by hand.
Your platform plan is a ceiling, not a template: a plan granting more than your kuploy.app tier allows is refused when you save it, and a feature only reaches an organization when both your platform tier and the org's plan grant it.
See Manage Your Plans for the full walkthrough — quotas, currency, the Internal tier, and what you can't delete.
6. Verify Your Plans
- In kuploy-cloud, go to Admin → Plans
- Check each plan shows the name, price and currency you expect
- Confirm exactly one plan is marked Default — that is where new organizations land
- Stripe Products and Prices are provisioned on save — no manual Price ID entry required
7. Set Up Webhooks
Stripe webhooks now flow Stripe → your epay-gateway → kuploy-cloud rather than directly to kuploy-cloud. Full setup is covered in the Payment Gateway guide — see Point your webhooks at kuploy-cloud.
At a glance:
- In the Stripe Dashboard, add an endpoint pointing at your epay-gateway:
https://<your-gateway-host>/api/webhooks/stripe/<merchantCode> - Subscribe to the subscription + invoice events (
customer.subscription.*,invoice.payment_*). - Paste the Stripe signing secret (
whsec_...) into the Stripe provider record on your gateway — not into kuploy-cloud. The gateway verifies and relays to/api/webhooks/epayon kuploy-cloud.
8. Test Your Setup
Use Stripe test cards to verify everything works:
| Card Number | Result |
|---|---|
4242 4242 4242 4242 | Successful payment |
4000 0000 0000 0002 | Card declined |
4000 0000 0000 3220 | Requires 3D Secure |
Use any future expiry date and any 3-digit CVC.
- Create a test user account
- Go to Billing and select a paid plan
- Complete checkout with a test card
- Verify the subscription appears in both kuploy-cloud and Stripe Dashboard
Assigning Plans Manually (Employees, Partners, Test Accounts)
Some organizations on your platform should not be billed through Stripe — internal employees, partner accounts, or test accounts you provision yourself. For these, use Admin → Organizations & Plans in your kuploy-cloud dashboard:
- Search for the organization
- Click Change plan and pick a plan from the dropdown
- Save — the org now has an "active" subscription tagged Manual with a 30-day billing period (so build-minute quotas reset on a predictable boundary)
Manual subscriptions show a Manual badge in the org list. Their members see a "Your plan is managed by the platform administrator" notice on the billing page instead of Stripe checkout/portal buttons. Use Reset period to roll the billing period forward another 30 days, and Cancel to mark the manual sub as canceled.
The Organizations admin refuses to change plans on Stripe-backed subscriptions to avoid drift between the database and Stripe. To change those, use the Stripe Dashboard — webhooks will sync the change back.
Going Live
When ready for production:
- Complete Stripe business verification
- Toggle off "Test mode" in the Stripe Dashboard
- Swap the Stripe secret key + webhook signing secret on your epay-gateway Stripe provider record for the live values
- Update the Stripe webhook endpoint in the Stripe Dashboard to point at your production epay-gateway URL (test-mode and live-mode endpoints are separate)
- Re-save each priced plan at
/admin/plansso its Product and Price are created on the live Stripe account - Test with a real card (you can refund immediately)
kuploy-cloud itself has no Stripe keys to swap; the gateway is the single credentials surface.
Technical Reference
For Kubernetes deployments, the only Stripe-related environment variables live on your epay-gateway deployment, not on kuploy-cloud. See admin/.env.example in the gateway repo for the full list.
kuploy-cloud only needs the gateway connection details (URL + admin key + merchant code + merchant key). Those are configured through Admin → Payment Gateway; for headless Kubernetes installs, the same four values are accepted as env vars:
| Variable | Description |
|---|---|
EPAY_GATEWAY_URL | Public URL of your epay-gateway deployment |
EPAY_GATEWAY_ADMIN_KEY | Bearer token kuploy-cloud uses to call the gateway's management API |
EPAY_MERCHANT_CODE | Tenant merchant identifier inside the gateway |
EPAY_MERCHANT_KEY | HMAC secret used to verify relayed webhooks |
Apply the usual way:
echo -n "your_admin_key" | base64
kubectl patch secret kuploy-secrets -n kuploy \
-p '{"data":{"EPAY_GATEWAY_ADMIN_KEY":"<base64-value>"}}'
kubectl rollout restart deployment/kuploy -n kuploy
Database Migrations
Schema changes run automatically when a new container starts, before it accepts traffic. There are no migration commands for you to run, and no manual step during an upgrade — see Upgrading to Cloud.
Troubleshooting
Checkout fails
- Open Admin → Payment Gateway in kuploy-cloud and click Test Connection — a green check confirms kuploy-cloud can reach the gateway with the stored admin key.
- On your epay-gateway admin, verify the Stripe provider record has the right secret key for the current mode (test vs live).
- Check that plan sync completed and Stripe Prices were auto-provisioned:
kubectl logs -n kuploy -l app.kubernetes.io/name=kuploy | grep -i "stripe.*price"
Webhooks not received
- Confirm the Stripe Dashboard endpoint points at your epay-gateway (
https://<gateway>/api/webhooks/stripe/<merchantCode>) — not at kuploy-cloud. - On the gateway's Stripe provider record, the
apiSecretmust match the Stripe Dashboard's signing secret for that endpoint. - kuploy-cloud's inbound endpoint is
/api/webhooks/epay; check those logs for signature/verification errors. - View Stripe-side delivery logs: Stripe Dashboard → Developers → Webhooks → Select endpoint.
Plans not showing
Your plan catalog is local to your instance — nothing arrives from kuploy.app, so a sync problem is never the cause. At Admin → Plans, check that:
- The plan exists at all. A fresh install has only
freeandinternaluntil you add more — use Suggest paid plans for a starting ladder. - It is Active. Inactive plans keep existing subscribers but are hidden from new signups.
- It is Public. Non-public plans are hidden from
/pricingand the upgrade picker; you can still assign an org to one from Admin → Organizations & Plans. - Exactly one plan is marked Default, or new organizations have nowhere to land.