Billing and credits
One $20/month plan, a prepaid credit wallet per project, and a ledger that refuses to go below zero.
Camplax keeps money boring. There is one plan — $20/month for platform access — and one prepaid credit wallet per project for the metered features. There is no free tier and no per-seat pricing; a card is required at signup.
The plan
$20/month covers what the platform does for every project: hosting, the database, sign-in, storage, deploys, previews, domains and secrets, inside the launch caps. The Billing page lists every project you can see, each one's monthly cost, and the workspace total. Seats in the billing role can see this page without touching anything else.
Credits
Variable-cost features — AI calls, Lee Pro turns, heavy usage — spend from a prepaid wallet, one per project, denominated in dollars:
- Top up on the Billing page through Stripe Checkout. The payment lands on a signature-verified webhook and posts a
stripe_checkoutcredit to the ledger — deduplicated by Stripe payment id, so a retried webhook cannot double-credit. Live Stripe money can only credit a live project; test money only a test-mode project. - Spend happens through a single-writer ledger. Every debit is one atomic statement that computes the running balance and refuses if the wallet cannot cover it.
- At zero, it stops. Debits fail closed — no overdraft, no surprise invoice at the end of the month. The error tells you to top up or switch back to the included model.
- Refunds work the same way. A reserved-but-unspent hold posts back as a positive delta on the same ledger.
- Every row carries an idempotency key. Replaying a call returns the original row instead of moving the balance twice.
The checkout offers preset top-up amounts — $5, $20 and $50 on the pricing page — but the wallet itself just holds a dollar balance; you are not buying a fixed bundle that expires.
Reading the ledger
GET /v1/billing/credits/:slug → { "balance": 12.40, "ledger": [ …last 50 rows… ] }
GET /v1/billing/summary → { "projects": [ … ], "totalMonthlyCost": 40 }
POST /v1/billing/credits/:slug is the support escape hatch, not a self-serve mint — it requires the owner role, a positive delta, reason: "support_grant", and an Idempotency-Key header so a retried call cannot grant twice. The read routes above accept a console session in the owner or billing role; project API keys cannot read the wallet.
What you will never see
- No overdraft. Balance hits zero, the billable feature stops, and the API says so plainly.
- No surprise metering. Top-ups are explicit; nothing silently charges the card mid-month.
- No cross-project leakage. Each wallet is scoped to one project, and the Stripe webhook ignores events it cannot tie to a real project.
Related docs
- Teams and roles — the
billingseat. - AI gateway — where credits actually get spent.
- API keys — which credentials can reach billing routes (none of the project-scoped ones).