# Platform API Reference The Platform Backend provides the foundational SaaS services: authentication, user management, organization management, billing, and configuration. **Base URL**: `https://gateway.trueportai.com/platform/api` --- ## Authentication The Platform API uses **JWT Bearer tokens** issued via the auth endpoints. There are two token types: | Token Type | Scope | Claims | |-----------|-------|--------| | **Global JWT** | Cross-tenant actions (list orgs, register) | `{sub: user_id}` | | **Scoped JWT** | Tenant-specific actions | `{sub: user_id, tid: tenant_id, role, env}` | ```mermaid stateDiagram-v2 [*] --> GlobalJWT : POST /auth/login GlobalJWT --> ScopedJWT : POST /auth/select-tenant ScopedJWT --> ScopedJWT : POST /auth/switch-environment ScopedJWT --> GlobalJWT : Token expires → re-login ``` --- ## Global Auth Endpoints Base path: `/platform/api/global/auth` --- ### `POST /register` Create a new user account. **Request Body:** ```json { "email": "dev@acme.com", "password": "SecurePassword123!", "first_name": "Jane", "last_name": "Doe" } ``` **Response** `201 Created`: ```json { "id": "usr_a1b2c3d4", "email": "dev@acme.com", "first_name": "Jane", "last_name": "Doe", "created_at": "2024-01-15T10:30:00Z" } ``` **Errors**: `400` Email already registered | `422` Validation error --- ### `POST /login` Authenticate with email and password. Returns a **global** JWT. **Request Body:** ```json { "email": "dev@acme.com", "password": "SecurePassword123!" } ``` **Response** `200 OK`: ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 1800 } ``` **Errors**: `401` Invalid credentials --- ### `POST /otp/request` Request a one-time password sent to email (passwordless login). **Request Body:** ```json { "email": "dev@acme.com" } ``` **Response** `200 OK`: ```json { "message": "OTP sent to your email" } ``` --- ### `POST /otp/verify` Verify OTP code and receive a JWT. **Request Body:** ```json { "email": "dev@acme.com", "code": "847291" } ``` **Response** `200 OK`: ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer" } ``` --- ### `POST /select-tenant` Exchange a global JWT for a **scoped JWT** tied to a specific tenant. Required before calling service APIs. **Headers**: `Authorization: Bearer {global_jwt}` **Request Body:** ```json { "tenant_id": "ten_x1y2z3w4" } ``` **Response** `200 OK`: ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "tenant_id": "ten_x1y2z3w4", "role": "admin", "environment": "prod" } ``` --- ### `POST /forgot-password` Initiate password reset. Sends a reset link via email. **Request Body:** ```json { "email": "dev@acme.com" } ``` **Response** `200 OK` (always — prevents email enumeration): ```json { "message": "If that email exists, a reset link has been sent" } ``` --- ### `POST /reset-password` Complete password reset using the token from the email link. **Request Body:** ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "new_password": "NewSecurePassword456!" } ``` **Response** `200 OK`: ```json { "message": "Password updated successfully" } ``` --- ### `PUT /password` Update password for the currently authenticated user. **Headers**: `Authorization: Bearer {jwt}` **Request Body:** ```json { "current_password": "OldPassword123!", "new_password": "NewPassword456!" } ``` **Response** `200 OK` --- ## Organization Management Base path: `/platform/api/global` --- ### `POST /tenants` Create a new organization (tenant). The caller becomes the **owner**. **Headers**: `Authorization: Bearer {global_jwt}` **Request Body:** ```json { "name": "Acme Corp", "slug": "acme-corp", "billing_email": "billing@acme.com" } ``` **Response** `201 Created`: ```json { "id": "ten_x1y2z3w4", "name": "Acme Corp", "slug": "acme-corp", "status": "active", "billing_email": "billing@acme.com", "created_at": "2024-01-15T10:30:00Z" } ``` **Errors**: `409` Slug already taken --- ### `GET /tenants` List all organizations the authenticated user belongs to. **Headers**: `Authorization: Bearer {global_jwt}` **Response** `200 OK`: ```json [ { "id": "ten_x1y2z3w4", "name": "Acme Corp", "slug": "acme-corp", "role": "owner", "status": "active" } ] ``` --- ### `GET /tenants/check-availability` Check if a tenant slug is available before creating. **Query Parameters**: `?slug=acme-corp` **Response** `200 OK`: ```json { "slug": "acme-corp", "available": false } ``` --- ## Service APIs (Tenant-Scoped) Base path: `/platform/api/service` > All service endpoints require a **scoped JWT** (`Authorization: Bearer {scoped_jwt}`). The tenant context is derived from the token's `tid` claim — no `tenant_id` in URL paths. --- ### `GET /info` Get current tenant information. **Response** `200 OK`: ```json { "id": "ten_x1y2z3w4", "name": "Acme Corp", "slug": "acme-corp", "status": "active", "billing_email": "billing@acme.com", "subscription": { "plan": "Pro", "status": "ACTIVE", "end_date": "2025-01-15T00:00:00Z" } } ``` --- ### `POST /auth/switch-environment` Switch the active environment for the current session. **Request Body:** ```json { "environment": "staging" } ``` | Value | Description | |-------|-------------| | `prod` | Production data | | `staging` | Staging/QA data | | `dev` | Development data | **Response** `200 OK`: ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "environment": "staging" } ``` --- ### Member Management #### `GET /members` List all members of the current tenant. **Response** `200 OK`: ```json [ { "id": "mem_001", "user_id": "usr_a1b2c3d4", "email": "dev@acme.com", "first_name": "Jane", "last_name": "Doe", "role": "admin", "status": "active", "joined_at": "2024-01-15T10:30:00Z" } ] ``` --- #### `POST /invites` Invite a new user to the organization by email. **Request Body:** ```json { "email": "newuser@acme.com", "role": "member" } ``` | Role | Description | |------|-------------| | `admin` | Can manage members, keys, policies | | `member` | Can use keys, view analytics | | `viewer` | Read-only analytics access | **Response** `201 Created`: ```json { "id": "inv_001", "email": "newuser@acme.com", "role": "member", "expires_at": "2024-01-22T10:30:00Z" } ``` --- #### `DELETE /members/{user_id}` Remove a member from the organization. **Response** `200 OK` **Errors**: `403` Cannot remove the owner | `404` Member not found --- ### Billing & Subscriptions #### `GET /catalog/plans` List available subscription plans. **Response** `200 OK`: ```json [ { "id": "plan_dev", "name": "Developer", "price": 0, "billing_cycle": "MONTHLY", "features": ["10,000 req/month", "1 API key", "7-day log retention"] }, { "id": "plan_pro", "name": "Pro", "price": 299, "billing_cycle": "MONTHLY", "features": ["500,000 req/month", "10 API keys", "90-day log retention", "ML violation detection"] }, { "id": "plan_enterprise", "name": "Enterprise", "price": 0, "billing_cycle": "MONTHLY", "features": ["Unlimited requests", "Unlimited keys", "365-day retention", "Custom ML models", "On-premise option"] } ] ``` --- #### `POST /subscriptions` Activate or change the subscription plan for the current tenant. **Headers**: Must be **owner** or **admin** role **Request Body:** ```json { "plan_id": "plan_pro" } ``` **Response** `201 Created`: ```json { "id": "sub_001", "plan_id": "plan_pro", "plan_name": "Pro", "status": "ACTIVE", "start_date": "2024-01-15T10:30:00Z", "end_date": "2024-02-15T10:30:00Z" } ``` --- ### Configuration Management #### `GET /configs` Retrieve the merged configuration for the current tenant and environment. **Response** `200 OK`: ```json { "resources": [ { "resrc_name": "Security", "config_groups": [ { "grp_title": "Authentication", "type": "TENANT", "sections": [ { "header_title": "MFA Settings", "configs": [ { "key": "auth.mfa_enforced", "lbl": "Enforce MFA for all users", "val": false, "gen_type": "boolean", "mod": true, "is_locked": false } ] } ] } ] } ] } ``` --- #### `PUT /configs/{key}` Update a configuration value for the current tenant. **Request Body:** ```json { "value": true } ``` **Errors**: `403` Config is locked by platform admin | `404` Config key not found --- ### Storage Configuration #### `GET /storage` Get the current storage provider configuration for the tenant. **Response** `200 OK`: ```json { "provider": "S3", "bucket": "acme-corp-audit-logs", "region": "us-east-1", "credentials_set": true } ``` --- #### `PUT /storage` Update the storage provider configuration. **Request Body (S3):** ```json { "provider": "S3", "bucket": "acme-corp-audit-logs", "region": "us-east-1", "aws_access_key_id": "AKIAIOSFODNN7EXAMPLE", "aws_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" } ``` **Request Body (Azure):** ```json { "provider": "AZURE", "azure_connection_string": "DefaultEndpointsProtocol=https;AccountName=...", "container_name": "acme-audit-logs" } ``` --- ## Admin APIs Base path: `/platform/api/admin` > Requires `is_platform_admin = true` on the authenticated user. --- ### Tenant Management #### `GET /tenants` List all tenants in the platform. **Query Parameters**: `?status=active&limit=50&offset=0` **Response** `200 OK`: ```json { "items": [ { "id": "ten_x1y2z3w4", "name": "Acme Corp", "slug": "acme-corp", "status": "active", "subscription_plan": "Pro", "member_count": 12 } ], "total": 847 } ``` --- #### `PUT /tenants/{tenant_id}/status` Update a tenant's status (suspend, activate, archive). **Request Body:** ```json { "status": "suspended", "reason": "Payment overdue" } ``` --- #### `GET /users` List all users across the platform. **Query Parameters**: `?limit=50&offset=0&email=acme.com` --- #### `GET /stats` Platform-wide statistics. **Response** `200 OK`: ```json { "total_tenants": 847, "active_tenants": 812, "total_users": 5240, "total_api_requests_24h": 1847200, "total_violations_24h": 143 } ``` --- ### Admin Configuration #### `GET /configs` Retrieve all global platform configurations. --- #### `PUT /configs/{key}` Update a global configuration value. **Request Body:** ```json { "value": "smtp.sendgrid.com", "scope": "GLOBAL", "is_locked": false } ``` --- ## Response Status Codes | Status | Meaning | |--------|---------| | `200` | OK — successful read/update | | `201` | Created — resource successfully created | | `204` | No Content — successful delete | | `400` | Bad Request — validation error | | `401` | Unauthorized — missing or invalid JWT | | `403` | Forbidden — insufficient role/permissions | | `404` | Not Found — resource does not exist | | `409` | Conflict — duplicate resource (e.g. slug taken) | | `422` | Unprocessable Entity — schema validation failed | | `500` | Internal Server Error |