Admin API Reference
Complete reference for the admin_backend_api server endpoints. All routes (except /health and auth endpoints) require a valid Keycloak Authorization: Bearer <token> header.
Authentication
All auth requests are sent to Keycloak via the admin backend.
POST /api/admin/auth/login
Login as an admin user.
Request:
{
"email": "[email protected]",
"password": "securepassword"
}
Response:
{
"access_token": "eyJhbGci...",
"refresh_token": "eyJhbGci...",
"expires_in": 300,
"token_type": "Bearer"
}
POST /api/admin/auth/refresh
Refresh an expired access token.
Request:
{
"refresh_token": "eyJhbGci..."
}
Response:
{
"access_token": "eyJhbGci...",
"refresh_token": "eyJhbGci..."
}
POST /api/admin/auth/logout
Invalidate the current session.
Request:
{
"refresh_token": "eyJhbGci..."
}
Response:
{
"message": "Logout successful"
}
POST /api/admin/auth/verify-session
Verify the current token is valid.
Headers: Authorization: Bearer <token>
Response:
{
"valid": true,
"subject": "keycloak-user-id",
"username": "[email protected]"
}
GET /api/admin/auth/me
Get the authenticated admin's profile.
Headers: Authorization: Bearer <token> (read access)
Response:
{
"subject": "keycloak-user-id",
"username": "[email protected]",
"role": "full_admin"
}
Users
GET /api/admin/users
List all users with pagination, search, and status filtering.
Auth: Read
Query Parameters:
- page (int, default: 1)
- page_size (int, default: 20, max: 100)
- search (string, optional) — Search in email, first_name, last_name
- status (string, optional) — Filter by status: active, blocked, deleted
Response:
{
"items": [
{
"uuid": "user-uuid",
"email": "jo***@example.com",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"tier_name": "Pro",
"organization_name": "Acme Corp",
"created_at": "2024-01-15T10:30:00Z"
}
],
"page": 1,
"page_size": 20,
"total": 150
}
GET /api/admin/users/<userUuid>
Get detailed user information.
Auth: Read
Response:
{
"uuid": "user-uuid",
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"has_temporary_password": false,
"tier": {
"uuid": "tier-uuid",
"name": "Pro"
},
"organizations": [
{
"uuid": "org-uuid",
"name": "Acme Corp",
"role": "member"
}
],
"feature_roles": ["functions:read", "functions:write"],
"created_at": "2024-01-15T10:30:00Z"
}
PATCH /api/admin/users/<userUuid>
Update user fields.
Auth: Write (full_admin)
Request:
{
"first_name": "Jonathan",
"last_name": "Doe",
"email": "[email protected]"
}
Response:
{
"success": true,
"message": "User updated successfully",
"user": { /* updated user */ }
}
POST /api/admin/users/<userUuid>/disable
Block a user account (sets status = 'blocked').
Auth: Write (full_admin)
Response:
{
"success": true,
"message": "User disabled successfully"
}
POST /api/admin/users/<userUuid>/enable
Re-enable a blocked user (sets status = 'active').
Auth: Write (full_admin)
Response:
{
"success": true,
"message": "User enabled successfully"
}
DELETE /api/admin/users/<userUuid>
Soft-delete a user (sets status = 'deleted'). Never physically removes the record.
Auth: Write (full_admin)
Response:
{
"success": true,
"message": "User deleted successfully"
}
POST /api/admin/users/<userUuid>/send-temporary-password
Generate and email a temporary password to the user.
Auth: Write (full_admin)
Response:
{
"success": true,
"message": "Temporary password sent to jo***@example.com"
}
Notes:
- Passwords are generated with Random.secure(), hashed with BCrypt
- The temporary_password flag is set to true on the user record
- Emails are sent via ForwardEmail
Keycloak User Feature Roles
GET /api/admin/keycloak-users/<keycloakUserId>/feature-roles
Get feature roles for a Keycloak user.
Auth: Read
Response:
{
"keycloak_user_id": "kc-user-id",
"assigned_roles": ["container:read"],
"default_roles": ["functions:read", "functions:write", "sites:read", "sites:write"],
"grantable_roles": ["container:read", "container:write", "webhook:read", "webhook:write"],
"effective_roles": ["functions:read", "functions:write", "sites:read", "sites:write", "container:read"]
}
POST /api/admin/keycloak-users/<keycloakUserId>/feature-roles/grant
Grant feature roles to a user. Only roles in the grantable allowlist can be granted.
Auth: Write (full_admin)
Request:
{
"roles": ["container:read", "webhook:write"]
}
Response:
{
"success": true,
"message": "Roles granted successfully",
"granted_roles": ["container:read", "webhook:write"]
}
POST /api/admin/keycloak-users/<keycloakUserId>/feature-roles/remove
Remove feature roles from a user.
Auth: Write (full_admin)
Request:
{
"roles": ["container:read"]
}
Response:
{
"success": true,
"message": "Roles removed successfully",
"removed_roles": ["container:read"]
}
GET /api/admin/feature-roles/stats
Get aggregate statistics for all feature roles across users. Full admins are excluded from counts.
Auth: Read
Response:
{
"roles": {
"container:read": { "assigned_count": 42 },
"container:write": { "assigned_count": 15 },
"webhook:read": { "assigned_count": 38 },
"webhook:write": { "assigned_count": 12 }
},
"total_users": 150,
"total_full_admins": 3
}
Tiers
GET /api/admin/tiers
List all service tiers.
Auth: Read
Response:
{
"items": [
{
"uuid": "tier-uuid",
"name": "Pro",
"description": "Professional tier",
"is_active": true,
"user_count": 45,
"created_at": "2024-01-01T00:00:00Z"
}
]
}
POST /api/admin/tiers
Create a new tier.
Auth: Write (full_admin)
Request:
{
"name": "Enterprise",
"description": "Enterprise tier with full features",
"metadata": { "max_functions": 100 }
}
Response:
{
"success": true,
"tier": { /* created tier */ }
}
PATCH /api/admin/tiers/<tierId>
Update a tier.
Auth: Write (full_admin)
Request:
{
"name": "Enterprise Plus",
"description": "Updated description"
}
Response:
{
"success": true,
"tier": { /* updated tier */ }
}
DELETE /api/admin/tiers/<tierId>
Delete a tier.
Auth: Write (full_admin)
Response:
{
"success": true,
"message": "Tier deleted successfully"
}
POST /api/admin/tiers/<tierId>/assign-user
Assign a user to a tier.
Auth: Write (full_admin)
Request:
{
"user_uuid": "user-uuid"
}
Response:
{
"success": true,
"message": "User assigned to tier successfully"
}
DELETE /api/admin/tiers/<tierId>/assign-user/<userUuid>
Remove a user from a tier.
Auth: Write (full_admin)
Response:
{
"success": true,
"message": "User unassigned from tier successfully"
}
Organizations
GET /api/admin/organizations
List all organizations with pagination.
Auth: Read
Query Parameters:
- page (int, default: 1)
- page_size (int, default: 20)
- search (string, optional)
Response:
{
"items": [
{
"uuid": "org-uuid",
"name": "Acme Corp",
"owner_email": "ad***@acme.com",
"member_count": 12,
"created_at": "2024-01-15T10:30:00Z"
}
],
"page": 1,
"page_size": 20,
"total": 8
}
POST /api/admin/organizations
Create a new organization.
Auth: Write (full_admin)
Request:
{
"name": "New Corp",
"owner_uuid": "user-uuid"
}
Response:
{
"success": true,
"organization": { /* created org */ }
}
GET /api/admin/organizations/<organizationUuid>
Get organization details including members.
Auth: Read
Response:
{
"uuid": "org-uuid",
"name": "Acme Corp",
"owner_email": "[email protected]",
"members": [
{
"uuid": "user-uuid",
"email": "jo***@acme.com",
"role": "member",
"joined_at": "2024-01-15T10:30:00Z"
}
],
"created_at": "2024-01-15T10:30:00Z"
}
PATCH /api/admin/organizations/<organizationUuid>
Update organization details.
Auth: Write (full_admin)
Request:
{
"name": "Acme Corp Updated"
}
POST /api/admin/organizations/<organizationUuid>/members
Add a member to an organization.
Auth: Write (full_admin)
Request:
{
"user_uuid": "user-uuid",
"role": "member"
}
DELETE /api/admin/organizations/<organizationUuid>/members/<userUuid>
Remove a member from an organization.
Auth: Write (full_admin)
Observability
GET /api/admin/observability/overview
Get system overview metrics.
Auth: Read
Query Parameters:
- period (string) — 1h, 24h, 7d (default: 24h)
Response:
{
"error_rate": 2.5,
"total_executions": 15000,
"active_functions": 342,
"avg_latency_ms": 120
}
GET /api/admin/observability/logs
Get function execution logs.
Auth: Read
Query Parameters:
- function_uuid (string, optional) — Filter by function
- level (string, optional) — info, warn, error
- limit (int, default: 100)
- since (ISO 8601, optional)
Response:
{
"logs": [
{
"timestamp": "2024-01-15T10:30:00Z",
"function_uuid": "func-uuid",
"level": "error",
"message": "Connection timeout"
}
],
"total": 150
}
GET /api/admin/observability/errors
Get filtered error logs.
Auth: Read
Query Parameters:
- function_uuid (string, optional)
- limit (int, default: 50)
- since (ISO 8601, optional)
Response:
{
"errors": [
{
"timestamp": "2024-01-15T10:30:00Z",
"function_uuid": "func-uuid",
"message": "Unhandled exception: Null check operator used on a null value"
}
],
"total": 23
}
GET /api/admin/observability/load
Get system load metrics over time.
Auth: Read
Query Parameters:
- period (string) — 1h, 24h, 7d (default: 24h)
- interval (string) — 5m, 15m, 1h (default: 15m)
Response:
{
"data": [
{
"timestamp": "2024-01-15T10:00:00Z",
"request_count": 250,
"avg_latency_ms": 115,
"error_count": 3
}
],
"period": "24h",
"interval": "15m"
}
Early Access Features (Feature Flags)
GET /api/admin/early-access-features
List all feature flags.
Auth: Read
Response:
{
"items": [
{
"uuid": "flag-uuid",
"name": "preview_registration_enabled",
"enabled": true,
"value": { "target_users": 100 },
"created_at": "2024-01-01T00:00:00Z"
}
]
}
GET /api/admin/early-access-features/<name>
Get a specific feature flag by name.
Auth: Read
PUT /api/admin/early-access-features/<uuid>
Update a feature flag.
Auth: Write (full_admin)
Request:
{
"enabled": false,
"value": { "target_users": 200 }
}
GET /api/admin/early-access-features/<featureUuid>/overview
Get feature overview with registration statistics.
Auth: Read
Early Access Form Schemas
GET /api/admin/early-access-form-schemas
List all form schemas.
Auth: Read
Response:
{
"items": [
{
"uuid": "schema-uuid",
"feature_uuid": "feature-uuid",
"feature_name": "preview_registration",
"schema_version": 2,
"created_at": "2024-01-15T10:30:00Z"
}
]
}
GET /api/admin/early-access-form-schemas/<schemaUuid>
Get a specific schema by UUID.
Auth: Read
GET /api/admin/early-access-form-schemas/by-feature/<featureUuid>
Get schemas for a specific feature.
Auth: Read
POST /api/admin/early-access-form-schemas
Create or update a form schema (upsert).
Auth: Write (full_admin)
Request:
{
"feature_uuid": "feature-uuid",
"schema": {
"fields": [
{
"name": "company",
"type": "text",
"required": true,
"label": "Company Name"
}
]
}
}
DELETE /api/admin/early-access-form-schemas/<schemaUuid>
Delete a form schema.
Auth: Write (full_admin)
POST /api/admin/early-access-form-schemas/validate
Validate form data against a schema.
Auth: Read
Request:
{
"schema_uuid": "schema-uuid",
"data": {
"company": "Acme Corp"
}
}
Early Access Request Management
For detailed documentation on early access request management, see Early Access Admin.
Summary of Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/admin/early-access/requests | Read | List requests with pagination, search, status filter |
| GET | /api/admin/early-access/requests/<uuid> | Read | Get request details |
| POST | /api/admin/early-access/requests/<uuid>/approve | Write | Approve request (with capacity check) |
| POST | /api/admin/early-access/requests/<uuid>/reject | Write | Reject request with reason |
| POST | /api/admin/early-access/requests/<uuid>/send-temporary-password | Write | Generate and email temp password |
| GET | /api/admin/early-access/requests/<uuid>/audit-logs | Read | Get audit log for a request |
| GET | /api/admin/early-access/settings | Read | Get capacity/status settings |
| PUT | /api/admin/early-access/settings/capacity | Write | Update capacity limit |
| PUT | /api/admin/early-access/settings/toggle | Write | Enable/disable registration |
Health Check
GET /health
Check admin backend server health.
Auth: None
Response:
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00Z"
}
Error Responses
400 Bad Request
{
"error": "Invalid request",
"details": "Missing required field: email"
}
401 Unauthorized
{
"error": "Missing or invalid authorization header"
}
403 Forbidden
{
"error": "Insufficient permissions"
}
Note: Returned when a viewer tries a write operation, or a user has no admin role.
404 Not Found
{
"error": "User not found"
}
500 Internal Server Error
{
"error": "Internal server error"
}
All unhandled errors are reported to Sentry (when configured).
Next Steps
- Read Admin Backend Overview for server architecture
- Read Keycloak Authentication for auth system details
- Read User Management for users, orgs, tiers, and roles