← Docs

Billing & plans

Every Organization has exactly one real Plan — price, limits, and feature flags, never inferred from a separate tier label. See the public pricing page for the real, current catalog, or fetch it directly:

GET /api/v1/billing/          -> { plan, usage, onehux_pay }  (your own Organization)
GET /api/v1/billing/plans/    -> the full real catalog, for the upgrade UI

Usage is tracked, not estimated

usage.applications.count and usage.mau.count are computed live from real rows (a live Application count; monthly active users counted from real sign-in activity in the current period) — never a cached estimate that can drift from what actually happened.

Overage gates creation, never authentication

Reaching Plan.max_applications blocks creating another Application (a real 400 from POST /api/v1/applications/) — it never blocks anyone from signing in, and never disables an Application you've already registered. The same principle applies to every other plan-gated feature (custom domain, white-label branding, webhooks, API keys, SCIM): the check happens server-side, at the point of use, not just hidden in this dashboard's UI, and a downgrade takes effect immediately on the next check, not just on new creation attempts.

Upgrading (and downgrading) — a real OneHux Pay checkout

POST /api/v1/billing/upgrade/  { "plan_slug": "growth-monthly" }
-> { authorization_url, reference }

Redirects the browser to Paystack's own hosted checkout page (authorization_url, forwarded by OneHux Pay — no card details ever touch this platform's own servers). The Organization's Plan only actually changes once OneHux Pay confirms the subscription via a real, signature-verified webhook, never optimistically on redirect — closing the checkout tab without completing payment leaves the Organization on its current plan, not a half-upgraded state.

The same endpoint handles switching to a cheaper paid tier, too: OneHux Pay's subscriptions API has no period-end date to schedule a future downgrade against, so every plan-to-plan move — up or down — is a fresh real checkout, applied the moment OneHux Pay confirms it, never scheduled.

Cancelling

POST /api/v1/billing/cancel/

Cancels the real OneHux Pay subscription first; the Organization only drops to the free plan once that cancellation is confirmed — never charged again after a successful cancellation request, and never silently downgraded while a subscription might still be active. The same real cancellation path is reused, not reimplemented, when an Organization is deleted outright (see Organizations & Applications — a OneHux Pay failure during that flow blocks and rolls back the whole deletion, rather than deleting the Organization while still billing it).

What's not built yet

Enterprise pricing is not self-service — its Plan row has no fixed price (null means "contact us"), negotiated outside this flow entirely. That's a deliberate business decision, not a gap.