The catalogue lives in @repo/plans (LIMIT_DEFINITIONS / planCatalogue), so the pricing page, the members page,
the admin Plans & limits page and the API all read the same values. Categories are Listings, Website, CRM,
Marketing, SEO, Team and AI.
Rows marked planned in the admin table belong to a later stage. The limit is visible now, but its guard is switched on when the feature lands.
requireModule(); a missing module returns PLAN_REQUIRED.assertWithinLimit(); an exhausted limit returns LIMIT_EXCEEDED.organisation_usage and are incremented only after the action succeeds.All admin routes are off unless ADMIN_API_TOKEN is set. Send Authorization: Bearer <token>.
| Method | Path | Purpose |
|---|---|---|
GET | /v1/plans | Public catalogue (plans, modules, categories, limits). |
GET | /v1/admin/organisations/:id/plan | An agency’s plan, modules, overrides and limits. |
PUT | /v1/admin/organisations/:id/plan | Set the plan and module overrides; audited. Body: { "plan": "solo", "overrides": { "crm": true } }. |
GET | /v1/admin/organisations/:id/usage | Current usage against every enforced limit. |
Unknown modules, non-boolean overrides and unknown plans return 400. An unknown agency returns 404.