Skip to main content

Tenant Management

Manage tenant lifecycle including creation, updates, and status changes.

Get Current Tenant

Retrieve the tenant associated with the current user.

Endpoint

GET /tenants/current

Response (200 OK)

{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "Acme Corporation",
"slug": "acme",
"status": "ACTIVE",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}

Get Tenant by ID

Retrieve a specific tenant (must be your own tenant).

Endpoint

GET /tenants/:id

Response (200 OK)

{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "Acme Corporation",
"slug": "acme",
"status": "ACTIVE",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}

Error: Cross-Tenant Access

{
"type": "https://api.cortex.purplelab.ai/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Tenant not found"
}
Security

Attempting to access another tenant returns 404, not 403. This prevents information leakage.

Update Tenant

Update tenant properties (requires admin permissions).

Endpoint

PATCH /tenants/:id

Request

{
"name": "Acme Corp International"
}

Response (200 OK)

{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "Acme Corp International",
"slug": "acme",
"status": "ACTIVE",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}

Updatable Fields

FieldTypeDescription
namestringTenant display name
statusstringTenant status (admin only)
caution

The slug field cannot be updated after creation as it may be used in URLs.

Tenant Statuses

StatusDescription
ACTIVENormal operation
SUSPENDEDTemporarily disabled (users cannot log in)
INACTIVEPermanently disabled

Status Transitions

ACTIVE ──────────────────────▶ SUSPENDED
▲ │
│ │
└──────────────────────────────┘

ACTIVE ──────────────────────▶ INACTIVE
SUSPENDED ───────────────────▶ INACTIVE

Once a tenant is INACTIVE, it cannot be reactivated.

Code Examples

TypeScript

interface Tenant {
id: string;
name: string;
slug: string;
status: 'ACTIVE' | 'SUSPENDED' | 'INACTIVE';
createdAt: string;
updatedAt: string;
}

// Get current tenant
async function getCurrentTenant(accessToken: string): Promise<Tenant> {
const response = await fetch('http://localhost:8091/tenants/current', {
headers: {
'Authorization': `Bearer ${accessToken}`,
},
});
return response.json();
}

// Update tenant
async function updateTenant(
accessToken: string,
tenantId: string,
updates: Partial<Pick<Tenant, 'name' | 'status'>>
): Promise<Tenant> {
const response = await fetch(`http://localhost:8091/tenants/${tenantId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
body: JSON.stringify(updates),
});
return response.json();
}

cURL

# Get current tenant
curl http://localhost:8091/tenants/current \
-H "Authorization: Bearer <access-token>"

# Update tenant name
curl -X PATCH http://localhost:8091/tenants/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{"name": "Acme Corp International"}'