Skip to content

Platform API

Base URL: http://localhost:9123/api/v1/platform

All endpoints except login require platform authentication via Authorization: Bearer <token> header, where <token> is either a JWT from login or a platform API key (ifplatform_*). Platform API keys are created with ironflow apikey create --platform — see API Keys for details.


One-time bootstrap endpoint to initialize the platform. Creates the first admin user. Requires a tenant admin API key and refuses if any platform users already exist.

Request:

{
"email": "admin@example.com",
"password": "secure-password",
"name": "Admin User"
}

Response (201): Returns the created admin user.

Status Description
201 Admin user created
409 Platform already bootstrapped (users exist)

Authenticate a platform user and receive a JWT token.

Request:

{
"email": "admin@example.com",
"password": "your-password"
}

Response (200):

{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": "puser_a1b2c3d4",
"email": "admin@example.com",
"name": "Platform Admin",
"roles": ["platform_admin"]
}
}

Also sets an ironflow_dashboard_token HttpOnly cookie (24h TTL).

Status Description
200 Login successful
401 Invalid credentials
403 Account is inactive

List all platform users.

Response (200):

[
{
"id": "puser_a1b2c3d4",
"email": "admin@example.com",
"name": "Platform Admin",
"is_active": true,
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-12T10:00:00Z"
}
]

Create a platform user.

Request:

{
"email": "ops@example.com",
"password": "secure-password",
"name": "Ops User",
"role_ids": ["role_platform_admin"]
}
Field Type Required Description
email string Yes Unique email address
password string Yes User password
name string Yes Display name
role_ids string[] No Platform role IDs to assign

Response (201): Returns the created user object.

Status Description
201 User created
400 Missing required fields
409 Email already exists

Get a single platform user by ID.

Response (200): Returns the user object.

Status Description
200 Success
404 User not found

Update a platform user. All fields are optional.

Request:

{
"name": "New Name",
"email": "new@example.com",
"password": "new-password",
"is_active": false
}

Response (200): Returns the updated user object.

Status Description
200 User updated
404 User not found
409 Email already exists

Delete a platform user.

Status Description
204 User deleted
404 User not found

Platform API keys are now managed through the unified /api/v1/apikeys endpoint with platform=true. See API Keys for the full API key documentation.

List all platform API keys. The full key value is never returned.

Response (200):

[
{
"id": "ak_e5f6g7h8",
"name": "my-ci-key",
"key_prefix": "ifplatform_a1b2c3d4",
"created_at": "2026-03-12T10:00:00Z"
}
]

Create a platform API key by setting "platform": true in the request body.

Request:

{
"name": "my-ci-key",
"platform": true,
"role_ids": ["role_platform_admin"]
}
Field Type Required Description
name string Yes Key name
platform bool No Set to true for platform keys
role_ids string[] No Role IDs to assign

Response (201):

{
"id": "ak_e5f6g7h8",
"name": "my-ci-key",
"key_prefix": "ifplatform_a1b2c3d4",
"key": "ifplatform_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"created_at": "2026-03-12T10:00:00Z"
}

The key field is only returned on creation and rotation.

Delete (revoke) an API key.

Status Description
204 Key deleted
404 Key not found

Rotate a key — generates a new key value while keeping the same ID and role assignments. The old key is immediately invalidated.

Response (200):

{
"id": "ak_e5f6g7h8",
"name": "my-ci-key",
"key_prefix": "ifplatform_x9y8z7w6",
"key": "ifplatform_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4",
"created_at": "2026-03-12T10:00:00Z"
}

List all platform roles (built-in and custom).

Response (200):

[
{
"id": "role_platform_admin",
"name": "platform_admin",
"is_default": false,
"created_at": "2026-03-12T10:00:00Z"
}
]

Get a single role.

Create a custom platform role.

Request:

{
"name": "support-role",
"policy_ids": ["pol_abc123"]
}
Status Description
201 Role created
409 Role name already exists

Update a custom role.

Request:

{
"name": "renamed-role"
}
Status Description
200 Role updated

Delete a custom role. Built-in roles cannot be deleted.

Status Description
204 Role deleted
400 Cannot delete built-in role

List all platform policies.

Get a single policy.

Create a platform policy.

Request:

{
"name": "deny-prod-tenant-mutations",
"effect": "deny",
"actions": "platform:tenants:manage",
"resources": "*",
"condition": "request.environment == 'env_prod'"
}
Field Type Required Description
name string Yes Policy name
effect string Yes deny only (#943, ADR 0016 T2). allow returns 400 policy_effect_allow_deprecated.
actions string Yes Comma-separated action list
resources string Yes Comma-separated resource patterns
condition string No CEL expression

Update a policy.

Delete a policy.


List all tenant organizations (excludes the platform sentinel org).

Response (200):

[
{
"id": "org_x1y2z3w4",
"name": "Acme Corp",
"created_at": "2026-03-12T10:00:00Z"
}
]

Get a single tenant.

Provision a new tenant organization.

Request:

{
"name": "Acme Corp"
}

Response (201): Returns the created tenant object.

Delete a tenant organization. Cannot delete the platform sentinel org (org_platform).

Status Description
204 Tenant deleted
400 Cannot delete platform org
404 Tenant not found

Platform-side alias for POST /api/v1/orgs. Creates an organization without bundling an environment or admin key (use POST /api/v1/platform/tenants for full tenant provisioning). Exists so platform admins can create orgs without an impersonation header — the tenant-scoped POST /api/v1/orgs is denied at the RBAC gate when called with platform credentials.

Request:

{
"name": "Acme Corp"
}

Response (201): Returns the created organization object.


Query platform audit events.

Query Parameters:

Parameter Type Description
event_type string Filter by event type (e.g., platform.user.created)
from string Start timestamp (ISO 8601, inclusive)
to string End timestamp (ISO 8601, inclusive)
platform_key_id string Filter by acting platform API key
impersonated_org_id string Filter by impersonated organization
cursor string Pagination cursor from previous response
limit int Max results per page (default: 100)

Response (200):

{
"events": [
{
"id": "01HXYZ...",
"event_type": "platform.user.created",
"scope": "platform",
"platform_key_id": "ak_e5f6g7h8",
"platform_user_id": "puser_a1b2c3d4",
"impersonated_org_id": "",
"payload": { "user_id": "puser_d4e5f6g7", "email": "ops@example.com" },
"created_at": "2026-03-12T10:00:00Z"
}
],
"total": 42
}

Event Types:

Event Type Description
platform.user.created Platform user created
platform.user.updated Platform user updated
platform.user.deleted Platform user deleted
platform.key.created Platform API key created
platform.key.revoked Platform API key deleted or rotated
platform.role.changed Platform role created, updated, or deleted
platform.impersonated Impersonated request initiated

Any non-platform endpoint can be called with platform credentials by adding the X-Ironflow-Org header:

Terminal window
curl http://localhost:9123/api/v1/functions \
-H "Authorization: Bearer $PLATFORM_TOKEN" \
-H "X-Ironflow-Org: org_x1y2z3w4"

See Impersonating Tenants for details.