End-to-End Billing Setup: From Zero to Working Credits in 10 Steps
Complete walkthrough building a working billing system with OurVibe — metric, metering rule, plan, variant, customer, subscription, and usage in one linear sequence.
End-to-End Billing Setup
Pattern: the full billing pipeline, one step at a time.
The goal
Go from an empty QuotaStack tenant to a working billing system where a customer has a subscription, credit grants fire automatically, usage debits credits, and entitlement checks gate access.
We’ll use OurVibe (a chat companion app) as the running example. By the end, Alice (a customer) will have a weekly subscription that grants 50 credits, and each chat message will cost 1 credit.
Phase 1: Define what you charge for
Step 1: Create a billable metric
A billable metric is a named action you charge for. OurVibe charges per message:
POST /v1/billable-metrics
Idempotency-Key: metric:chat_message
{ "key": "chat_message", "name": "Chat Message" }
The key is the stable identifier you’ll reference everywhere — metering rules, usage events, entitlement checks. It defaults to type: metered (credit-based).
Step 2: Set the price with a metering rule
POST /v1/metering-rules
Idempotency-Key: rule:chat_message
{ "billable_metric_key": "chat_message", "cost_type": "per_unit", "unit_cost": 1000 }
1,000mc per unit = 1 credit per message. Now QuotaStack knows: when a usage event arrives for chat_message, debit 1,000mc from the customer’s balance.
Phase 2: Build the plan
Step 3: Create a plan and variant
The plan is the product (“OurVibe Chat”). The variant is the specific pricing tier (“Weekly Standard” — prepaid, weekly billing cycle):
POST /v1/plans
Idempotency-Key: plan:ourvibe-chat
{ "name": "OurVibe Chat", "description": "Companion chat subscription plans" }
POST /v1/plans/{plan_id}/variants
Idempotency-Key: variant:weekly-standard
{ "name": "Weekly Standard", "billing_cycle": "weekly", "billing_mode": "prepaid" }
Step 4: Attach a credit grant template
Tell QuotaStack to automatically grant 50,000mc (50 credits) every week:
POST /v1/plans/{plan_id}/variants/{variant_id}/credit-grants
Idempotency-Key: grant-template:weekly-50k
{
"credits": 50000,
"grant_interval": "billing_cycle",
"grant_type": "recurring",
"expires_after_seconds": 604800,
"rollover_percentage": 0,
"priority": 0
}
expires_after_seconds: 604800 = 7 days. Each grant expires when the next one arrives — no hoarding. rollover_percentage: 0 means unused credits don’t carry over.
At this point you have a complete plan: metric → pricing → variant → automatic grants. Nothing has happened yet because no customer is subscribed.
Phase 3: Onboard a customer
Step 5: Create a customer
POST /v1/customers
Idempotency-Key: customer:user_alice
{ "external_id": "user_alice", "display_name": "Alice" }
Step 6: Subscribe them
After Alice pays via your payment provider (Stripe, Razorpay, etc.), activate the subscription:
POST /v1/subscriptions
Idempotency-Key: sub:alice-weekly-001
{ "external_customer_id": "user_alice", "plan_variant_id": "{variant_id}" }
On activation, QuotaStack immediately fires the credit grant template — Alice now has 50,000mc (50 credits). The subscription status is active, with current_period_end set to one week from now.
Phase 4: Use it
Step 7: Check entitlement before each message
GET /v1/customer-by-external-id/user_alice/entitlements/chat_message
{
"allowed": true,
"balance": 50000,
"estimated_cost": 1000,
"balance_after": 49000
}
allowed: true means Alice can send a message. balance_after: 49000 is what her balance will be afterward. If allowed were false, your UI shows “you’ve used all your messages this week.”
Step 8: Record usage
Alice sends 5 messages. Your backend fires a usage event for each (or batches them):
POST /v1/usage
Idempotency-Key: usage:msg_001
{
"external_customer_id": "user_alice",
"billable_metric_key": "chat_message",
"units": 5,
"idempotency_key": "msg_batch_001"
}
Returns 202 Accepted — usage events process asynchronously. 5 × 1,000mc = 5,000mc will be debited within seconds.
Step 9: Verify the balance
GET /v1/customer-by-external-id/user_alice/credits
{
"balance": 45000,
"lifetime_earned": 50000,
"lifetime_consumed": 5000
}
50,000 - 5,000 = 45,000mc remaining. Alice has 45 messages left this week.
What you’ve built
chat_message metric → "what we charge for"
↓ priced by
per_unit metering rule → "1,000mc per message"
↓ used by
Weekly Standard variant → "50,000mc/week, expires in 7 days"
↓ subscribed by
Alice → "active, 45,000mc remaining"
↓ gated by
entitlement check → "allowed: true"
↓ consumed by
usage events → "5 messages = 5,000mc debited"
The metric defines WHAT you track. The metering rule defines HOW MUCH it costs. The plan variant defines WHO gets credits and when. The subscription binds a customer to a variant. Entitlements gate access. Usage events consume credits.
Next steps
- Add variable companion pricing — charge premium companions more by varying the
unitsfield - Set up webhooks to react to
subscription.renewal_dueandcredit.consumedevents - Add a wallet for pay-as-you-go overflow when weekly credits run out
- Use reservations for long-running AI calls that might fail mid-generation
Loading…