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}

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:

{
  "email": "dev@acme.com",
  "password": "SecurePassword123!",
  "first_name": "Jane",
  "last_name": "Doe"
}

Response 201 Created:

{
  "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:

{
  "email": "dev@acme.com",
  "password": "SecurePassword123!"
}

Response 200 OK:

{
  "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:

{
  "email": "dev@acme.com"
}

Response 200 OK:

{
  "message": "OTP sent to your email"
}

POST /otp/verify

Verify OTP code and receive a JWT.

Request Body:

{
  "email": "dev@acme.com",
  "code": "847291"
}

Response 200 OK:

{
  "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:

{
  "tenant_id": "ten_x1y2z3w4"
}

Response 200 OK:

{
  "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:

{
  "email": "dev@acme.com"
}

Response 200 OK (always — prevents email enumeration):

{
  "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:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "new_password": "NewSecurePassword456!"
}

Response 200 OK:

{
  "message": "Password updated successfully"
}

PUT /password

Update password for the currently authenticated user.

Headers: Authorization: Bearer {jwt}

Request Body:

{
  "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:

{
  "name": "Acme Corp",
  "slug": "acme-corp",
  "billing_email": "billing@acme.com"
}

Response 201 Created:

{
  "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:

[
  {
    "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:

{
  "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:

{
  "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:

{
  "environment": "staging"
}

Value

Description

prod

Production data

staging

Staging/QA data

dev

Development data

Response 200 OK:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "environment": "staging"
}

Member Management

GET /members

List all members of the current tenant.

Response 200 OK:

[
  {
    "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:

{
  "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:

{
  "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:

[
  {
    "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:

{
  "plan_id": "plan_pro"
}

Response 201 Created:

{
  "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:

{
  "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:

{
  "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:

{
  "provider": "S3",
  "bucket": "acme-corp-audit-logs",
  "region": "us-east-1",
  "credentials_set": true
}

PUT /storage

Update the storage provider configuration.

Request Body (S3):

{
  "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):

{
  "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:

{
  "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:

{
  "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:

{
  "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:

{
  "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