Documentation Index
Fetch the complete documentation index at: https://grantmaster.dev/llms.txt
Use this file to discover all available pages before exploring further.
Stripe Payment Setup
Developer guide for configuring Stripe payments in GrantMaster — local development, staging, and production.
Prerequisites
- A Stripe account (test mode is fine for local dev)
- Firebase CLI installed (
npm install -g firebase-tools)
- GrantMaster repo cloned and dependencies installed
Architecture Overview
Browser (Stripe.js + Elements)
│
├─ Publishable key (pk_*) — loaded from VITE_STRIPE_PUBLISHABLE_KEY
│ Used only for Stripe Elements (card inputs, Payment Element)
│
└─ Cloud Functions (Firebase)
├─ Secret key (sk_*) — stored in STRIPE_SECRET_KEY env/secret
├─ Webhook secret (whsec_*) — stored in STRIPE_WEBHOOK_SECRET
│
├─ callableHandlers.ts — checkout, portal, list invoices/methods
├─ paymentMethods.ts — attach, detach, SetupIntent, set default
├─ subscriptionOperations.ts — tier changes, cancel, reactivate
├─ subscriptionManagement.ts — seats, usage sync, cost preview
├─ paymentSettings.ts — billing address, tax, invoice footer
└─ webhookHandlers.ts — 11 event types, idempotent processing
All sensitive Stripe operations run server-side. The frontend only uses the publishable key for Stripe Elements.
Step 1: Get Your Stripe API Keys
- Go to Stripe Dashboard → API keys
- Copy your Publishable key (
pk_test_... or pk_live_...)
- Copy your Secret key (
sk_test_... or sk_live_...)
Security: Never commit secret keys to version control. Never expose sk_* keys in frontend code.
Frontend (.env.local)
# Safe to store locally — publishable keys are designed for client-side use
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key_here
Cloud Functions (functions/.env)
For local emulator development, copy and fill in:
cp functions/.env.example functions/.env
Required variables in functions/.env:
STRIPE_SECRET_KEY=sk_test_your_secret_key_here
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_signing_secret
APP_URL=http://localhost:3000
Production / Staging
Use Firebase Functions secrets (never plain env files in deployed environments):
firebase functions:secrets:set STRIPE_SECRET_KEY
firebase functions:secrets:set STRIPE_WEBHOOK_SECRET
Automated Setup Script
A helper script is available that prompts for keys interactively:
bash scripts/setup-stripe-keys.sh
It accepts environment variables or prompts, validates key formats, stores the secret key in Firebase, and writes the publishable key to .env.local.
Step 3: Create Stripe Products & Prices
GrantMaster uses three subscription tiers. Create these in Stripe Dashboard → Products:
| Tier | Monthly Price ID | Yearly Price ID |
|---|
| Starter (Potential) | price_... | price_... |
| Professional | price_... | price_... |
| Ultimate | price_... | price_... |
Each tier also needs seat add-on prices (monthly + yearly).
After creating prices, update the IDs in src/config/subscriptionTiers.ts:
stripeMonthlyBasePriceId: 'price_your_id_here',
stripeYearlyBasePriceId: 'price_your_id_here',
stripeMonthlySeatPriceId: 'price_your_id_here',
stripeYearlySeatPriceId: 'price_your_id_here',
And set the corresponding env vars for webhook tier resolution in Cloud Functions:
STRIPE_PRICE_POTENTIAL_MONTHLY=price_...
STRIPE_PRICE_POTENTIAL_YEARLY=price_...
STRIPE_PRICE_PROFESSIONAL_MONTHLY=price_...
STRIPE_PRICE_PROFESSIONAL_YEARLY=price_...
STRIPE_PRICE_ULTIMATE_MONTHLY=price_...
STRIPE_PRICE_ULTIMATE_YEARLY=price_...
Production
- Go to Stripe Dashboard → Webhooks
- Add endpoint:
https://<region>-<project-id>.cloudfunctions.net/stripeWebhook
- Select these events:
checkout.session.completed
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted
customer.subscription.trial_will_end
customer.updated
invoice.payment_succeeded
invoice.payment_failed
payment_method.attached
payment_method.detached
charge.dispute.created
- Copy the signing secret → store as
STRIPE_WEBHOOK_SECRET
Local Development
Use the Stripe CLI to forward webhooks to your emulator:
stripe listen --forward-to http://localhost:5001/<project-id>/<region>/stripeWebhook
The CLI prints a webhook signing secret (whsec_...) — add it to functions/.env.
Step 5: Verify the Integration
Stripe.js Loading
index.html includes <script src="https://js.stripe.com/v3/"></script>. Verify it loads in your browser’s Network tab.
Content Security Policy
firebase.json includes CSP headers allowing:
script-src: https://js.stripe.com, https://m.stripe.network
connect-src: https://api.stripe.com, https://m.stripe.network
frame-src: https://js.stripe.com, https://m.stripe.network
Test Card Numbers
Use Stripe test cards:
| Card Number | Scenario |
|---|
4242 4242 4242 4242 | Successful payment |
4000 0000 0000 3220 | 3D Secure authentication required |
4000 0000 0000 9995 | Payment declined |
Troubleshooting
“STRIPE_SECRET_KEY not configured” — Cloud Functions can’t find the secret key. Check functions/.env (local) or run firebase functions:secrets:access STRIPE_SECRET_KEY (deployed).
“Webhook secret not configured” — Set STRIPE_WEBHOOK_SECRET in functions/.env or Firebase secrets.
Payment settings return “permission denied” — The verifyOrganizationAccess function checks people/{uid} for org membership. Ensure the user’s people doc has the correct organizationId and an Admin/Super Admin systemRole.
Callable functions fail with “failed-precondition” — App Check is enforced in production. In the emulator, App Check is skipped automatically.
File Reference
| File | Purpose |
|---|
src/features/billing/services/stripePaymentService.ts | Frontend service — all Stripe operations via Cloud Functions |
src/features/billing/services/stripeModuleBilling.ts | Module add-on billing service |
src/config/subscriptionTiers.ts | Tier definitions with Stripe price IDs |
src/lib/runtimeEnv.ts | Validates VITE_STRIPE_PUBLISHABLE_KEY at build time |
functions/src/stripe/client.ts | Stripe client initialization + auth helpers |
functions/src/stripe/callableHandlers.ts | Checkout, portal, invoices, payment methods |
functions/src/stripe/paymentMethods.ts | Attach/detach/SetupIntent/default |
functions/src/stripe/subscriptionOperations.ts | Tier changes, cancel, reactivate |
functions/src/stripe/subscriptionManagement.ts | Seats, usage sync, cost preview |
functions/src/stripe/paymentSettings.ts | Billing address, tax, invoice footer |
functions/src/stripe/webhookHandlers.ts | Webhook processing (11 event types) |
functions/src/stripe/idempotency.ts | Webhook deduplication |
functions/src/stripe/stateMachine.ts | Subscription state machine |
scripts/setup-stripe-keys.sh | Interactive key setup script |