Organization Management ~5 min
Overview
Every user belongs to one organization. Organizations are provisioned automatically at registration or onboarding approval, and linked to a subscription plan that controls which services and features are available.
Organization model
| Field | Type | Values |
|---|---|---|
id | uuid | Primary key |
name | string | Display name |
slug | string | URL-safe unique identifier |
type | enum | ENTERPRISE, STARTUP, INDIVIDUAL, NON_PROFIT, GOVERNMENT |
status | enum | ACTIVE, INACTIVE, SUSPENDED |
planId | uuid | FK → subscription_plans |
createdAt | timestamp |
Auto-provisioning at registration
When a user registers via OAuth or the register endpoint, Shell automatically provisions an organization:
Email domain = gmail.com / outlook.com / yahoo.com / ... (public domain)
→ INDIVIDUAL org created for this user only
Email domain = acme.com (private domain)
→ Check for existing ENTERPRISE org with that domain
→ If found: add user to existing org
→ If not: create new ENTERPRISE orgDefault plan
New organizations are assigned the default plan (typically the free/community tier). Use the subscription upgrade flow to move to a paid plan.
List organizations
GET /api/organizations
Authorization: Bearer <shell-jwt> (requires organizations:list)Get an organization
GET /api/organizations/:id
Authorization: Bearer <shell-jwt> (requires organizations:read)Returns the organization plus its member users.
Update an organization
PUT /api/organizations/:id
Authorization: Bearer <shell-jwt> (requires organizations:write)
Content-Type: application/json
{
"name": "Acme Corp",
"type": "ENTERPRISE",
"status": "ACTIVE"
}| Field | Description |
|---|---|
name | Display name |
type | Organization type |
status | ACTIVE | INACTIVE | SUSPENDED |
Admin: override subscription plan
Bypass Stripe and directly assign a plan to an organization (admin use only):
PUT /api/organizations/:id/subscription
Authorization: Bearer <shell-jwt> (requires subscriptions:admin)
Content-Type: application/json
{
"planCode": "enterprise",
"reason": "Manual override for trial extension"
}Admin only
This endpoint requires the subscriptions:admin permission. It bypasses Stripe — no payment is processed. Use for trials, demos, or manual adjustments.
The change is recorded in organization_plan_history with a timestamp.
Organization ↔ Plan relationship
organizations (planId) ──► subscription_plans
│
plan_services ──► services
│
plan_limits (resource, limitValue)
│
plan_usage (resource, usageValue per org)- Services visible to an org = services in their plan's
plan_services - Usage limits enforced per resource key (e.g.
employees,documents) - Plan history recorded every time the plan changes