Skip to main content
DocsAPI ReferenceTenant API
Back to docs

Tenant API

Tenant resolution, branding, custom domains

api
tenant

Tenant API

Base path: /api/tenant

Manages multi-tenant resolution and whitelabel brand configuration.


GET /api/tenant/current

Resolve the current tenant from the request hostname. The server's tenant middleware matches the Host header against the domain and custom_domain columns of the tenants table.

Auth: None (public) Feature gate: None

Response (tenant found):

{
  "success": true,
  "data": {
    "isDefault": false,
    "id": "tenant-uuid",
    "slug": "acme-school",
    "name": "Acme School",
    "brandConfig": {
      "primaryColor": "#6366f1",
      "logoUrl": "https://cdn.example.com/logo.png",
      "faviconUrl": null,
      "appName": "Acme Learning",
      "customCss": null
    },
    "plan": "premium"
  }
}

Response (no tenant / default):

{
  "success": true,
  "data": {
    "isDefault": true,
    "brandConfig": {
      "primaryColor": "#6366f1",
      "logoUrl": null,
      "faviconUrl": null,
      "appName": "Creatiq",
      "customCss": null
    }
  }
}
FieldTypeDescription
isDefaultbooleantrue when no tenant matched the hostname
idstringTenant UUID (only when isDefault is false)
slugstringURL-safe tenant identifier
namestringTenant display name
brandConfigBrandConfigWhitelabel configuration (see below)
planstringSubscription plan (free, pro, premium, etc.)

BrandConfig object

FieldTypeDescription
primaryColorstringHex color code (e.g. #6366f1). Default: #6366f1
logoUrlstring | nullURL to the tenant logo image
faviconUrlstring | nullURL to the tenant favicon
appNamestringApplication name shown in the UI. Default: Creatiq
customCssstring | nullCustom CSS injected into the frontend. Max 50,000 characters.

Errors:

StatusBodyCondition
500{ "success": false, "error": "Failed to resolve tenant" }Database error

PUT /api/tenant/brand

Update brand configuration for the current tenant. Merges the provided fields into the existing brand_config JSONB column.

Auth: Required (JWT) Feature gate: whitelabel (Premium plan only)

Request body:

All fields are optional. Only provided fields are updated.

{
  "primaryColor": "#0ea5e9",
  "logoUrl": "https://cdn.example.com/new-logo.png",
  "faviconUrl": "https://cdn.example.com/favicon.ico",
  "appName": "Acme Learning Hub",
  "customCss": ".header { background: #000; }"
}
FieldTypeRequiredConstraints
primaryColorstringNoHex format: #RRGGBB
logoUrlstring | nullNoValid URL, max 1000 characters
faviconUrlstring | nullNoValid URL, max 1000 characters
appNamestringNoMin 1, max 100 characters
customCssstring | nullNoMax 50,000 characters

Response:

{
  "success": true,
  "data": {
    "brandConfig": {
      "primaryColor": "#0ea5e9",
      "logoUrl": "https://cdn.example.com/new-logo.png",
      "faviconUrl": "https://cdn.example.com/favicon.ico",
      "appName": "Acme Learning Hub",
      "customCss": ".header { background: #000; }"
    }
  }
}

Errors:

StatusBodyCondition
400{ "success": false, "error": "Validation error: ..." }Zod validation failure
403Forbiddenwhitelabel feature not enabled for the tenant's plan
404{ "success": false, "error": "Tenant not found" }No tenant resolved from hostname
500{ "success": false, "error": "Failed to update brand config" }Database error

PUT /api/tenant/domain

Update the custom domain for the current tenant. After updating, the tenant will be resolved when requests arrive at this domain.

Auth: Required (JWT) Feature gate: whitelabel (Premium plan only)

Request body:

{
  "customDomain": "learn.acmeschool.com"
}
FieldTypeRequiredConstraints
customDomainstringYesMin 3, max 500 characters. Lowercase alphanumeric with dots and hyphens. Pattern: ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$

Response:

{
  "success": true,
  "data": {
    "customDomain": "learn.acmeschool.com"
  }
}

Errors:

StatusBodyCondition
400{ "success": false, "error": "Validation error: ..." }Invalid domain format
403Forbiddenwhitelabel feature not enabled for the tenant's plan
404{ "success": false, "error": "Tenant not found" }No tenant resolved from hostname
500{ "success": false, "error": "Failed to update custom domain" }Database error or unique constraint violation
Back to docsdocs/product/api/tenant.md