Skip to content

Tenant management

The tenant management endpoints are protected by the X-Admin-Key header — the operator key that guards the tenant registry. They are never reachable with a tenant HMAC signature, and the admin key must never be shipped to a browser or a device.

For the cross-cutting conceptual model (states, secret shown once, rotation), see also Tenant lifecycle.

MethodPathTenant viaBody
POST/provision/tenantbodyfull
POST/update/tenant?tenant_id=partial
POST/rotate/tenant-secret?tenant_id=
POST/suspend/tenant?tenant_id=
POST/reactivate/tenant?tenant_id=
GET/fetch/tenant?tenant_id=
GET/fetch/tenants— (pagination)

Creates a tenant and returns its tenant_id and tenant_secret. Only tenant_name is required; the configuration fields can be set later.

Fenêtre de terminal
curl $BASE_URL/api/v1/provision/tenant \
-X POST \
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"tenant_name": "example_backend",
"rate_limit_per_min": 120,
"qr_login_allowed_origins": ["https://example.com"],
"callback_url_base": "https://api.example.com",
"branding_display_name": "Example",
"branding_logo_url": "https://example.com/logo.png",
"webauthn_rp_id": "example.com",
"webauthn_origins": ["https://example.com"],
"passkeys_enabled": true
}'

The configuration fields and what they drive:

FieldUsed by
rate_limit_per_minRate cap on relay calls (default 60, max 10,000).
qr_login_allowed_originsQR login: allowed web origins. Empty list = QR login disabled.
callback_url_baseRelay → tenant callbacks. The relay appends /relay-callbacks/<flow>.
branding_display_nameMobile consent screen: “Sign in to …?”. Falls back to tenant_name.
branding_logo_urlLogo (square, HTTPS) on the mobile consent screen.
webauthn_rp_idWebAuthn Relying Party ID (eTLD+1). Required for passkeys.
webauthn_originsOrigin allowlist for passkey ceremonies. Empty list = passkeys disabled.
passkeys_enabledPasskey progressive rollout flag (null/true/false).

The response — tenant_secret shown only once:

{
"success": true,
"status_code": 201,
"message": "Tenant provisioned. Save tenant_secret now — it will not be shown again.",
"data": {
"tenant_id": "tnt_...",
"tenant_secret": "sk_...",
"tenant_name": "example_backend",
"rate_limit_per_min": 120,
"created_at": "2026-06-21T..."
}
}

Partial update: only the fields present in the body are written. The secret is never changed here (use rotation) and state changes go through suspend / reactivate.

Fenêtre de terminal
curl "$BASE_URL/api/v1/update/tenant?tenant_id=tnt_..." \
-X POST \
-H "X-Admin-Key: YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"qr_login_allowed_origins": ["https://example.com", "https://preview.example.com"],
"branding_display_name": "Example (Preview)"
}'
{
"success": true,
"status_code": 200,
"message": "Tenant updated",
"data": {
"tenant_id": "tnt_...",
"tenant_name": "example_backend",
"status": "active",
"rate_limit_per_min": 120,
"qr_login_allowed_origins": ["https://example.com", "https://preview.example.com"],
"branding_display_name": "Example (Preview)",
"abuse_strikes": 0,
"created_at": "2026-06-21T...",
"updated_at": "2026-06-21T..."
}
}

Generates a new tenant_secret. The old secret becomes invalid immediately — deploy the new one before any subsequent signed call. The new secret is shown only once.

Fenêtre de terminal
curl "$BASE_URL/api/v1/rotate/tenant-secret?tenant_id=tnt_..." \
-X POST \
-H "X-Admin-Key: YOUR_ADMIN_KEY"
{
"success": true,
"status_code": 200,
"message": "Secret rotated. Save the new tenant_secret — old secret is now invalid.",
"data": {
"tenant_id": "tnt_...",
"tenant_secret": "sk_...",
"rotated_at": "2026-06-21T..."
}
}

Suspending blocks all of the tenant’s relay calls: a /relay/* request signed by a suspended tenant is rejected with 403. Reactivation undoes the suspension.

Fenêtre de terminal
curl "$BASE_URL/api/v1/suspend/tenant?tenant_id=tnt_..." \
-X POST \
-H "X-Admin-Key: YOUR_ADMIN_KEY"
{ "success": true, "status_code": 200, "message": "Tenant suspended", "data": null }

GET /fetch/tenant returns a tenant’s configuration and state (never the secret). GET /fetch/tenants returns a paginated list.

Fenêtre de terminal
curl "$BASE_URL/api/v1/fetch/tenant?tenant_id=tnt_..." \
-H "X-Admin-Key: YOUR_ADMIN_KEY"
{
"success": true,
"status_code": 200,
"message": "OK",
"data": {
"tenant_id": "tnt_...",
"tenant_name": "example_backend",
"status": "active",
"rate_limit_per_min": 120,
"abuse_strikes": 0,
"created_at": "2026-06-21T...",
"updated_at": null
}
}