Stripe Integration & Backend Overhaul

via Freelancer ·

Budget / Salary$250–750
TypeFreelance project
LocationRemote
Posted1 hour ago
Termp Stripe Billing Integration and backend change to support it

Add subscription billing so organizations are gated by pricing tier (Free, Solo, Team, LSP). One subscription per org. Current JWT auth is compatible — no auth changes needed. Stripe webhooks bypass auth and validate via signature.

---

### Definitions

Billing unit is the organization. Each org gets one subscription.

Plans: Free (default), Solo ($29/mo, $23/mo yearly), Team ($149/mo, $119/mo yearly), LSP (custom, sales-assisted).

Limits enforcement uses segments as the countable unit (pricing page says "keys" but we count segments). Advanced seats = admin + project_manager + translator roles. Reviewer-only members are free. MT words counted at platform level before sending to provider. AI words and integrations are placeholder meters — include in schema but do not enforce until those features ship.

Data preservation on downgrade: existing data stays accessible. Only new creation beyond the lower limit returns 402.

---

### Schema Changes

Add to organizations table: stripe_customer_id (unique), stripe_subscription_id, stripe_price_id, plan (default 'free'), subscription_status (default 'free'), current_period_end, trial_ends_at.

New usage_meters table: id, org_id (FK), period_start, period_end, mt_words_used (default 0), ai_words_used (default 0). Unique index on (org_id, period_start).

Add env vars: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, price ID mappings per plan/interval. Store in AWS Secrets Manager, add to EC2 user-data fetch loop.

---

### Billing Service

Create/get Stripe customer on org creation. Use unique constraint to prevent duplicates on race conditions.

Checkout session creation: accepts org ID, price ID, success/cancel URLs, optional 14-day trial. Admin only.

Portal session creation: returns Stripe Customer Portal URL for self-service management.

Plan limits function returns per-tier caps: segments (500/5K/50K/unlimited), languages (3/10/unlimited/unlimited), projects (1/5/unlimited/unlimited), advanced seats (1/1/5/unlimited), MT words/month (10K/100K/1M/unlimited).

Cancel subscription at period end (not immediate).

---

### Webhook Handler

Register at /api/v1/webhooks/stripe without auth middleware. Use raw body + Stripe signature verification. Must be idempotent (check event ID to skip duplicates).

Events: checkout.session.completed (activate plan), customer.subscription.updated (sync plan/status/period), customer.subscription.deleted (revert to free), invoice.payment_failed (set past_due), invoice.paid (clear past_due).

---

### Plan Enforcement

Add checks to existing routes. Return 402 with error, resource type, current usage, limit, plan, and upgrade flag.

- Document upload/creation: count org-wide segments, block if exceeds plan
- Project creation: count org projects, block at limit
- Member addition: count advanced seats, block if new non-reviewer member exceeds limit
- MT translation (single + batch): count source words, check against monthly MT limit, increment meter atomically on success
- Project creation with new language pair: count distinct target languages across org

Use atomic SQL increments for meters to handle concurrency.

---

### Frontend

Billing settings page (admin only): current plan badge, usage bars (segments, MT words, seats vs limits), Manage Subscription button (opens Stripe Portal), Upgrade button (initiates checkout), period end date, trial days remaining.

Pricing page: wire "Start 14-day trial" CTAs to checkout endpoint with trial. "Talk to sales" links to contact form.

Global 402 handler: when API returns 402, show upgrade prompt with limit details and link to billing page.

Trial banner in dashboard header when org is trialing, showing days remaining.

Billing context follows org switcher (all billing calls include org ID from currentOrg store).

---

### Trial Flow

All new orgs start on free. Stripe customer created automatically on org creation. No auto-trial.

User clicks trial CTA, checkout creates subscription with 14-day trial. At expiry: payment method present converts to paid (Stripe default behavior); no payment method triggers subscription.deleted webhook which reverts to free.

---

### Edge Cases

Org deletion: cancel active Stripe subscription immediately before database deletion.

Stripe API outage: return 503 for checkout/portal calls but never block core features (editing, TM, QA). Plan limits read from local database, not Stripe API.

Past-due grace: set status to past_due on payment failure but maintain access. Only revoke on subscription.deleted (Stripe exhausted retries).

Webhook replay: return 200 without reprocessing if event already handled.

---

### Acceptance Criteria

- Free org works within limits (500 segments, 3 languages, 1 project, 10K MT words)
- Upgrade end-to-end: CTA, Stripe Checkout, webhook, plan updates, limits expand immediately
- Downgrade: cancel via portal, runs until period end, reverts to free, existing data preserved, new creation blocked at 402
- MT metering tracks words per cycle, blocks at limit with 402
- Admin-only billing access
- Idempotent webhooks handle duplicates and out-of-order events
- Trial: 14-day, banner with countdown, auto-downgrade without payment, auto-convert with payment
- Org deletion cancels subscription
- Stripe failures never block translation work
- Limits enforce on creation only, never retroactively restrict existing data
javascript project management software architecture node.js software development stripe web development payment processing saas
Apply on Freelancer →

Project sourced from Freelancer.com. Applications happen directly on the original platform — we never collect your data.