billing:read
Get billing status
200:
free | starter | developer | pro | scale. Accounts on the legacy enterprise plan are reported as scale.
Status values: active | past_due | canceled | trialing | incomplete
limits.requestsPerMonth is the published monthly request allotment (enforced only once metering is active). It is a number on free and null on every paid plan. null means the plan has no request cap: requests are metered and bounded by a spend cap instead (see Spend cap).
limits.maxDomainMembers is null when the plan has no member-count cap. Extra seats are billed at limits.seatPrice per seat.
usage.requestsThisMonth is the request count for the current billing period (the Stripe period when one exists, otherwise the UTC calendar month). Per-request metering is not active yet, so this currently reads 0.
Usage is recorded internally as an hourly total for each server and meter. Recording the same hour again replaces its total rather than adding to it, so retries never double-count, and an hour whose total is unchanged is not rewritten. This ledger has no public endpoint. Its visible effects are the
usage.requestsThisMonth total above and the usage Stripe bills (see Usage reporting to Stripe).Usage reporting to Stripe
Each closed hourly total is sent to Stripe as one Billing Meter event on the meter for that usage (requests, awake time or always-on hours per machine size, or egress per region tier). The event is stamped with the start of the usage hour and identified by the ledger row, so a retried send is not counted twice. Metered subscription items on a Platform subscription are billed from these events at the end of the billing period.
Reporting is switched on per deployment and sends usage only where it is enabled. It adds no endpoint and no request or response fields.
Period credit grant
When the invoice for adeveloper or pro plan is paid, the platform issues the billing account a Stripe credit grant equal to the plan fee. The grant applies to the metered usage items on the subscription (see Usage reporting to Stripe), so the plan fee is spent on usage before any usage charge is billed. It expires at the end of the period the invoice paid for. Unused credit does not roll over.
The platform also records each grant against your billing account, so your credit balance is computed without calling Stripe. The grant adds no endpoint and no request or response fields.
Spend cap
Stripe totals metered usage only when it invoices, so the platform keeps its own balance from the usage ledger and your credit grants: the credit remaining, minus the usage since the period start that credit did not cover. Seats and tax are not part of it. The balance is recomputed at least hourly. A paid account reaches its spend cap when its plan fee plus the usage that credit did not cover reaches the cap. A Free account reaches its quota at 10,000 requests or 100 awake hours in a UTC calendar month, unless a card-unlock, promotional or top-up credit still has a balance. A subscription that has beenpast_due for more than 3 days is treated the same as a reached spend cap. Refusing requests at a limit is not active yet; this release computes and stores the limit state.
GET /api/v1/billing/spend-cap returns the cap in force and PUT /api/v1/billing/spend-cap changes it. Both use session authentication.
PUT takes { "spendCapCents": 9000 }, a positive whole number of cents, or { "spendCapCents": null } to return to the default.
Top-ups
A top-up buys credit with a one-off card payment. Each top-up creates a Stripe credit grant for the amount paid, tax excluded. The grant has no expiry. It applies to metered usage after the period grant, so the credit that expires soonest is spent first. Top-ups are available in Stripe test mode only for now: with a live Stripe key,POST returns 503 and auto top-up charges nothing.
POST /api/v1/billing/top-up takes { "amountCents": 2500 } and returns 201 with a Stripe Checkout URL to send the customer to. The credit is added when Stripe confirms the payment, not when this request returns. The card is saved so that auto top-up can charge it later.
PUT /api/v1/billing/top-up sets auto top-up and GET /api/v1/billing/top-up returns it. Both use session authentication.
PUT takes { "enabled": true, "thresholdCents": 500, "amountCents": 2500 }. When your balance falls below thresholdCents, the platform charges the saved card amountCents and adds that credit. thresholdCents and amountCents may be left out when they were saved earlier. GET returns the same three values and, when the platform turned auto top-up off, disabledReason and disabledAt.
Credit and spend-cap alerts
A paid account is told by email, and by a banner on the billing page (/dashboard/billing), when it crosses a threshold. Each threshold fires once per billing period and fires again in the next period.
The email names the threshold, your current balance and cap, and links to the billing page, where you can raise the cap or top up. If several thresholds are crossed between two checks, one email for that kind of alert (credit or spend cap) names the highest. Free accounts get no alerts: they have neither credit nor a cap. Alerts are account notices, so unsubscribing from marketing email does not stop them. A failed email send is retried at the next check, which runs at least hourly. The billing page also has forms for the spend cap (the form refuses a cap below your plan fee), one-off top-ups and auto top-up.
Subscribe / upgrade plan
201:
url to complete payment.
Checkout creates the domain’s Stripe customer on first use and reuses it afterwards.
A paid Platform subscription is the plan’s price plus one usage-based item for every Platform meter (requests, awake time and always-on hours per machine size, and egress per region tier). The meter items carry no quantity: usage is reported to them as it happens. Checkout itself contains only the plan. The meter items are added to the subscription when the payment completes, and the plan is recorded on your account only after that succeeds. If adding them fails, the confirmation is retried instead of leaving a paid plan without metering. Subscriptions are created in Stripe’s flexible billing mode, which allows more items per subscription than the default 20 limit.
Checkout sells the plan with no extra seats. Extra seats on pro and enterprise are billed at limits.seatPrice per seat.
Cancel subscription
cancel_at_period_end = true in Stripe). The subscription remains active until the period ends.
Response 204: No content.
Change plan
DELETE /v1/billing/subscribe (cancel) instead.
To upgrade from the free plan, use POST /v1/billing/subscribe (checkout) instead.
Request body:
Response
204: No content.
Only the plan’s price changes, and the new price is prorated: the change creates a credit for the unused time on the old plan and a charge for the new one, both billed on the next invoice. The billing cycle does not reset. The subscription’s metered items carry over unchanged. They are billed in arrears on reported usage and are not prorated.
If the subscription has extra seats, they follow the plan. Moving between pro and enterprise keeps the seat count and re-prices the seats at the new plan’s rate. Moving to developer, which sells no seats, is refused while extra seats remain:
Billing unavailable errors
POST /v1/billing/subscribe and PATCH /v1/billing/plan price each paid plan (developer, pro, enterprise) from the ezForge Stripe catalog, looking up the plan’s catalog lookup_key when the request is made. Ready and Hub plans are priced from the same catalog. Plan prices don’t need to be configured as price IDs at deploy time. A price ID that is still configured takes precedence over the catalog lookup, so the errors below apply only to plans without one.
If the requested plan has no active price in the catalog, both endpoints fail closed instead of creating a checkout session or changing the subscription:
Plan comparison
The Scale server count is set by contract. Until contract terms apply, 50 is the default floor.
Accounts on the legacy
enterprise plan are reported as scale.
See Billing Tiers for full details.