API Reference: Shell
This document details all RESTful API endpoints for the Shell — the central identity, billing, and orchestration hub.
Base path: All endpoints are prefixed with
/api.
1. Auth — Public
No authentication required.
GET /api/auth/providers
List all enabled OAuth identity providers.
Response: { "code": 200, "data": [{ "providerId": "google", "type": "oauth2" }] }
GET /api/auth/login
Get the OAuth authorization URL to redirect the user to.
Query: ?provider=<providerId> (optional)
Response: { "code": 200, "data": { "loginUrl": "https://..." } }
GET /api/auth/callback
OAuth callback handler. Validates code and state, creates session, redirects to app.
Query: code, state (optional)
POST /api/auth/register
Register a new user and provision their organization.
Body:
{
"email": "string",
"username": "string",
"password": "string (min 8 chars)",
"firstName": "string",
"lastName": "string",
"plan": "HOBBY | PRO | ENTERPRISE"
}POST /api/auth/local-login
Login with username/email and password.
Body: { "usernameOrEmail": "string", "password": "string" }
Response:
{
"accessToken": "string",
"refreshToken": "string",
"expiresIn": 3600,
"tokenType": "Bearer",
"user": { "id": "uuid", "email": "string", "username": "string", "organizationId": "uuid" }
}POST /api/auth/refresh
Refresh an expired access token using a refresh token.
Body: { "refreshToken": "string" }
Response: { "accessToken": "string", "expiresIn": 3600 }
GET /api/.well-known/jwks.json
Shell JWKS endpoint. Used by satellite services to verify Shell-issued RS256 JWTs.
Response: { "keys": [...] }
2. Auth — Session & Token Exchange
JWT auth required.
POST /api/auth/exchange
Exchange Shell JWT for a service-scoped JWT. Called by satellite services after receiving the Shell token via BroadcastChannel.
Body: { "service": "string" } (service slug, e.g. "drive")
Response: { "accessToken": "string", "expiresIn": 3600, "service": "string" }
POST /api/auth/exchange-keycloak
Exchange a Keycloak token for a Shell JWT. No authentication required. Used for Keycloak SSO flows.
Body: { "keycloakToken": "string", "serviceId": "string (optional)" }
Response: { "accessToken": "string", "expiresIn": 3600, "service": "string" }
POST /api/auth/exchange-for-service
Exchange Shell JWT for a remote service JWT via gRPC gateway. JWT auth required.
Body: { "keycloakToken": "string", "serviceId": "string" }
Response: { "accessToken": "string", "tokenType": "Bearer", "expiresIn": 3600, "service": "string" }
GET /api/auth/logout
Invalidate the current session and blacklist the JWT.
Response: { "message": "Logged out successfully" }
3. Auth — Account Management
JWT auth required.
GET /api/auth/me
Get the current user's profile and organization context.
Response:
{
"id": "uuid",
"email": "string",
"username": "string",
"firstName": "string",
"lastName": "string",
"organizationId": "uuid",
"organization": { "id": "uuid", "name": "string", "slug": "string", "type": "string", "subscriptionPlan": "string" },
"preferences": {}
}PUT /api/auth/me/preferences
Update the current user's UI preferences (theme, language, etc.).
Body: Record<string, unknown>
Response: Updated preferences object.
POST /api/auth/change-password
Change the current user's password.
Body: { "currentPassword": "string", "newPassword": "string (min 8 chars)" }
Response: 204 No Content
POST /api/auth/request-password-reset
Request a password reset email.
Body: { "email": "string" }
Response: 204 No Content
POST /api/auth/confirm-password-reset
Complete password reset using the token received by email.
Body: { "token": "string", "newPassword": "string (min 8 chars)" }
Response: 204 No Content
4. Users
JWT auth required. All endpoints are permission-gated.
GET /api/users
List users. Requires USERS_LIST permission.
Query: ?filter (JSON filter string)
POST /api/users
Create a new user in the organization. Requires USERS_WRITE permission.
Response: 201 Created
GET /api/users/:id
Get a user with their assigned roles. Requires USERS_READ permission.
PUT /api/users/:id
Update user fields (name, status, etc.). Requires USERS_WRITE permission.
DELETE /api/users/:id
Delete a user. Requires USERS_DELETE permission.
Response: 204 No Content
GET /api/users/:id/roles
Get role IDs assigned to a user. Requires USERS_READ permission.
Response: ["uuid", ...]
POST /api/users/:id/roles
Assign one or more roles to a user. Requires USERS_WRITE permission.
Body: { "roleIds": ["uuid", ...] }
Response: 201 Created
DELETE /api/users/:id/roles/:roleId
Remove a role from a user. Requires USERS_WRITE permission.
Response: 204 No Content
5. Organizations
JWT auth required. Permission-gated.
GET /api/organizations
List organizations. Requires ORGANIZATIONS_LIST permission.
GET /api/organizations/:id
Get an organization with its users. Requires ORGANIZATIONS_READ permission.
PUT /api/organizations/:id
Update organization fields. Requires ORGANIZATIONS_WRITE permission.
Body: { "name"?: "string", "type"?: "string", "status"?: "string", "domain"?: "string" }
PUT /api/organizations/:id/subscription
Override an organization's subscription plan (admin). Requires SUBSCRIPTIONS_ADMIN permission.
Body: { "planCode": "string" }
Response: { "success": true }
6. RBAC
JWT auth required.
GET /api/roles
List all roles available in the organization.
GET /api/permissions
List all permission codes across all registered apps.
POST /api/roles/:id/permissions
Assign a set of permissions to a role.
7. Subscriptions
JWT auth required. Organization context is extracted from the JWT.
GET /api/subscriptions/current
Get the current organization's active subscription and status.
GET /api/subscriptions/usage
Get consumption vs. quota for all tracked limits.
POST /api/subscriptions/upgrade
Create a Stripe Checkout session for a plan upgrade.
Body: { "planCode": "string", "interval": "monthly | yearly" }
Response: { "checkoutUrl": "string" }
POST /api/subscriptions/upgrade-direct
Upgrade directly using a saved payment method (no redirect).
Body: { "planCode": "string", "interval": "monthly | yearly", "paymentMethodId": "string" }
Response: { "success": true }
GET /api/subscriptions/portal
Get the Stripe Customer Portal URL for managing invoices and cards.
Query: ?returnUrl
Response: { "portalUrl": "string" }
POST /api/subscriptions/check-limit
Check whether the organization has reached a usage limit.
Body: { "limitKey": "string" }
POST /api/subscriptions/consume
Increment a usage counter by 1.
Body: { "limitKey": "string" }
Response: { "success": true }
POST /api/subscriptions/payment-methods/setup
Create a Stripe SetupIntent for saving a new card.
Response: { "clientSecret": "string" }
GET /api/subscriptions/payment-methods
List all saved payment methods for the organization.
DELETE /api/subscriptions/payment-methods/:paymentMethodId
Remove a saved payment method.
Response: { "success": true }
PUT /api/subscriptions/payment-methods/:paymentMethodId/default
Set a payment method as the default.
Response: { "success": true }
POST /api/subscriptions/webhook
Stripe webhook handler. No auth required — validated via stripe-signature header.
8. Plans
JWT auth required. Permission-gated.
GET /api/plans
List all subscription plans. Requires PLANS_LIST permission.
GET /api/plans/:id
Get plan details including included apps and limits. Requires PLANS_READ permission.
POST /api/plans
Create a new plan (admin only).
Body:
{
"code": "string",
"name": "string",
"tagline": "string (optional)",
"monthlyPrice": 0,
"yearlyPrice": 0,
"section": "individual | business",
"ctaLabel": "string",
"ctaLink": "string",
"features": [{ "label": "string", "included": true }],
"status": "active | hidden | deprecated",
"serviceIds": ["uuid"]
}Response: 201 Created
PUT /api/plans/:id
Update plan fields. Requires PLANS_WRITE permission.
GET /api/plans/:id/limits
Get all quota limits defined for a plan. Requires PLANS_READ permission.
PUT /api/plans/:id/limits
Set quota limits for a plan (admin only).
Body: { "limits": [{ "limitKey": "string", "limitValue": 100, "period": "monthly" }] }
POST /api/plans/:id/sync-stripe
Sync plan pricing to Stripe products and price objects (admin only).
9. Apps / Service Registry
JWT auth required. Admin only.
GET /api/admin/apps
List all registered SCS apps.
Query: ?filter (JSON filter string)
GET /api/admin/apps/:id
Get a single registered app by ID.
POST /api/admin/apps
Register a new app with full metadata.
Body: { "slug", "name", "type", "apiUrl", "uiUrl"?, "icon"?, "description"?, "category"?, "status"?, "metadata"? }
Response: 201 Created
POST /api/admin/apps/register-remote
Register an app by providing only its UI entry URL. Shell fetches metadata from the remote automatically.
Body: { "uiUrl": "string (URL)", "slug"?: "string" }
Response: 201 Created
PUT /api/admin/apps/:id
Update an existing app registration.
DELETE /api/admin/apps/:id
Remove an app from the registry.
Response: 204 No Content
10. Onboarding
POST /api/onboarding (Public)
Submit a B2B enterprise onboarding request.
Body:
{
"orgName": "string",
"orgType": "string",
"contactEmail": "string",
"firstName": "string",
"lastName": "string",
"applicantEmail": "string",
"contactPhone": "string (optional)",
"companySize": 100,
"ssoInterest": true,
"subscriptionPlan": "string (optional)"
}Response: 201 Created
GET /api/onboarding
List all onboarding requests. Requires ONBOARDING_LIST permission.
GET /api/onboarding/:id
Get a single onboarding request. Requires ONBOARDING_READ permission.
PUT /api/onboarding/:id/approve
Approve a request — provisions the organization and admin user. Requires ONBOARDING_APPROVE permission.
PUT /api/onboarding/:id/reject
Reject an onboarding request. Requires ONBOARDING_REJECT permission.
Body: { "reason": "string" }
11. Config (Public Discovery)
GET /api/config/apps (Public)
Returns active apps for the Shell Launchpad UI.
GET /api/config/plans (Public)
Returns active plans for the public pricing page.
GET /api/config (Admin only)
Returns internal infrastructure configuration (Keycloak, MinIO, Redis).
12. Audit
GET /api/admin/audit
Get recent platform audit log entries. Requires USERS_LIST permission.
Query: ?limit (1–50, default 20)
13. S2S Gateway (gRPC/Connect)
Service-to-Service communication channel. Requires a token with aud: "shell-rbac".
RbacService.CheckPermission
Verifies whether a user (sub) can perform an action (act) on a resource (obj). Called by satellite services to validate permissions without a REST roundtrip.
14. Standard Error Codes
| Status Code | Description |
|---|---|
401 Unauthorized | Missing or invalid Shell JWT. |
403 Forbidden | Insufficient RBAC permissions for the requested action. |
404 Not Found | User, role, organization, or plan does not exist. |
409 Conflict | Email or slug already in use. |
429 Too Many Requests | Rate limit exceeded for auth or billing endpoints. |
500 Server Error | Identity provider or database failure. |