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.

StatusDescription
201Admin user created
409Platform 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).

StatusDescription
200Login successful
401Invalid credentials
403Account 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"]
}
FieldTypeRequiredDescription
emailstringYesUnique email address
passwordstringYesUser password
namestringYesDisplay name
role_idsstring[]NoPlatform role IDs to assign

Response (201): Returns the created user object.

StatusDescription
201User created
400Missing required fields
409Email already exists

Get a single platform user by ID.

Response (200): Returns the user object.

StatusDescription
200Success
404User 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.

StatusDescription
200User updated
404User not found
409Email already exists

Delete a platform user.

StatusDescription
204User deleted
404User 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",
"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"]
}
FieldTypeRequiredDescription
namestringYesKey name
platformboolNoSet to true for platform keys
role_idsstring[]NoRole IDs to assign

Response (201):

{
"id": "ak_e5f6g7h8",
"name": "my-ci-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.

StatusDescription
204Key deleted
404Key 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",
"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"]
}
StatusDescription
201Role created
409Role name already exists

Update a custom role.

Request:

{
"name": "renamed-role"
}
StatusDescription
200Role updated

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

StatusDescription
204Role deleted
400Cannot delete built-in role

List all platform policies.

Get a single policy.

Create a platform policy.

Request:

{
"name": "allow-tenant-read",
"effect": "allow",
"actions": "platform:tenants:read,platform:impersonate:read",
"resources": "*",
"condition": ""
}
FieldTypeRequiredDescription
namestringYesPolicy name
effectstringYesallow or deny
actionsstringYesComma-separated action list
resourcesstringYesComma-separated resource patterns
conditionstringNoCEL 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).

StatusDescription
204Tenant deleted
400Cannot delete platform org
404Tenant 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:

ParameterTypeDescription
event_typestringFilter by event type (e.g., platform.user.created)
fromstringStart timestamp (ISO 8601, inclusive)
tostringEnd timestamp (ISO 8601, inclusive)
platform_key_idstringFilter by acting platform API key
impersonated_org_idstringFilter by impersonated organization
cursorstringPagination cursor from previous response
limitintMax 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 TypeDescription
platform.user.createdPlatform user created
platform.user.updatedPlatform user updated
platform.user.deletedPlatform user deleted
platform.key.createdPlatform API key created
platform.key.revokedPlatform API key deleted or rotated
platform.role.changedPlatform role created, updated, or deleted
platform.impersonatedImpersonated 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.