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 UIusage.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.
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.
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.
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).
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.