API reference
Platform administration
Organizations, plans, regions and locations, for platform administrators.
These routes check scopes in the platform organization, not in an organization in the path.
GET /v1/platform/analytics
Traffic across every customer deployment, with the busiest organizations.
Auth: user access token or platform agent key · Scope: platform:analytics in the platform organization
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
range | "24h" | "7d" | "30d" | No | "24h" |
Response 200
{
top: {
hosts?: {
key: string
requests: number
bytes: number
name?: string
}[]
orgs?: {
key: string
requests: number
bytes: number
name?: string
}[]
paths?: {
key: string
requests: number
bytes: number
name?: string
}[]
countries?: {
key: string
requests: number
bytes: number
name?: string
}[]
deployments?: {
key: string
requests: number
bytes: number
name?: string
}[]
projects?: {
key: string
requests: number
bytes: number
name?: string
}[]
}
unattributed: number
updatedAt: null | number
range: "24h" | "7d" | "30d"
step: number
from: string
to: string
totals: {
requests: number
bytes: number
s2xx: number
s3xx: number
s4xx: number
s5xx: number
hits: number
misses: number
p50: null | number
p95: null | number
}
series: {
requests: number
bytes: number
s2xx: number
s3xx: number
s4xx: number
s5xx: number
hits: number
misses: number
p50: null | number
p95: null | number
t: string
}[]
}GET /v1/platform/mail/usage
Mail sent and received per organization over the last days.
Auth: user access token or platform agent key · Scope: platform:analytics in the platform organization
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
days | integer | No | 7 | 1–31; coerced from a string |
Response 200
{
days: number
total: {
sent: number
received: number
}
orgs: {
orgId: string
sent: number
received: number
bounced: number
complained: number
}[]
}GET /v1/platform/usage
Cost per organization for a month (month=YYYY-MM, default this month) from Cost Explorer, grouped by the si:org cost allocation tag, with each organization's projects, repositories, databases and buckets. Spend without the tag is untagged.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
| Query parameter | Type | Required | Notes |
|---|---|---|---|
month | string | No | matches ^\d{4}-(0[1-9]|1[0-2])$ |
Response 200
{
month: string
currency: string
estimated: boolean
costError?: string
orgs: {
projects: number
repositories: number
databases: number
buckets: number
orgId: string
name: string
slug: string
kind: "platform" | "customer"
planId?: string
cost: null | number
}[]
untagged: null | number
otherOrgs: null | number
}GET /v1/platform/orgs
Platform organizations and the newest customer organizations.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
Response 200
{
orgs: {
name: string
createdAt?: number
updatedAt?: number
orgId: string
slug: string
kind: "platform" | "customer"
planId?: string
auditExportBucketId?: string
}[]
}POST /v1/platform/orgs
Onboards a customer: the org (slug claimed atomically, optional plan) and an owner invite. The invite link is in the response once (and mailed where SES is set up); the owner joins through ID.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | 1–64 characters; trimmed |
slug | string | Yes | matches ^[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9])){1,38}$; trimmed |
ownerEmail | string | Yes | up to 254 characters; email address |
planId | string | No | matches ^[a-z0-9][a-z0-9-]{1,62}$; can be null |
Response 201
{
org: {
name: string
createdAt?: number
updatedAt?: number
orgId: string
slug: string
kind: "platform" | "customer"
planId?: string
auditExportBucketId?: string
}
invite: {
inviteId: string
email: string
link: string
delivered: boolean
expiresAt: number
}
}Errors
| Status | Message |
|---|---|
400 | Unknown plan |
403 | Onboarding needs a signed-in admin. |
PATCH /v1/platform/orgs/:orgId
Assigns an organization to a plan. planId: null returns it to the default plan.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
planId | string | Yes | matches ^[a-z0-9][a-z0-9-]{1,62}$; can be null |
Response 200
{
org: {
name: string
createdAt?: number
updatedAt?: number
orgId: string
slug: string
kind: "platform" | "customer"
planId?: string
auditExportBucketId?: string
}
}Errors
| Status | Message |
|---|---|
400 | Unknown plan |
404 | Organization not found |
GET /v1/platform/stats
Counts of organizations, customers, regions and locations.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
Response 200
{
orgs: number
customers: number
regions: number
locations: number
}GET /v1/platform/audit
The platform organization's audit log: registry and plan changes, onboarding and the platform organization's own activity.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
cursor | string | No | up to 4,096 characters | |
action | string | No | matches ^[a-z_]{1,32}(\.[a-z_]{1,32})?$ | |
actor | string | No | 1–512 characters | |
target | string | No | matches ^[a-z_]{1,32}:[^\s]{1,512}$ | |
limit | integer | No | 50 | 1–100; coerced from a string |
Response 200
{
events: {
eventId: string
orgId: string
action: string
actor: {
type: "user" | "device" | "key" | "system"
id: string
label?: string
}
target: {
type: string
id: string
label?: string
}
metadata?: {
[key: string]: unknown
}
ip?: string
userAgent?: string
createdAt: number
}[]
cursor: null | string
retentionDays?: number
}Errors
| Status | Message |
|---|---|
400 | Invalid cursor |
403 | Missing scope platform:admin |
GET /v1/platform/regions
The region and location registry.
Auth: user access token or platform agent key · Scope: platform:infra in the platform organization
Response 200
{
regions: {
name: string
status?: "active" | "disabled"
createdAt?: number
updatedAt?: number
regionId: string
unavailable?: string[]
}[]
locations: {
label: string
status?: "active" | "disabled" | "preview"
createdAt?: number
updatedAt?: number
locationId: string
isDefault?: boolean
regions: string[]
sortOrder?: number
}[]
}PUT /v1/platform/regions/:regionId
Creates or replaces a region. Services that ran from the cached registry see the change within a minute.
Auth: user access token or platform agent key · Scope: platform:infra in the platform organization
| Path parameter | Description |
|---|---|
:regionId | AWS region id, e.g. us-west-1. |
Request body
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name | string | Yes | 1–100 characters | |
status | "active" | "disabled" | No | "active" | |
unavailable | string[] | No | [] | up to 100 items; each up to 64 characters |
Response 200
{
region: {
name: string
status?: "active" | "disabled"
createdAt?: number
updatedAt?: number
regionId: string
unavailable?: string[]
}
}PUT /v1/platform/locations/:locationId
Creates or replaces a location with its ordered region list (primary first).
Auth: user access token or platform agent key · Scope: platform:infra in the platform organization
| Path parameter | Description |
|---|---|
:locationId | Location id. |
Request body
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
label | string | Yes | 1–100 characters | |
regions | string[] | Yes | 1–10 items; each matches ^[a-z0-9][a-z0-9-]{1,62}$ | |
status | "active" | "preview" | "disabled" | No | "active" | |
isDefault | boolean | No | false | |
sortOrder | integer | No | 0 |
Response 200
{
location: {
label: string
status?: "active" | "disabled" | "preview"
createdAt?: number
updatedAt?: number
locationId: string
isDefault?: boolean
regions: string[]
sortOrder?: number
}
}GET /v1/platform/plans
Plans and their settings. Organizations without a plan use the default plan.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
Response 200
{
plans: {
name: string
createdAt?: number
updatedAt?: number
planId: string
isDefault?: boolean
sortOrder?: number
auditRetentionDays: number
mailSendPerDay?: number
mailMaxMessageMb?: number
mailMaxRecipients?: number
maxConnectors?: number
maxConnectorTools?: number
}[]
}PUT /v1/platform/plans/:planId
Creates or replaces a plan. Optional limits that aren't sent keep their stored value; null clears one (the default applies). Making a plan the default clears the flag on the others.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
| Path parameter | Description |
|---|---|
:planId | Plan id. |
Request body
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name | string | Yes | 1–100 characters; trimmed | |
auditRetentionDays | integer | Yes | 1–3650 | |
isDefault | boolean | No | false | |
sortOrder | integer | No | 0 | |
mailSendPerDay | integer | No | 0–1000000; can be null | |
mailMaxMessageMb | integer | No | 1–40; can be null | |
mailMaxRecipients | integer | No | 1–1000; can be null | |
maxConnectors | integer | No | 0–1000; can be null | |
maxConnectorTools | integer | No | 0–1000; can be null |
Response 200
{
plan: {
name: string
createdAt?: number
updatedAt?: number
planId: string
isDefault?: boolean
sortOrder?: number
auditRetentionDays: number
mailSendPerDay?: number
mailMaxMessageMb?: number
mailMaxRecipients?: number
maxConnectors?: number
maxConnectorTools?: number
}
}GET /v1/platform/models
Chat models and the capabilities that shape their requests. Chat reads them within the cache TTL.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
Response 200
{
models: {
label: string
createdAt?: number
updatedAt?: number
description?: string
isDefault?: boolean
sortOrder?: number
modelId: string
enabled?: boolean
thinking?: "none" | "adaptive" | "budget"
thinkingBudget?: number
effort?: "low" | "medium" | "high" | "xhigh" | "max"
maxTokens: number
eagerToolInput?: boolean
fallbackModelId?: string
}[]
}PUT /v1/platform/models/:modelId
Creates or replaces a chat model in the catalog: label, whether it's enabled or the default, thinking and effort settings, output tokens and fallback model. Making a model the default clears the flag on the others.
Auth: user access token or platform agent key · Scope: platform:admin in the platform organization
| Path parameter | Description |
|---|---|
:modelId | Bedrock base model id, e.g. anthropic.claude-opus-5-5. |
Request body
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
label | string | Yes | 1–100 characters; trimmed | |
description | string | No | "" | up to 120 characters; trimmed |
enabled | boolean | No | true | |
isDefault | boolean | No | false | |
sortOrder | integer | No | 0 | |
thinking | "adaptive" | "budget" | "none" | No | "adaptive" | |
thinkingBudget | integer | No | 1024–128000; can be null | |
effort | "low" | "medium" | "high" | "xhigh" | "max" | No | can be null | |
maxTokens | integer | Yes | 1024–128000 | |
eagerToolInput | boolean | No | true | |
fallbackModelId | string | No | matches ^[a-z0-9][a-z0-9.:-]{2,127}$; can be null |
Also checked: Budget thinking needs a thinking budget below the max tokens The default model must be enabled
Response 200
{
model: {
label: string
createdAt?: number
updatedAt?: number
description?: string
isDefault?: boolean
sortOrder?: number
modelId: string
enabled?: boolean
thinking?: "none" | "adaptive" | "budget"
thinkingBudget?: number
effort?: "low" | "medium" | "high" | "xhigh" | "max"
maxTokens: number
eagerToolInput?: boolean
fallbackModelId?: string
}
}Errors
| Status | Message |
|---|---|
400 | A model can't fall back to itself |
400 | Unknown fallback model |
400 | Set another model as the default first |