Skip to main content

Cloud Edition Billing Setup

After deploying Kuploy Cloud edition, configure Stripe and seed billing plans to enable subscriptions.

1. Create Stripe Products

In Stripe Dashboard (use test mode for development):

  1. Create a Pro product with a $20/month recurring price
  2. Create a Business product with a $100/month recurring price
  3. Copy the Price IDs (e.g., price_1234...)
note

The Free plan doesn't need a Stripe product - it's managed entirely in the database.

2. Update Stripe Configuration

Add the Price IDs to your deployment secrets:

# Get current secrets
kubectl get secret kuploy-secrets -n kuploy -o yaml > /tmp/secrets.yaml

# Edit to add/update:
# STRIPE_PRO_PRICE_ID: <base64-encoded-price-id>
# STRIPE_BUSINESS_PRICE_ID: <base64-encoded-price-id>

# Encode your values
echo -n "price_your_pro_id" | base64
echo -n "price_your_business_id" | base64

# Apply updated secrets
kubectl apply -f /tmp/secrets.yaml

# Restart deployment to pick up changes
kubectl rollout restart deployment/kuploy -n kuploy

3. Seed Billing Plans

The database needs to be seeded with the Free, Pro, and Business plans:

# Get DATABASE_URL from secrets
export DATABASE_URL=$(kubectl get secret kuploy-secrets -n kuploy -o jsonpath='{.data.DATABASE_URL}' | base64 -d)

# Option A: Run seed from kuploy-cloud repo (if available locally)
cd kuploy-cloud/packages/cloud-server
pnpm db:seed

# Option B: Run seed via kubectl exec
kubectl exec -it deployment/kuploy -n kuploy -- npm run db:seed

# Option C: Insert plans manually via SQL
kubectl exec -it postgresql-0 -n database -- psql $DATABASE_URL -c "
INSERT INTO cloud_plans (\"planId\", name, \"stripePriceId\", \"maxProjects\", \"maxApps\", \"maxDatabases\", \"maxTeamMembers\", \"maxDomains\", \"buildMinutesPerMonth\", \"cpuLimit\", \"memoryLimit\", \"storageLimit\", price, \"isActive\", \"sortOrder\")
VALUES
('free', 'Free', NULL, 1, 2, 1, 1, 1, 100, '500m', '1Gi', '5Gi', 0, true, 0),
('pro', 'Pro', 'price_YOUR_PRO_PRICE_ID', 5, 10, 5, 5, 10, 500, '2000m', '4Gi', '20Gi', 2000, true, 1),
('business', 'Business', 'price_YOUR_BUSINESS_PRICE_ID', 20, 50, 25, 20, 50, 2000, '8000m', '16Gi', '100Gi', 10000, true, 2)
ON CONFLICT (\"planId\") DO UPDATE SET
\"stripePriceId\" = EXCLUDED.\"stripePriceId\",
\"isActive\" = EXCLUDED.\"isActive\";
"

4. Verify Plans

Check that plans are visible:

# Query the database
kubectl exec -it postgresql-0 -n database -- psql $DATABASE_URL -c "SELECT \"planId\", name, \"stripePriceId\", price FROM cloud_plans;"

# Or visit the billing page in your browser
# https://your-domain.com/billing

You should see Free, Pro, and Business plans displayed on the billing page.

5. Configure Stripe Webhooks

For production, configure webhooks in Stripe Dashboard:

  1. Go to DevelopersWebhooks
  2. Add endpoint: https://your-domain.com/api/webhooks/stripe
  3. Select events:
    • checkout.session.completed
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.paid
    • invoice.payment_failed
  4. Copy the webhook signing secret
  5. Update STRIPE_WEBHOOK_SECRET in your secrets:
# Encode the new webhook secret
echo -n "whsec_your_webhook_secret" | base64

# Update the secret in Kubernetes
kubectl edit secret kuploy-secrets -n kuploy
# Or patch it:
kubectl patch secret kuploy-secrets -n kuploy -p '{"data":{"STRIPE_WEBHOOK_SECRET":"<base64-encoded-value>"}}'

# Restart to pick up changes
kubectl rollout restart deployment/kuploy -n kuploy

Updating Price IDs Later

If you need to update Stripe price IDs after initial setup:

kubectl exec -it postgresql-0 -n database -- psql $DATABASE_URL -c "
UPDATE cloud_plans SET \"stripePriceId\" = 'price_NEW_PRO_ID' WHERE \"planId\" = 'pro';
UPDATE cloud_plans SET \"stripePriceId\" = 'price_NEW_BUSINESS_ID' WHERE \"planId\" = 'business';
"

Troubleshooting

Plans not showing on billing page

  1. Verify plans exist in database:

    kubectl exec -it postgresql-0 -n database -- psql $DATABASE_URL -c "SELECT * FROM cloud_plans;"
  2. Check isActive is true for all plans

  3. Check browser console for API errors

Stripe checkout fails

  1. Verify STRIPE_SECRET_KEY is correct
  2. Verify stripePriceId in database matches Stripe Dashboard
  3. Check Kuploy logs: kubectl logs -n kuploy -l app.kubernetes.io/name=kuploy

Webhooks not received

  1. Verify webhook endpoint is accessible from internet
  2. Check STRIPE_WEBHOOK_SECRET matches Stripe Dashboard
  3. View webhook logs in Stripe Dashboard → Developers → Webhooks → Select endpoint