Web + MCP
Billing Builder
An embeddable, agent-built billing widget - plans, paid-feature gating, and live billing state - that drops into any MindLap app.
Want the product? Enter your email to try it live.
About this project
Billing Builder is an embeddable billing layer for MindLap apps, generated end-to-end by the agent factory. It models plans, billing types, payment methods, and per-feature entitlements, then exposes a billing-state resolution API so any product can check in real time whether a user can activate a paid feature. The frontend ships as a self-contained widget - a billing page plus an embed entry point with its own routing - built on reusable primitives aligned to the Halo design system, while the backend covers schema migrations, repository primitives, and a billing summary aggregation that rolls usage into a single state endpoint.
Demo
At a glance
8.2h
Agent hours
87M
Tokens
2
Laps
11
Stories
87M
tokens
Others · 100%
Tokens by stage
Implement
50M
Code Review
7M
Fix
8M
Merge
21M
Auth Review
1M
Pipeline
Stage
Runs
Tokens
Duration
Implement
20
50M
3.7h
Code Review
14
7M
1.4h
Fix
3
8M
1.5h
Merge
7
21M
1.6h
Auth Review
1
1M
0.1h
Engines used
Others
Tokens
87M
Runs
45
Agent hours
8.2h
Success
48.9%
Agent team
developer
28 runs · 6.7h
13 passed · 15 failed
engineering_manager
15 runs · 1.5h
9 passed · 6 failed
Artifacts
PRD
markdownBillingBuilder - Product Requirements Document
1. Overview
1.1 Problem Statement
Product teams building SaaS, API, and infrastructure products need a way to attach pricing and billing to individual features without building custom checkout infrastructure from scratch. Wiring up a payment flow per feature requires significant engineering effort: designing pricing pages, integrating with a payment processor, handling subscriptions and proration, managing entitlements, and tracking usage.
BillingBuilder solves this by giving product owners a no-code configuration wizard that produces embeddable billing pages, fully integrated with Razorpay, ready to drop into any existing product.
1.2 Product Vision
A self-serve tool that lets any product owner configure pricing and generate a production-ready billing page for any product feature in under 15 minutes, without writing code.
1.3 Scope (v1)
- Single organisation (not a multi-tenant SaaS platform)
- One billing unit (meter) per feature config
- Razorpay as the payment processor (Subscriptions for recurring, Orders for one-time)
- Embeddable billing page delivered as iframe, JS snippet, or React component
- Post-authentication end-user interactions only
Note: Multi-tenancy, multiple meters per feature, and additional payment processors are explicitly out of scope for v1.
1.4 Out of Scope (v1)
- Multi-tenant mode (multiple companies using BillingBuilder)
- Multiple simultaneous usage meters per feature
- Payment processors other than Razorpay
- Pre-authentication public-facing marketing pricing pages
- Revenue dashboards and analytics beyond basic subscriber counts
- Custom billing cycles (quarterly, bi-annual, etc.)
2. Users and Roles
BillingBuilder serves two distinct user types with separate surfaces.
| Role | Who they are | Primary surface | Key actions |
|---|---|---|---|
| Product Owner (Admin) | Internal team member configuring billing for a product feature | Admin Config Dashboard | Create/edit configs, define tiers, publish embed code |
| End User (Customer) | Authenticated user of the product owner's app, post-login | Embedded Billing Page | Subscribe, upgrade, downgrade, cancel, view invoices |
3. Admin Configuration Flow
The admin creates a billing config via a 7-step wizard. Configs are saved as drafts until explicitly published.
3.1 Step 1 - Feature Identifier
- Feature ID - internal lowercase slug (e.g.
ai-summarize). Unique within the org, validated on input. - Feature Flag Key - exact key checked by the backend to gate access. Flipped ON on activation and OFF on cancellation.
- Display Name - user-facing title shown on the billing page.
- Description - optional subtitle. Communicates feature value before plan selection.
3.2 Step 2 - Billing Unit
Each feature has exactly one unit (single meter).
- Standard Catalog - pre-built units: API calls, Tokens, Seats / Users, GB storage, GB bandwidth, Events, Renders, Minutes, Tasks, Messages, Credits, Documents, Queries, Workflows.
- Custom Unit - custom label (e.g. "Frames processed") and optional plural form.
3.3 Step 3 - Billing Method
| Method | Description | Best for |
|---|---|---|
| Flat subscription | Fixed price per billing period, independent of usage | Unlimited access, seat-based features |
| Metered | Charge per unit consumed; backend reports usage via API | API, compute, AI inference features |
| Tiered | Price per unit changes at defined volume brackets | Features where heavier users pay less per unit |
| Credits / Prepaid | Users buy credit packs upfront; usage deducts from balance | Unpredictable usage, prepaid wallet model |
| One-time charge | Single payment; entitlement is time-bounded or perpetual | Tools, templates, one-off access grants |
Selecting "One-time charge" skips Step 5 (Trial Period), since trials only apply to recurring subscriptions.
3.4 Step 4 - Define Tiers
Per-tier configuration: Name, Base price ($), Billing period (Monthly and/or Annual - a toggle appears on the billing page if any tier offers both), Included units, Overage price ($ per unit) (leave blank to hard-cap), Hard-cap toggle, Recommended flag.
Razorpay Plan sync - On publish, one Razorpay Plan is created per tier × billing period combination. Plan IDs are stored on the Tier record. Plan creation is idempotent. A price change creates a new Plan; existing subscribers migrate at their next renewal.
3.5 Step 5 - Trial Period
Optional free trial for recurring tiers. Skipped for one-time billing.
- Trial duration - number of days (0 = no trial).
- Per-tier application - trial enabled/disabled independently per tier.
Trial mechanics: Razorpay collects the payment mandate at trial start (no charge during trial). Status is trial until trialEndsAt; feature flag enabled immediately. End user notified 3 days before expiry; first charge date displayed at signup. On trial end, subscription auto-converts to paid and the first charge is collected.
3.6 Step 6 - Preview
A live render of the billing page using the admin's actual tier config. No real payments in preview mode. Toggle Desktop / Mobile viewports. Captures the billing recurrence setting: Recurring (Razorpay Subscription) or One-time (Razorpay Order).
3.7 Step 7 - Embed and Publish
| Type | How it works | Best for |
|---|---|---|
| iframe | URL with signed config JWT. Append orgId, userId, authToken as query params. | Quickest integration; no frontend dependency |
| JS Snippet | <script> tag mounting a shadow-DOM component into a <div>. Context via window.BillingConfig. | Teams wanting more layout control |
| React Component | npm package. Props: token, orgId, userId. Auth token from app session. | React apps; tight integration with app state |
| Export JSON | Full config as structured JSON for AI-assisted analysis (Claude, Gemini, etc.). | Config audits, documentation, pricing review |
Config token and publish action - Publishing generates a signed HS256 JWT encoding featureId, config version, and allowed origins. Allowed origins must be configured before publishing. Publish increments the config version, syncs Razorpay Plans, activates the embed token, and sets status to live. Rollback to any previous version is available post-publish.
4. End-User Billing Page
The billing page is an embeddable component loaded post-authentication in the product owner's app. The host app passes orgId, userId, and a signed auth JWT.
4.1 Entry and State Detection
- JWT validated server-side on load. Invalid or expired token shows an error state with no data leaked.
- Page queries active Subscription for
(featureId, orgId). - No subscription → Checkout view.
- Active or trial subscription → Management view.
- Cancelled but not yet expired → Management view with expiry notice and reactivate option.
4.2 Checkout Flow
Tier comparison - All tiers displayed side by side: name, price, billing period, included units, overage rate, trial info, CTA. Tiers with a trial show "Start free trial"; others show "Select plan". Monthly/annual toggle appears if any tier offers both periods. Recommended tier visually emphasised.
Plan selection and payment - On selection the user sees the exact first charge date and amount. Recurring: backend creates a Razorpay Subscription, frontend opens Razorpay Checkout for mandate + first payment. One-time: backend creates a Razorpay Order and opens Checkout.
Entitlement activation - On successful webhook: Subscription record created, feature flag flipped ON for orgId, confirmation shown, page transitions to Management. Webhook handlers use razorpaySubscriptionId as idempotency key.
4.3 Management View
- Current tier name, price, next renewal date
- Trial countdown if applicable (with first charge date)
- End-of-period usage summary (units consumed in current billing period)
- Invoice history (links to Razorpay-generated invoices)
- Actions: Change tier, Cancel subscription
4.4 Tier Change (Upgrade / Downgrade)
Proration amount shown before confirmation.
- Upgrade: prorated charge collected immediately via Razorpay subscription update API.
- Downgrade: credit applied to next invoice. No immediate charge. New tier effective immediately.
- On confirmation: Razorpay subscription plan updated, Subscription record updated, feature flag payload updated if tiers gate different capabilities.
4.5 Cancellation Flow
Pre-cancellation screen shows last access date, what will be lost, and (if multiple tiers exist) a downgrade alternative. On confirmation: backend calls POST /subscriptions/:id/cancel with {cancel_at_cycle_end: true}. Status stays active until period end. On the period-end webhook, feature flag is flipped OFF and status set to cancelled. User can reactivate before period end.
5. Data Model
5.1 Feature
featureId (PK, slug), featureFlagKey, displayName, description?, billingUnit, billingMethod (flat|metered|tiered|credits|one-time), recurrence (recurring|one-time), trialDays (0 = none, recurring only), configVersion, status (draft|live|archived), embedToken, publishedAt?.
5.2 Tier
tierId (PK), featureId (FK), name, basePrice, billingPeriod (monthly|annual), includedUnits? (null = unlimited), overagePricePerUnit? (null = hard-cap), hardCap, recommended, displayOrder, razorpayPlanId? (null until published).
5.3 Subscription
subscriptionId (PK), featureId (FK), tierId (FK), orgId (FK), razorpaySubscriptionId?, status (trial|active|paused|cancelled|expired), currentPeriodStart, currentPeriodEnd, cancelAtPeriodEnd, trialEndsAt?.
5.4 UsageEvent
eventId (PK), featureId (FK), orgId, quantity, idempotencyKey (unique per org+feature), reportedAt, periodBucket (YYYY-MM).
6. API Surface
6.1 Feature Config API (Admin)
| Method | Endpoint | Description |
|---|---|---|
| POST | /features | Create a new feature config (draft) |
| GET | /features/:featureId | Fetch config and all tiers |
| PATCH | /features/:featureId | Update config fields (draft only) |
| POST | /features/:featureId/publish | Publish; syncs Razorpay Plans; increments version |
| POST | /features/:featureId/rollback | Roll back to a previous config version |
| GET | /features/:featureId/preview | Return preview render data (no payments) |
| GET | /features/:featureId/export | Return full config as JSON for AI analysis |
6.2 Billing Page API (End-User, Authenticated)
| Method | Endpoint | Description |
|---|---|---|
| GET | /billing/:featureId/state | Fetch subscription state and all tiers for org |
| POST | /billing/:featureId/subscribe | Create Razorpay Subscription or Order; return checkout data |
| POST | /billing/:featureId/change-tier | Update Razorpay subscription plan; apply proration |
| POST | /billing/:featureId/cancel | Cancel subscription at period end |
| POST | /billing/:featureId/reactivate | Re-enable cancelled subscription before period end |
| GET | /billing/:featureId/invoices | Return Razorpay invoice list for the org |
6.3 Usage Reporting API
| Method | Endpoint | Description |
|---|---|---|
| POST | /usage | Report usage events (batch supported) |
| GET | /usage/:featureId/:orgId/summary | End-of-period usage aggregation for billing page display |
6.4 Webhook Events (Razorpay → BillingBuilder)
| Event | Action |
|---|---|
subscription.charged | Create/activate Subscription record; flip feature flag ON |
subscription.completed | Set status = cancelled; flip feature flag OFF |
subscription.halted | Set status = paused; notify org of payment failure |
payment.captured | Activate entitlement for one-time purchases |
payment.failed | Log failure; surface error to end user on billing page |
All webhook handlers must be idempotent. Use
razorpaySubscriptionId(orrazorpayOrderIdfor one-time) as the idempotency key. A dead-letter queue captures failed executions for retry.
7. Razorpay Integration
- 7.1 Recurring Subscriptions - One Razorpay Plan per tier × billing period on publish. At checkout, backend creates a Subscription (
plan_id,total_count,start_at);subscription_idreturned to frontend, which opens Razorpay Checkout. User authorises autopay mandate + first payment in one step. Trials: mandate collected onstart_at; first charge fires after trial. - 7.2 One-time Payments - Razorpay Order created at checkout; frontend opens Checkout with
order_id. Onpayment.captured, entitlement activated for the configured duration or perpetually. - 7.3 Tier Change (Proration) - Upgrade:
PATCH /subscriptions/:idwith newplan_id, Razorpay charges prorated difference immediately. Downgrade: credits prorated difference to next invoice. Billing page must fetch and display the proration amount before executing. - 7.4 Cancellation -
POST /subscriptions/:id/cancelwith{cancel_at_cycle_end: true}. Razorpay stops auto-renewal; subscription stays active until period end, then firessubscription.completed, triggering feature-flag deactivation.
8. Embed System
- 8.1 Config Token - Publishing generates a signed HS256 JWT encoding
featureId,configVersion,orgAllowlist,originAllowlist. Validated on every billing page API request. Tokens are versioned - older tokens continue to resolve to the config version they were issued for. - 8.2 Context Passing - iframe: query params
?orgId=&userId=&authToken=. JS Snippet:window.BillingConfig = { orgId, userId, authToken }ordata-attributes. React: propstoken,orgId,userId. - 8.3 Security - Config JWT signing secret never exposed client-side. All billing page API calls authenticated against the signed auth JWT. Origin allowlist enforced on every embed load (403 for non-allowlisted). Invalid/expired/revoked tokens render an error state - no data leaked.
9. JSON Export for AI Analysis
The Export JSON option generates a machine-readable snapshot of the full billing config for pasting into an AI assistant for pricing analysis and documentation.
9.1 JSON Contents: featureId, featureFlagKey, displayName, billingUnit, billingMethod, recurrence, trialDays, all tier definitions (name, basePrice, billingPeriod, includedUnits, overagePricePerUnit, hardCap, recommended), Razorpay Plan IDs per tier, configVersion, publishedAt.
10. Non-Functional Requirements
- 10.1 Security - Admin endpoints require internal admin auth; end-user billing calls require a valid auth JWT. Config JWTs signed HS256, secret in a secrets manager. Origin allowlists enforced on embed load and every API call.
- 10.2 Reliability and Idempotency - Idempotent webhook handlers; idempotent Razorpay Plan creation; feature-flag flips retried on failure; dead-letter queue for unprocessable events.
- 10.3 Versioning - Every publish increments
configVersion; the embed token encodes the version; old tokens resolve to their pinned version; admins can roll back; existing subscribers stay on their version until they change plans. - 10.4 Performance - Billing page renders subscription state and tier data in under 800ms for 95% of requests. Usage ingestion (
POST /usage) is asynchronous and must not block the product's critical path.
11. Open Questions
- Should a feature support both monthly and annual billing on the same tier, or should each period be a separate tier? (Product, Open)
- What currency should pricing be in? Is multi-currency a v1 requirement? (Product, Open)
- How should proration be surfaced for annual plan tier changes where the credit/charge could be large? (Design, Open)
- Should cancellation offer an immediate-effect option (forfeiting remaining period)? (Product, Open)
- What retention strategy should be shown on cancellation (e.g. win-back offer)? (Product, Open)
- Should the JSON export include subscriber counts per tier for richer AI analysis? (Engineering, Open)
12. Appendix
- 12.1 Billing Unit Catalog (v1): API calls, Tokens, Seats / Users, GB storage, GB bandwidth, Events, Renders, Minutes, Tasks, Messages, Workflows, Credits, Documents, Queries.
- 12.2 Feature Config Status Transitions: draft → live (publish) | live → archived (manual) | any version ← previous version (rollback). Archived configs are read-only; existing subscriptions run until they naturally end.
- 12.3 Subscription Status Transitions: trial → active (trial end + first charge) | active → cancelled (at period end) | active → paused (payment failure) | paused → active (retry success) | cancelled → active (reactivated before period end) | active → expired (one-time entitlement elapsed).