Billing

Metered domain usage, plan, and quota for the caller's tenant

The tenant is derived from the authenticated credential, never a query parameter. ?period= defaults to the current UTC calendar month.

get/billing/usage

Request

  • Base URL: https://api.customdomain.ai/v1
  • URL: https://api.customdomain.ai/v1/billing/usage
  • Auth: one of:
    • HTTP bearer
    • HTTP bearer

Query parameters

periodstring
Example:2026-07

Response

Usage

orgstring required

The tenant the usage belongs to, derived from the authenticated credential.

periodstring required

UTC calendar month, YYYY-MM.

usedinteger required

metered domain connections this period

mode'test' | 'live' | '' required

The Stripe key mode the control plane is running against; empty when billing is unconfigured.

plan'starter' | 'startup' | 'growth' | 'premium' | 'enterprise' | 'free'

free is retired: legacy workspaces still carry it until they subscribe, and it cannot be bought or assigned.

plan_namestring

The plan's display name, e.g. Growth.

quotainteger

The plan's included domain connections for ONE billing MONTH (DomainsPerYear ceiling-divided by 12; 0 = unlimited). Compare used against this. limit carries the identical value.

limitinteger

Alias of quota, carrying the identical value. This schema declared limit while the handler emitted only quota; rather than break either reader, both are emitted. Prefer quota in new code.

meteredboolean

true on tiers priced for overage (growth, enterprise). It carries NO enforcement meaning; it describes pricing only. Read hard_cap for the plan's refusal policy and quota_enforced for whether a 402 is possible right now. Never branch on this field.

hard_capboolean

Whether this PLAN refuses connections past quota (402 quota_exceeded) rather than allowing and recording them as overage. true only on the entry tiers: starter ($10 a month) and the retired free. Every larger tier (startup, premium, growth, enterprise) is false and is never refused at quota. The refusal reaches the tenant's own end users through the embedded widget, so it is worded neutrally for them. Independent of the deployment's BILLING_ENFORCE_QUOTA; combine the two via quota_enforced.

quota_state'ok' | 'approaching' | 'at_limit'

The server's classification of used against quota. approaching means at or past 80% of quota; at_limit means used >= quota. Always ok on an unlimited plan (quota <= 0).

quota_enforcedboolean

Whether an over-quota connection would actually be refused with 402 quota_exceeded right now. True only when the plan's hard_cap is set AND the deployment enables enforcement. A client cannot infer the second half, which is why this is served rather than derived. On every paid tier it is false at any usage level. A tenant may therefore be at_limit with quota_enforced: false (over the line with nothing refused), so never treat at_limit alone as "blocked". Always false on an unlimited plan.

remaininginteger

quota - used, floored at 0. Omitted entirely on an unlimited plan, where no remainder is meaningful.

statusstring

Subscription status mirrored from Stripe, e.g. active, past_due (empty for a workspace that has not subscribed). Owners and admins only.

has_billing_accountboolean

true when a Stripe customer exists for the org, i.e. the billing portal is available. Owners and admins only.

billing_state'trialing' | 'active' | 'past_due' | 'grace' | 'blocked' | 'comped' | 'canceled' | 'legacy_free'

A workspace's billing state, evaluated from its record and the clock. trialing and active are a running Stripe subscription; past_due is a failed payment Stripe is still retrying (nothing is refused); grace is a legacy Free workspace (or an operator extension) inside its grace period; legacy_free is a Free workspace whose grace has not started; comped is an operator comp; blocked and canceled refuse new connections (402 billing_required) while live domains keep working. A new workspace (blocked, reason setup_required) is refused only once its first domain is connected: see first_domain_free.

Example response

{
  "period": "2026-07"
}

Changes

No recorded changes to this operation across all 1 revision of this API.