Node API Reference (OpenAPI)
This page is the node API as a machine-readable
OpenAPI 3.1 document, rendered: every
route of router in crates/node/src/api.rs (and the area routers it merges,
api/<area>.rs) outside /internal/, with its
credential, parameters, request body, answer and error codes.
Node API is the same API as an operator’s overview
with the meroctl command for each route.
Where it comes from
Section titled “Where it comes from”The document is docs/public/openapi.json, served beside this page as
openapi.json. It is generated from the registry next to
the router, crates/node/src/api/openapi.rs, and that registry’s tests hold it
to the code on every CI run:
- every route
routerserves (outside/internal/) has exactly one entry, and no entry names a route the router lacks; - each entry’s request body and query are the ones its handler extracts
(
Json<T>,Option<Json<T>>,Query<T>or raw bytes), with the same field names asT; a sample of the shape deserializes intoT, and a field is optional in the document exactly whenTaccepts the body without it; additionalProperties: falsemarks a body whose type refuses unknown fields;- every error code a handler raises with a literal code is listed for it;
- each error code that carries
detailsnames that value’s schema, on every error response that lists the code (x-calimero-details) and at the document’s root (x-calimero-error-details), and the schema is held to the constructor that builds the error: each value it builds is one of the schema, and each property is built, always when it is required and not always when it is optional; - a response schema the node answers by serializing a Rust type (an app record,
an API key, a package release reference, an organization and its teams, an
upgrade,
Access,Deployer, an attestation and its KMS evidence, an account proof, a registered node, the quotas) names that type, and is held to it the same way: the same field names, a sample read into the type writes back as a value of the schema, and a field is optional exactly when the type may leave it out; one the type only serializes (a Raft group’s status, the rollback counter) is held to real values of the type; - the committed
openapi.jsonis what the registry builds now.
The other response schemas, those a handler builds with json!, are written in
the registry from the handlers’ answers and are not checked against them. A
value left free-form ({} in the schema) is one whose shape is not the API’s:
an app’s metadata, initArgs, a method’s result, an event’s data, an app’s
error value, the WebAuthn options a ceremony hands to the browser, an app’s ABI
and its own OpenAPI document. Each says so in its description. To
change the API, change the handler and its entry, then regenerate:
UPDATE_OPENAPI=1 cargo test -p calimero-node --lib openapicargo run -p calimero-client-genThe second command regenerates the Rust client’s route layer from the document
(crates/client/src/generated/, by tools/client-gen): one method per
operation on its x-calimero-group’s accessor (client.orgs().invite_create(..),
client.apps().call(..)), named as the other SDKs name it. Its test fails while
the checked-in code differs from what the document generates, so a route change
regenerates both in the same pull request.
Every error answers the one Error schema, so a client decodes any error,
including a code a route does not list, the same way; it reads details by the
error code with the schema the code names. The sealed channel’s own refusal
(busy, outside the envelope) is not an Error: its schema is the one
x-calimero-sealed-refusal names at the root.
The SDKs (mero-js, calimero-client-py, swift-sdk and kotlin-sdk, the openapi
repositories in .github/fleet.json) each vendor this document and generate
their client from it. When a push to master changes it, openapi-sync.yml
sends each of them a core-openapi event with the commit. Each SDK’s own
openapi-sync.yml calls core’s reusable sdk-openapi-sync.yml (pinned by
commit), which re-vendors the document at that commit, regenerates, and opens
or refreshes one pull request (chore/core-openapi), so that SDK’s CI judges
the change before anything is released. Run the workflow by hand (dry run by
default) to resend the event.
The pull request’s title sets the SDK’s next version. scripts/openapi-classify.py
diffs the document the SDK vendors now against the new one, using a pinned
oasdiff and a set of rules for the x-calimero-* extensions:
| Change | Title | SDK release |
|---|---|---|
Something callers of the generated client rely on is removed or changed: a route, a response field, an operationId, a narrowed enum, a new required request field. The same holds for an operation that now needs a step-up, an operator signature or the sealed channel, stops being retry-safe, or moves to another x-calimero-group. |
feat(api)!: with a BREAKING-CHANGE: footer |
major |
| Something is added and nothing is broken | feat(api): |
minor |
Descriptions, new x-calimero-codes entries, and anything else no generated signature sees |
chore(api): |
patch |
A pull request here that changes the document gets the same verdict in the
summary of its OpenAPI impact run, so its author sees what each SDK will
release before merging.
Calimero node API, OpenAPI 3.1.0: openapi.json(164 paths). Shared schemas are listed at the end.
Public
In the clear (/health, /attestation) or sealed without a credential.
GET /attestation
The node's attestation. In the clear.
In the clear. A TDX quote binding the node's transport key (or, with purpose=receipts, its receipt key and the governance; with purpose=kms, what it verified of its KMS; with purpose=orchestrator, the cluster identity this replica holds) to nonce; app/appHash bind an app's bundle hash. A client checks it before it seals anything to the key.
Who: anyone.
| Parameter | In | Type |
|---|---|---|
nonce | query | string |
app? | query | string |
appHash? | query | string |
purpose? | query | "receipts" | "kms" | "orchestrator" |
Answer (application/json)
AttestationDoc| Status | Codes |
|---|---|
| 400 | BAD_HASH; BAD_NONCE |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
GET /health
Node health. In the clear.
In the clear. The node's id, the system group's leader (null: none known), its merod release, the newest cluster version it supports (clusterVersion) and the cluster's rollback epoch (null on a node without a rollback counter).
Who: anyone.
Answer (application/json)
{
ok: boolean,
node: integer,
systemLeader: integer | null,
release: string,
clusterVersion: string,
rollbackEpoch: integer | null
}GET /publishers/{signer}
Whether a signing key is bound. Sealed.
Whether a package signing key (did:key) is bound to an organization on this cluster (bound, never which), and its binding generation (0: never bound).
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
signer | path | string |
Answer (application/json)
{
signerId: string,
cluster: string,
generation: integer,
bound: boolean
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /recover/holder
Bring an organization's or account's apps back from its recovery files. Sealed.
Sent by the holder's own device, over the sealed channel: its newest holder file (slice), each app's file and the code files, in the receiving node's --recovery-dir (or --recover-from) under org-<id>/ or account-<id>/, each with the data key the holder opened from it with its backup key (hex). The cluster admits it with the operator's signature over cluster / __recover_holder / { holder, slice, apps: [{ app, file, sha256 }] } (428 first, naming it). Where owners upgrade apps, and only for an organization, account, apps and passkeys the cluster does not hold; the receiving node seeds each app, which answers 409 APP_RESTORING until its replicas hold it. People sign in again with the passkeys they had.
Who: anyone. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
holder: string,
slice: {
file: string,
key: string
},
apps?: {
file: string,
key: string
}[],
code?: {
file: string,
key: string
}[],
operatorProof?: OperatorProof
}Answer (application/json)
{
apps: any
}| Status | Codes |
|---|---|
| 400 | BAD_RECOVERY_FILE; BAD_RECOVERY_KEY; BAD_REQUEST: the request is malformed; NOT_A_REPLICA_NODE; TOO_MANY_FILES; UNATTESTED_RECOVERY_FILE |
| 403 | BAD_OPERATOR_SIGNATURE |
| 409 | FEATURE_NOT_ACTIVE; NO_BACKUP_DIR; RECOVERY_SEGMENTS_MISSING. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /releases
The cluster's releases. Sealed.
The cluster's governance and the deadlines set on mero-tee releases, oldest release first: after after (RFC 3339; afterSecs Unix seconds) a scope that has not approved that release (or a newer one) starts no new work.
Who: anyone.
Answer (application/json)
{
governance: Governance,
deadlines: {
version: string,
after: string,
afterSecs: integer
}[]
}Accounts
Sign-up, sign-in, passkeys, sessions, API keys and the account's own approvals.
POST /auth/account-proof
Prove the account to another party. Sealed.
A statement signed with this node's receipt key that the caller's passkey session asked to bind nonce for audience.
Who: a passkey session (an API key is refused).
Body (application/json)
{
nonce: string,
audience: string
}Answer (application/json)
AccountProof| Status | Codes |
|---|---|
| 400 | BAD_AUDIENCE; BAD_NONCE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/activity
What the account's passkeys did. Sealed.
Newest first, the last 100: sign-ins (app, origin) and approvals (method, subject); after keeps the entries after that Unix second.
Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
after? | query | integer |
Answer (application/json)
{
activity: {
at: integer,
passkey: string,
kind: "signIn" | "approval",
app?: string | null,
origin?: string | null,
method?: string,
subject?: string
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/aliases
The account's aliases. Sealed.
Who: signed in (a session or an API key).
Answer (application/json)
{
aliases: {
[key: string]: string
}
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/aliases/{alias}
Resolve an alias. Sealed.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
alias | path | string |
Answer (application/json)
{
alias: string,
appId: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
PUT /auth/aliases/{alias}
Set an alias. Sealed.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
alias | path | string |
Body (application/json)
{
app: string
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /auth/aliases/{alias}
Remove an alias. Sealed.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
alias | path | string |
Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/apikeys
The account's API keys. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend).
Answer (application/json)
{
keys: ApiKey[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/apikeys
Make an API key. Sealed.
Scoped to apps and methods, read-only or not, for ttlSecs; upgrades makes an upgrade key, which signs upgrades of one app in place of a passkey. 412 first. The key is shown once.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
label?: string,
apps?: string[],
methods?: string[],
readOnly?: boolean,
allowConfirm?: boolean,
ttlSecs?: integer,
upgrades?: {
app: string,
package?: string
},
confirm?: Confirm
}Answer (application/json)
{
keyId: string,
key: string
}| Status | Codes |
|---|---|
| 400 | BAD_UPGRADE_KEY; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | QUOTA_EXCEEDED |
DELETE /auth/apikeys/{key}
Revoke an API key. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
key | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/apps
The account's own apps. Sealed.
The apps the account owns, in any organization (a package-bound session: its package's), with its personal organization's approvedReleases: each app's release, the newer releases it may upgrade to, its last upgrade, its replicas' releases and lastWriteAt.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
after? | query | string |
limit? | query | integer |
Answer (application/json)
{
scope: AppScope,
governance: Governance,
approvedReleases: string[] | null,
clusterReleases: ClusterRelease[],
apps: ReportApp[],
next: string | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/backup-key
The account's backup key. Sealed.
The X25519 public key the recovery-disk backups of the account's personal apps are sealed to (key, null while none is set).
Who: an account holder (a passkey session not bound to an app's frontend).
Answer (application/json)
BackupKeyAnswer| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/backup-key
Set the account's backup key. Sealed.
publicKey: 64 lowercase hex, an X25519 public key whose private half the account holder keeps (never a node), for its personal apps, where owners upgrade apps. 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
publicKey: string,
confirm?: Confirm
}Answer (application/json)
BackupKeyAnswer| Status | Codes |
|---|---|
| 400 | BAD_BACKUP_KEY; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/logout
End this session. Sealed.
Who: a passkey session (an API key is refused).
Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/logout-all
End every session of the account. Sealed.
revoked: how many sessions ended.
Who: an account holder (a passkey session not bound to an app's frontend).
Answer (application/json)
{
revoked: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/me
The caller's account. Sealed.
The account, its passkeys (with addedAt and lastSignInAt), organizations (personal: the one made at sign-up, where its instances go unless they name another; its approvals are that organization's), recovery state, and how the caller came (via).
Who: signed in (a session or an API key).
Answer (application/json)
{
accountId: string,
name: string,
passkeys: {
id: string,
signCount: integer,
label: string | null,
addedAt?: integer | null,
lastSignInAt?: integer | null
}[],
orgs: {
orgId: string,
name: string,
role: OrgRole,
personal?: boolean
}[],
via: "session" | "apiKey",
passkeyId: string | null,
app?: string | null,
origin?: string | null,
recoveryCode?: boolean,
recoveryPending?: {
accountId: string,
credentialId: string,
startedAt: integer,
readyAt: integer
} | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/passkey/login/begin
Start a sign-in. Sealed.
A WebAuthn challenge for any passkey of the cluster. origin is an app frontend's registered origin, whose rp-id the ceremony then uses. options are the WebAuthn options to hand to the browser as they are: free-form here, their shape is WebAuthn's.
Who: anyone.
Body (application/json, optional): May be absent.
{
origin?: string
}Answer (application/json)
{
challengeId: string,
options: any
}| Status | Codes |
|---|---|
| 429 | RATE_LIMITED: a node's limit on open streams or ceremonies |
POST /auth/passkey/login/finish
Finish a sign-in. Sealed.
Who: anyone.
Body (application/json)
{
challengeId: string,
assertion: Assertion
}Answer (application/json)
Session| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | PASSKEY_UNKNOWN_HERE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/passkey/register/begin
Start a sign-up. Sealed.
Creation options for a new passkey. invite is an organization or cluster sign-up invite token, which the policy may require; 403 SIGN_UP_REFUSED when the policy would refuse the sign-up. options are the WebAuthn options to hand to the browser as they are: free-form here, their shape is WebAuthn's.
Who: anyone.
Body (application/json)
{
name?: string,
origin?: string,
invite?: string
}Answer (application/json)
{
challengeId: string,
options: any
}| Status | Codes |
|---|---|
| 403 | SIGN_UP_REFUSED |
| 429 | RATE_LIMITED: a node's limit on open streams or ceremonies |
POST /auth/passkey/register/finish
Finish a sign-up. Sealed.
The new passkey's registration. Answers 412 CONFIRM_REQUIRED first: the new passkey signs the account it creates; the retry with confirm (and the same invite) opens a session, and redeems invite for the new account.
Who: anyone. Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
challengeId: string,
registration: Registration,
invite?: string,
confirm?: Confirm
}Answer (application/json)
Session| Status | Codes |
|---|---|
| 400 | BAD_REGISTRATION; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | PASSKEY_UNKNOWN_HERE |
| 403 | SIGN_UP_REFUSED |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/passkeys/add/begin
Start adding a passkey. Sealed.
Creation options for another passkey (a device) on the caller's account. options are the WebAuthn options to hand to the browser as they are: free-form here, their shape is WebAuthn's.
Who: an account holder (a passkey session not bound to an app's frontend).
Answer (application/json)
{
challengeId: string,
options: any
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/passkeys/add/finish
Finish adding a passkey. Sealed.
Answers 412 first; sent again with confirm signed by a passkey the account already has.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
challengeId: string,
registration: Registration,
confirm?: Confirm
}Answer (application/json)
{
credentialId: string
}| Status | Codes |
|---|---|
| 400 | BAD_REGISTRATION; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/passkeys/{cred}
Name a passkey. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
cred | path | string |
Body (application/json)
{
label: string
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /auth/passkeys/{cred}
Remove a passkey. Sealed.
Its sessions end. 412 first; the retry's JSON body is { confirm }.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
cred | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/recovery
Make a recovery code. Sealed.
Shown once, replacing any; 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{
code: string
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /auth/recovery
Remove the recovery code. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/recovery/begin
Start an account recovery. Sealed.
Signed out, with the recovery code: creation options for the passkey that will replace the lost ones. options are the WebAuthn options to hand to the browser as they are: free-form here, their shape is WebAuthn's.
Who: anyone.
Body (application/json)
{
code: string
}Answer (application/json)
{
challengeId: string,
options: any
}| Status | Codes |
|---|---|
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | RATE_LIMITED: a node's limit on open streams or ceremonies |
POST /auth/recovery/cancel
Cancel an account recovery. Sealed.
With a passkey the account has; 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/recovery/finish
Finish an account recovery. Sealed.
Approved by the new passkey once readyAt passed (412 first): adds it and ends every session of the account.
Who: anyone. Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
accountId?: string,
confirm?: Confirm
}Answer (application/json)
Session| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 409 | RECOVERY_NOT_READY. details of RECOVERY_NOT_READY: a RecoveryNotReady. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /auth/recovery/start
Spend the recovery code. Sealed.
Logs the new passkey as pending; it may finish the recovery once readyAt passed (72 h). 401 for a wrong or spent code.
Who: anyone.
Body (application/json)
{
challengeId: string,
code: string,
registration: Registration
}Answer (application/json)
{
accountId: string,
credentialId: string,
startedAt: integer,
readyAt: integer
}| Status | Codes |
|---|---|
| 400 | BAD_REGISTRATION; WRONG_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 409 | RECOVERY_PENDING |
POST /auth/refresh
Refresh a session. Sealed.
A new session and the refresh token to use next (the same one until it is an hour old). A reused, superseded token ends the sessions it opened. Who: anyone.
Body (application/json)
{
refreshToken: string
}Answer (application/json)
Session| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 503 | UNAVAILABLE: the cluster cannot answer now |
GET /auth/sessions
The account's live sessions. Sealed.
Latest active first, at most 256. openedAt (Unix seconds) is null for a session opened before the node kept it.
Who: an account holder (a passkey session not bound to an app's frontend).
Answer (application/json)
{
sessions: {
session: string,
passkey: string | null,
app: string | null,
origin: string | null,
openedAt: integer | null,
lastActiveAt: integer,
current: boolean
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /auth/sessions/{session}
End one session. Sealed.
404 for a session the account does not hold live.
Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
session | path | string |
Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /auth/usage
The account's usage against its quotas. Sealed.
The apps the account owns, its bundle bytes (a decimal string), API keys and owned organizations; the file bytes held by each payer it belongs to (each organization it is in, and account:<id> for its own apps); the cluster's quotas; and what today's runs of the apps the account develops used (decimal strings).
Who: signed in (a session or an API key).
Answer (application/json)
{
apps: integer,
bundleBytes: string /* decimal */,
apiKeys: integer,
orgsOwned: integer,
fileBytes: {
[key: string]: integer
},
quotas: Quotas,
developerFuelToday: string /* decimal */,
developerWritesToday: string /* decimal */
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
Packages
Signed releases (.mpk), raw bundles and frontend origins.
POST /bundles
Upload a raw component. Sealed.
A calimero:app component, 16 MiB at most; only on a node started with --allow-unsigned-bundles or --dev. A WASM core module (SDK 0.12) is refused 400 UNSUPPORTED_BUNDLE.
Who: an installer (an account holder, or an unscoped API key that is not read-only).
Body (application/wasm): the component
Answer (application/json)
{
hash: string
}| Status | Codes |
|---|---|
| 400 | BAD_BUNDLE; UNSUPPORTED_BUNDLE. details of BAD_BUNDLE: a ServiceRefused, UNSUPPORTED_BUNDLE: a ServiceRefused. |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | QUOTA_EXCEEDED |
GET /package-origins/{package}
A package's frontend origins. Sealed.
The custom origins (and rp-ids) the package's manager registered for its frontend. Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
package | path | string |
Answer (application/json)
{
package: string,
origins: PackageOrigin[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /package-origins/{package}
Register a frontend origin. Sealed.
By whoever manages the package, with a passkey step-up over the change. Answers the origin as registered (the one already there, when the same origin is registered again).
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
package | path | string |
Body (application/json)
{
origin: string,
rpId?: string,
served?: boolean,
confirm?: Confirm
}Answer (application/json)
PackageOrigin| Status | Codes |
|---|---|
| 400 | BAD_RP_ID; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | QUOTA_EXCEEDED |
DELETE /package-origins/{package}
Remove a frontend origin. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
package | path | string |
Body (application/json)
{
origin: string,
confirm?: Confirm
}Answer (application/json)
{
package: string,
origin: string,
removed: boolean
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /packages
Installed packages. Sealed.
Only the releases the caller may see. Who: signed in (a session or an API key).
Answer (application/json)
{
packages: Package[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /packages
Upload a signed release. Sealed.
A signed .mpk, checked as an install from the registry is (signature, artifact digests, minRuntimeVersion, the package's pinned signer, every service compiles). Only with --dev; otherwise 403 UPLOADS_DISABLED.
Who: an installer (an account holder, or an unscoped API key that is not read-only).
Body (application/octet-stream): the .mpk
Answer (application/json)
{
package: string,
version: string,
signerId: string,
services: {
[key: string]: string
}
}| Status | Codes |
|---|---|
| 400 | BAD_BUNDLE; BAD_PACKAGE; COMPUTE_ABI_MISMATCH; UNSUPPORTED_BUNDLE. details of BAD_BUNDLE: a ServiceRefused, COMPUTE_ABI_MISMATCH: a ServiceRefused, UNSUPPORTED_BUNDLE: a ServiceRefused. |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | DEPLOY_NOT_GRANTED; FORBIDDEN: the credential may not do this (scope, role, governance, read-only); UPLOADS_DISABLED |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /packages/install
Install a release from the registry. Sealed.
Who: an installer (an account holder, or an unscoped API key that is not read-only).
Body (application/json)
{
package: string,
version: string
}Answer (application/json)
{
package: string,
version: string,
signerId: string,
services: {
[key: string]: string
}
}| Status | Codes |
|---|---|
| 400 | BAD_BUNDLE; BAD_PACKAGE; COMPUTE_ABI_MISMATCH; NO_REGISTRY; UNSUPPORTED_BUNDLE. details of BAD_BUNDLE: a ServiceRefused, COMPUTE_ABI_MISMATCH: a ServiceRefused, UNSUPPORTED_BUNDLE: a ServiceRefused. |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | DEPLOY_NOT_GRANTED; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /packages/{package}
One package. Sealed.
The versions the caller may see; 404 when none.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
package | path | string |
Answer (application/json)
Package| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /packages/{package}
Uninstall a package. Sealed.
Every version; refused while an app runs one. Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
package | path | string |
Answer (application/json)
Uninstalled| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /packages/{package}/{version}
Uninstall one version. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
package | path | string |
version | path | string |
Answer (application/json)
Uninstalled| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /packages/{package}/{version}/pipelines
A release's pipelines. Sealed.
The pipelines the release registers, by name: hash, worstCaseFuel (a decimal string), the modules they pin and the canonical pipeline. 404 for a release the caller may not see.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
package | path | string |
version | path | string |
Answer (application/json)
{
[key: string]: {
hash: string,
worstCaseFuel: any,
modules: any,
pipeline: any
}
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
Apps
App instances (contexts): calls, views, events, upgrades, blobs and sealed files.
GET /apps
Apps the caller reaches. Sealed.
Anyone may list public apps. Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
package? | query | string |
bundle? | query | string |
Answer (application/json)
{
apps: AppEntry[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps
Create an app instance. Sealed.
From a release (package, version, service), a deployment's offer (deployment), or an uploaded bundle; in an organization (org), or, naming none, the caller's personal organization. Every app is in an organization. initArgs go to the app's init and metadata is kept as given (both free-form JSON). Answers once init committed; compute says whether the app has a compute component.
Who: an installer (an account holder, or an unscoped API key that is not read-only).
Body (application/json)
{
name?: string,
bundle?: string,
package?: string,
version?: string,
service?: string,
org?: string,
access?: Access,
initArgs?: any,
metadata?: any,
deployment?: string
}Answer (application/json)
{
appId: string,
contextId: string,
group: integer,
replicas: integer[],
compute: boolean
}| Status | Codes |
|---|---|
| 400 | AMBIGUOUS_COMPUTE; BAD_REQUEST: the request is malformed; NOT_OFFERED; NO_SUCH_SERVICE; VERSION_REQUIRED |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | RELEASE_DEADLINE; RUNTIME_TOO_OLD. details of RELEASE_DEADLINE: a ReleaseDeadline, RUNTIME_TOO_OLD: a RuntimeTooOld. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 422 | INIT_FAILED. details of INIT_FAILED: a InitFailed. |
| 429 | QUOTA_EXCEEDED |
| 503 | UNAVAILABLE: the cluster cannot answer now |
GET /apps/{app}
One app. Sealed.
{app} is an app id or its context id (hex(SHA-256(app_id))), here and on every /apps/{app} route.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
App| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /apps/{app}
Delete an app. Sealed.
The owner or an organization admin. Who: a passkey session (an API key is refused).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
appId: string,
deleted: boolean
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/abi
An app's ABI. Sealed.
The ABI its bundle embeds: methods, events, errors and state. abi is the bundle's own document, free-form here: its format is the ABI's, not this API's.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
bundle: string,
abi: any
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/access
Set who may reach an app. Sealed.
A package-bound session: only its own package's app, from one of its package's teams to another. Who: a passkey session (an API key is refused).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
access: Access
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/attestation
Every replica's receipt-key attestation. Sealed.
Each replica's /attestation?purpose=receipts for nonce (32 bytes, hex), or why it could not be had (error), and cluster, the cluster id each quote binds (with the replica's node): the documents are fetched in the clear, so their own cluster and node fields count for nothing. Any other query parameter is ignored.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
nonce | query | string |
Answer (application/json)
{
appId: string,
cluster: string,
replicas: {
node: integer,
attestation: AttestationDoc
} | {
node: integer,
error: string
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/blobs
List an app's blobs. Sealed.
Plain blobs only. Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
blobs: {
blobId: string,
id: string,
size: integer
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/blobs
Upload a blob. Sealed.
A plain blob, stored with the request's Content-Type, which a component app's download answers with: any media type (printable ASCII, 127 bytes at most; another is 400 BAD_REQUEST), application/octet-stream when the request names none. Send the blob's own type, not */*, which would be stored as its type. Any sealed parameter, true or false, is refused 400 USE_FILES_API: sealed files go through /files.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
sealed? | query | boolean |
Body (application/octet-stream): the blob; its Content-Type is the type it is stored and served with
Answer (application/json)
{
blobId: string,
id: string,
size: integer,
index: integer
}| Status | Codes |
|---|---|
| 400 | USE_FILES_API |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | QUOTA_EXCEEDED |
GET /apps/{app}/blobs/{id}
Download a blob. Sealed.
{id} is base58 or hex; grant is a link the app made (BlobRef::grant).
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
id | path | string |
grant? | query | string |
Answer (*/*): OK: the blob: a component app's under the MIME type it was stored with, otherwise application/octet-stream.
| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 503 | UNAVAILABLE: the cluster cannot answer now |
DELETE /apps/{app}/blobs/{id}
Forget a blob. Sealed.
The owner or an organization admin. Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
id | path | string |
Answer (application/json)
{
index: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/blobs/{id}/info
A blob's size. Sealed.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
id | path | string |
Answer (application/json)
{
blobId: string,
id: string,
size: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | NOT_SUPPORTED |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/blobs/{id}/revoke
Invalidate a blob's grants. Sealed.
The grants made so far for a published blob; the owner or an organization admin. Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
id | path | string |
Answer (application/json)
{
index: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/events
An app's events as server-sent events. Sealed.
Committed events from index from, then live ones, each to its audience.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
from? | query | integer |
Answer (text/event-stream): Server-sent events: each committed event the caller is in the audience of.
| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | RATE_LIMITED: a node's limit on open streams or ceremonies |
| 503 | UNAVAILABLE: the cluster cannot answer now |
GET /apps/{app}/files
List an app's sealed files. Sealed.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
files: {
blobId: string,
id: string,
size: integer,
sha256: string
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/files
Upload a sealed file. Sealed.
Up to 16 MiB in one request; the owner and the organization's members. Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/octet-stream): the file
Answer (application/json)
{
blobId: string,
id: string,
size: integer,
sha256: string,
index: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | QUOTA_EXCEEDED |
POST /apps/{app}/files/uploads
Begin a file upload. Sealed.
A session for a file of size bytes, sent in parts of partBytes.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
size: integer
}Answer (application/json)
{
uploadId: string,
partBytes: integer,
parts: integer,
expiresAt: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | QUOTA_EXCEEDED |
GET /apps/{app}/files/uploads/{upload}
Where an upload is. Sealed.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
upload | path | string |
Answer (application/json)
{
uploadId: string,
partBytes: integer,
parts: integer,
expiresAt: integer,
size: integer,
next: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /apps/{app}/files/uploads/{upload}
Abort an upload. Sealed.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
upload | path | string |
Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/files/uploads/{upload}/complete
Commit an upload. Sealed.
Charges and commits the file; a retry answers the same file. 409 UPLOAD_INCOMPLETE names the part still missing.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
upload | path | string |
Answer (application/json)
{
blobId: string,
id: string,
size: integer,
sha256: string,
index: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 409 | UPLOAD_INCOMPLETE. details of UPLOAD_INCOMPLETE: a UploadPosition. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
PUT /apps/{app}/files/uploads/{upload}/parts/{k}
Send one part. Sealed.
Part k (from 0), raw bytes; a part out of order (409 PART_OUT_OF_ORDER), or one that differs from the part sent before as k (409 PART_CONFLICT), answers the next one expected in details.next.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
upload | path | string |
k | path | string |
Body (application/octet-stream): the part
Answer (application/json)
{
next: integer
}| Status | Codes |
|---|---|
| 400 | BAD_PART; BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 409 | PART_CONFLICT; PART_OUT_OF_ORDER. details of PART_CONFLICT: a UploadPosition, PART_OUT_OF_ORDER: a UploadPosition. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 503 | FILES_UNAVAILABLE. details of FILES_UNAVAILABLE: a RetryAfter. |
GET /apps/{app}/files/{id}
One sealed file. Sealed.
Its plaintext size and SHA-256, never its key. Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
id | path | string |
Answer (application/json)
{
blobId: string,
id: string,
size: integer,
sha256: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/files/{id}/export
Export a sealed file's key. Sealed.
The owner and the organization's members. recipient is an X25519 public key (64 hex characters); the file's data key comes back wrapped to it, with the file's segments (each one's hash, hex) and ephemeral public key. The node never answers plaintext or a key in the clear. 30 a minute per account.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
id | path | string |
Body (application/json)
{
recipient: string
}Answer (application/json)
{
app: string,
id: string,
size: integer,
sha256: string,
segments: string[],
ephemeral: string,
wrapped: string
}| Status | Codes |
|---|---|
| 400 | BAD_RECIPIENT; BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | TOO_MANY_EXPORTS |
GET /apps/{app}/files/{id}/segments/{k}
One segment of a sealed file. Sealed.
Segment k (from 0) of the file's ciphertext, raw; the owner and the organization's members.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
id | path | string |
k | path | string |
Answer (*/*): OK: the segment's ciphertext, application/octet-stream.
| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see; NO_SUCH_SEGMENT |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/intents
Call a method. Sealed.
A logged call: the result, the events of the call the caller receives, and the answering node's receipt. A confirm method answers 412 first. An app error is 422 APP_ERROR with details { index, code, fields }; a trap 422 TRAP. args, result and each event's data are the app's own JSON, free-form here: the app's ABI (GET /apps/{app}/abi, or its OpenAPI document) types them.
Who: whoever the app's access admits (a public app: anyone). Step-up: when the method is a confirm method of the app's ABI, answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
method: string,
args?: any,
idempotencyKey?: string,
confirm?: Confirm
}Answer (application/json)
{
index: integer,
result: any,
events: {
kind: string,
data: any
}[],
receipt: Receipt
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | RELEASE_DEADLINE. details of RELEASE_DEADLINE: a ReleaseDeadline. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 413 | ARGS_TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 422 | APP_ERROR; TRAP. details of APP_ERROR: a AppError, TRAP: a Trap. |
| 429 | QUOTA_EXCEEDED |
| 503 | TIMEOUT; UNAVAILABLE: the cluster cannot answer now. details of TIMEOUT: a RetryAfter. |
POST /apps/{app}/metadata
Set an app's metadata. Sealed.
The owner or an organization admin; 16 KiB at most. metadata is the caller's own JSON, free-form, kept as given.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
metadata: any
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/methods/{method}
Call a method by its path. Sealed.
The body of /intents or /views without method, which the path names, as the app's OpenAPI document lists it: a view the running bundle's ABI declares (without confirm) is answered as /views, anything else as /intents, with that route's gate, step-up and limits. Retry-safe as a view always, as a call with idempotencyKey. args, result and each event's data are the app's own JSON, free-form here: the app's ABI (GET /apps/{app}/abi, or its OpenAPI document) types them.
Who: whoever the app's access admits (a public app: anyone). Step-up: when the method is a confirm method of the app's ABI, answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
app | path | string |
method | path | string |
Body (application/json)
{
args?: any,
idempotencyKey?: string,
confirm?: Confirm,
consistency?: "strong" | "stale",
minIndex?: integer
}Answer (application/json)
{
index: integer,
result: any,
events?: {
kind: string,
data: any
}[],
receipt: Receipt
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; RESERVED_METHOD; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | RELEASE_DEADLINE. details of RELEASE_DEADLINE: a ReleaseDeadline. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 413 | ARGS_TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 422 | APP_ERROR; TRAP. details of APP_ERROR: a AppError, TRAP: a Trap. |
| 429 | QUOTA_EXCEEDED |
| 503 | NOT_CAUGHT_UP; TIMEOUT; UNAVAILABLE: the cluster cannot answer now. details of TIMEOUT: a RetryAfter. |
POST /apps/{app}/move
Move an app to another organization. Sealed.
Its data where it is; its files, runs and quotas go to the target, org or app-team access becomes the target's app team of its package. bringMembers adds the source's members who reach it, capped at member. from is the organization it left, null for an app of the caller's own; added the accounts brought; revokedInvites how many invites to its old team were withdrawn.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
toOrg: string,
bringMembers?: boolean,
confirm?: Confirm
}Answer (application/json)
{
appId: string,
from: string | null,
org: string,
access: Access,
created: boolean,
added: string[],
revokedInvites: integer
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/openapi.json
An app's OpenAPI document. Sealed.
Generated from the ABI of the bundle the app runs, under the access /abi has: one POST /apps/{app}/methods/{method} per method, with its arguments, result and errors. Free-form here: it is a document of its own, which a client reads as OpenAPI.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
[key: string]: any
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 410 | UNSUPPORTED_ENGINE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 422 | BAD_ABI |
GET /apps/{app}/pipeline-runs
An app's pipeline runs. Sealed.
The recent runs, newest first, as { runs }; limit 1 to 100. Sizes, hashes and results only for callers who may list the app's files.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
limit? | query | string |
Answer (application/json)
{
[key: string]: any
}| Status | Codes |
|---|---|
| 400 | BAD_LIMIT |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/pipeline-runs/{run}
One pipeline run. Sealed.
Its record: state, version, hash, computeBundle, inputs, params, per-step status, runs, outputs, result, reason and cost (cost and costSoFar for a run with a cap). Sizes, hashes and results only for callers who may list the app's files.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
run | path | string |
Answer (application/json)
{
[key: string]: any
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/pipeline-runs/{run}/cancel
Cancel a pipeline run. Sealed.
The owner and the organization's members. Its pending steps end cancelled and its running steps' runs stop. Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
run | path | string |
Answer (application/json)
{
run: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/pipeline-runs/{run}/events
A pipeline run as server-sent events. Sealed.
Whoever may read the run. Metadata only; at most 64 streams per app per node, and one lasts an hour. Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
run | path | string |
Answer (text/event-stream): Server-sent events: a snapshot, then run and step per change, then end, and the stream closes.
| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | TOO_MANY_SUBSCRIBERS |
GET /apps/{app}/pipeline-runs/{run}/receipt
A pipeline run's receipt. Sealed.
The owner and the organization's members. For an ended run: the receipt, the answering node and its signature over it, by the node's receipt key. Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
run | path | string |
Answer (application/json)
{
receipt: any,
node: string,
signature: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | RUN_NOT_ENDED |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/pipeline-runs/{run}/retry
Retry a pipeline run. Sealed.
The owner and the organization's members. A new run of an ended run's pipeline at the same release, hash and compute component, with the same inputs and params, the limits applied and retryOf set. 202.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
run | path | string |
Body (application/json)
{
limits?: {
[key: string]: {
fuel?: integer,
memoryMib?: integer,
wallSecs?: integer
}
},
maxCost?: string
}Answer (application/json)
{
run: string,
retryOf: string,
worstCase?: string
}| Status | Codes |
|---|---|
| 400 | BAD_LIMITS; BAD_MAX_COST; LIMIT_EXCEEDS_CAP |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | CLUSTER_NOT_UPGRADED; NO_PRICE_TABLE; STILL_RUNNING |
| 410 | OUTPUT_EXPIRED |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | TOO_MANY_PIPELINE_RUNS |
POST /apps/{app}/pipelines/{name}/estimate
Estimate a pipeline run. Sealed.
The owner and the organization's members. Runs, fuel and cost of a run of a pipeline the app's release registers, for inputs (file ids, only counted) or counts, not both; numbers as decimal strings.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
name | path | string |
Body (application/json)
{
inputs?: {
[key: string]: string[]
},
counts?: {
[key: string]: integer
},
params?: {
[key: string]: any
}
}Answer (application/json)
{
steps: {
[key: string]: {
runs: string,
fuel: string,
cost?: string
}
},
fuel: string,
cost?: string,
priceVersion?: integer
}| Status | Codes |
|---|---|
| 400 | BAD_INPUTS; BAD_PARAMS |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see; NO_SUCH_PIPELINE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/pipelines/{name}/runs
Start a pipeline run. Sealed.
The owner and the organization's members. Starts a run of a pipeline the app's release registers. maxCost (micro-units, a decimal string) caps the run, and worstCase answers it. 202.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
name | path | string |
Body (application/json)
{
inputs?: {
[key: string]: string[]
},
params?: {
[key: string]: any
},
maxCost?: string
}Answer (application/json)
{
run: string,
worstCase?: string
}| Status | Codes |
|---|---|
| 400 | BAD_INPUTS; BAD_MAX_COST; BAD_PARAMS |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see; NO_SUCH_PIPELINE |
| 409 | CLUSTER_NOT_UPGRADED; NO_PRICE_TABLE |
| 410 | OUTPUT_EXPIRED |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 422 | PIPELINES_NEED_ONE_SERVICE |
| 429 | TOO_MANY_PIPELINE_RUNS |
GET /apps/{app}/presence
Who is present. Sealed.
One entry per present device (a session's passkey, or an API key): its account, device and state (hex). Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
present: {
account: string,
device: string,
state: string | null
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/presence
Publish presence. Sealed.
The caller's presence state (hex), in sequence; not logged. A null (or absent) state retracts it.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
seq: integer,
state?: string | null
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | BAD_STATE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/presence/stream
Presence as server-sent events. Sealed.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (text/event-stream): Server-sent events: a snapshot, then presence diffs.
| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/runs
An app's compute runs. Sealed.
Newest first, limit (1 to 100, default 20) at a time; next is the before of the next page, null on the last.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
limit? | query | string |
before? | query | string |
Answer (application/json)
{
runs: Run[],
next: string | null
}| Status | Codes |
|---|---|
| 400 | BAD_CURSOR; BAD_LIMIT |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/runs/{run}
One compute run. Sealed.
Its record without arguments or keys: method, state, cancelRequested, startTsMs, attempts, input and output ids (sizes and SHA-256 only for callers who may list the app's files), usage, and progress as the leader last polled it.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
run | path | string |
Answer (application/json)
Run| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/runs/{run}/logs
A compute run's attempt logs. Sealed.
Each attempt's module log, as a sealed file of the app: { attempt, id, size, sha256 }. Only for those who may handle the app's files; the bytes are a files export.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
run | path | string |
Answer (application/json)
{
logs: {
attempt: integer,
id: string,
size: integer,
sha256: string
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /apps/{app}/storage
What an app stores. Sealed.
Keys, bytes and blobs held, and lastWriteAt (Unix seconds of its last committed write, null before one).
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
keys: integer,
bytes: integer,
blobs: integer,
blobBytes: integer,
lastWriteAt?: integer | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/transfer
Hand an app to another account. Sealed.
The owner (for an organization's app, while a member and in the app's team), or an organization admin; an organization's app only to a member. Answers null.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
to: string,
confirm?: Confirm
}Answer (application/json)
null| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/upgrade
Upgrade an app instance. Sealed.
To a release (version, of the app's own package unless package names another) or a bundle, code only: the state stays and is read by the new code. Whoever the package's manifest names (upgrades: the owner, or its publisher's MANAGE_APPLICATION holders), with a step-up over { bundle, migrate, manifest }; an upgrade key signs in place of it. A refused or failed upgrade leaves the app on its release and answers 422 UPGRADE_FAILED with the app log's error in details (MigrationsNotSupported when migrate is named: there are no migrations in this version). error is the app log's error value (null when it ran), free-form: the app's own.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
bundle?: string,
package?: string,
version?: string,
service?: string,
confirm?: Confirm,
migrate?: string
}Answer (application/json)
{
index: integer,
status: string,
error: any,
compute: boolean
}| Status | Codes |
|---|---|
| 400 | AMBIGUOUS_COMPUTE; BAD_BUNDLE; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; VERSION_REQUIRED. details of BAD_BUNDLE: a ServiceRefused. |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | CONFLICT: the state does not allow it now; RELEASE_DEADLINE; RUNTIME_TOO_OLD. details of RELEASE_DEADLINE: a ReleaseDeadline, RUNTIME_TOO_OLD: a RuntimeTooOld. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 422 | UPGRADE_FAILED. details of UPGRADE_FAILED: a Applied. |
GET /apps/{app}/usage
An app's runs per day. Sealed.
The owner or an organization admin: today and the 30 days before it, figures as decimal strings; wallMs is information only.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
today: UsageDay,
days: UsageDay[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /apps/{app}/views
Read with a view method. Sealed.
Read linearizably (consistency: "strong", the default; any value but "stale" reads as it): the replica answering waits until it applied the index the app's leader names once it confirmed it leads, and sends the view to the leader if it cannot catch up; or ("stale") on the replica answering, as it stands; minIndex waits until the replica applied it (503 NOT_CAUGHT_UP). args, result and each event's data are the app's own JSON, free-form here: the app's ABI (GET /apps/{app}/abi, or its OpenAPI document) types them.
Who: whoever the app's access admits (a public app: anyone).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
method: string,
args?: any,
consistency?: "strong" | "stale",
minIndex?: integer
}Answer (application/json)
{
index: integer,
result: any,
receipt: Receipt
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 422 | APP_ERROR; TRAP. details of APP_ERROR: a AppError, TRAP: a Trap. |
| 503 | NOT_CAUGHT_UP; TIMEOUT. details of TIMEOUT: a RetryAfter. |
GET /apps/{app}/xcalls
An app's cross-app calls. Sealed.
The owner or an organization admin: how many calls wait in its outbox for delivery (pending, a count), and its dead letters, oldest first (atMs: the entry time it was dead-lettered at, Unix milliseconds).
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
app | path | string |
Answer (application/json)
{
pending: integer,
deadLetters: DeadLetter[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 503 | UNAVAILABLE: the cluster cannot answer now |
POST /pipelines/validate
Validate a pipeline. Sealed.
Every problem of source; with package and version (both, a release the caller sees) also against that release's methods, modules and the cluster's pools. Writes nothing.
Who: signed in (a session or an API key).
Body (application/json)
{
source: string,
package?: string,
version?: string
}Answer (application/json)
{
ok: boolean,
errors: {
path: string,
code: string,
message: string
}[],
pipeline?: any,
worstCaseFuel?: string,
worstCaseCost?: string
}| Status | Codes |
|---|---|
| 400 | BAD_RELEASE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
Organizations
Organizations, members, teams, invites, approvals and upgrade runs.
POST /invites/{token}/redeem
Join with an invite. Sealed.
No passkey prompt: the node signs the redemption with the token's key. Answers the organization joined. Who: a passkey session (an API key is refused).
| Parameter | In | Type |
|---|---|---|
token | path | string |
Answer (application/json)
{
org: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs
Create an organization. Sealed.
recoveryKey is the public half of an organization recovery key. Every account also has a personal organization from sign-up (personal in /auth/me), which this does not make.
Who: a passkey session (an API key is refused).
Body (application/json)
{
name: string,
recoveryKey?: string
}Answer (application/json)
{
orgId: string
}| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 429 | QUOTA_EXCEEDED |
GET /orgs/{org}
One organization. Sealed.
As the directory records it, with only the teams the caller reaches or manages and the people they see; and its mode (from its app teams), the accounts that may approve its releases (releaseApprovers), the keys it publishes under (publishes), and newWorkStopped: the release whose passed deadline stops new work in it (after, RFC 3339), null when none does. Those four are absent from a node older than they are (1.0.0-rc.1 sends none of them).
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Answer (application/json)
Org| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /orgs/{org}
Delete an organization. Sealed.
With its teams, invites and apps; the owner. apps: the apps deleted with it.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{
apps: string[]
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/all-apps
Give a member every app added later. Sealed.
Or stop it (allApps: false); apps already there are not touched. The owner or an admin; 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
account: string,
allApps: boolean,
confirm?: Confirm
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /orgs/{org}/app-teams
The organization's app teams. Sealed.
A member: each app team's package, id, name, join, member count, default capabilities, and whether the caller is in it or manages it (a guest: only their own).
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Answer (application/json)
{
mode: "legacy" | "standalone" | "shared",
appTeams: {
package: string,
teamId: string,
name: string,
join: TeamJoin,
memberCount: integer,
defaultCapabilities: integer | null,
member: boolean,
manages: boolean
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/app-teams
Give apps app teams, or open or close one. Sealed.
The owner or an admin; keep names who stays when a team closes; childTeams says whether the app team's members make restricted teams below it (private channels), adding or removing CREATE_CHILD_TEAM (absent: as they are). Naming join or childTeams on any package leaves shared unset to mean no other team. 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
apps?: {
package: string,
name?: string,
instances?: string[],
join?: TeamJoin,
keep?: string[],
childTeams?: boolean
}[],
shared?: boolean,
confirm?: Confirm
}Answer (application/json)
{
mode: "legacy" | "standalone" | "shared",
teams: {
package: string,
teamId: string,
created: boolean,
apps: string[],
added: integer,
join: TeamJoin | null,
dropped: integer
}[]
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; TOO_MANY_PACKAGES; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /orgs/{org}/apps
The organization's apps. Sealed.
As GET /auth/apps, for the apps the caller reaches or manages; 404 to a non-member.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
after? | query | string |
limit? | query | integer |
Answer (application/json)
{
scope: AppScope,
governance: Governance,
approvedReleases: string[] | null,
clusterReleases: ClusterRelease[],
apps: ReportApp[],
next: string | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /orgs/{org}/backup-key
The organization's backup key. Sealed.
The X25519 public key its apps' recovery-disk backups are sealed to (key, null while none is set), and how many apps that covers. Any member; 404 outside the organization.
Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Answer (application/json)
BackupKeyAnswer| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/backup-key
Set the organization's backup key. Sealed.
publicKey: 64 lowercase hex, an X25519 public key whose private half its holder keeps (never a node). Those who upgrade all the organization's apps (org-wide MANAGE_APPLICATION), where owners upgrade apps; replaces the key before. 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
publicKey: string,
confirm?: Confirm
}Answer (application/json)
BackupKeyAnswer| Status | Codes |
|---|---|
| 400 | BAD_BACKUP_KEY; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/capabilities
Set capabilities. Sealed.
A member's (account), in a team (team), or a team's default; the capability bits. 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
account?: string,
team?: string,
capabilities: integer,
confirm?: Confirm
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /orgs/{org}/invites
The organization's invites. Sealed.
Their keys and terms, never a token: expiresAt Unix seconds; createdBy and createdAt are null on an invite from before they were kept.
Who: a passkey session (an API key is refused).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Answer (application/json)
{
invites: {
inviteKey: string,
role: OrgRole,
teams: string[],
usesLeft: integer,
expiresAt: integer,
expired: boolean,
createdBy: string | null,
createdAt: integer | null,
allApps: boolean
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/invites
Make an invite. Sealed.
A token for role and teams, uses times within ttlSecs; allApps (an admin's) also gives every app added later. 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
role: OrgRole,
teams?: string[],
ttlSecs?: integer,
uses?: integer,
allApps?: boolean,
confirm?: Confirm
}Answer (application/json)
{
token: string
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /orgs/{org}/invites/{key}
Revoke an invite. Sealed.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
key | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /orgs/{org}/members
Members' lockout risk. Sealed.
detail=security (the only listing: without it, or with another value, 400 BAD_REQUEST), the owner or an admin: each member's passkeys (1, 2 or "3+"), recovery code, last active UTC day and sessions. 403 below admin, 404 outside the organization.
Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
org | path | string |
detail? | query | "security" |
Answer (application/json)
{
orgId: string,
members: {
account: string,
name: string | null,
role: OrgRole,
teams: string[],
passkeys: integer | "3+",
recoveryCode: boolean,
lastActiveDay: string | null,
sessions: integer
}[]
}| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/members
Set a member's role. Sealed.
owner moves ownership. 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
account: string,
role: OrgRole,
confirm?: Confirm
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /orgs/{org}/members/{account}
Remove a member, or leave. Sealed.
412 first; the retry's JSON body is { confirm }.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
account | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/members/{account}/metadata
Set a member's metadata. Sealed.
metadata is the caller's own JSON, free-form, kept as given.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
account | path | string |
Body (application/json)
{
metadata: any
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/members/{account}/teams
Set a member's rows in several teams. Sealed.
Each team judged as POST /orgs/{org}/teams/{team}/members would judge it, and none set unless every one may be (a row's absent role is member; absent capabilities, a new row takes the defaults and an existing row keeps its own). 1 to 64 distinct teams; one passkey, 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
account | path | string |
Body (application/json)
{
teams: {
team: string,
role?: TeamRole,
capabilities?: integer
}[],
confirm?: Confirm
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | BAD_TEAMS; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /orgs/{org}/members/{account}/teams
Remove a member from several teams, or leave them. Sealed.
Each judged as DELETE /orgs/{org}/teams/{team}/members/{account} would judge it, and none taken unless every one may be. 1 to 64 distinct teams; one passkey, 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
account | path | string |
Body (application/json)
{
teams: string[],
confirm?: Confirm
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | BAD_TEAMS; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/metadata
Set an organization's metadata. Sealed.
metadata is the caller's own JSON, free-form, kept as given.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
metadata: any
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/name
Rename an organization. Sealed.
The owner or an admin, to a name that fits as a new organization's would; 412 first.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
name: string,
confirm?: Confirm
}Answer (application/json)
{
orgId: string,
name: string
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/outbound
Approve outbound prefixes for the organization's apps. Sealed.
The owner; 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
package: string,
prefixes?: OutboundSelection,
replace?: boolean,
confirm?: Confirm
}Answer (application/json)
OutboundApproved| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/packages/{package}/upgrade
Upgrade every instance of a publisher's package. Sealed.
An upgrade run over every app on the cluster that runs the package, by its publisher's MANAGE_APPLICATION holders.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
package | path | string |
Body (application/json)
{
version: string,
migrate?: string,
confirm?: Confirm
}Answer (application/json)
UpgradeRun| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/publishers
Bind a package signing key. Sealed.
The key's signature over the binding proves the organization holds it; then its MANAGE_APPLICATION holders upgrade the apps of packages that name publisher. Answers the key's binding generation now.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
signerId: string,
publicKey: string,
signature: string,
confirm?: Confirm
}Answer (application/json)
{
generation: integer
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/recovery
Set the organization's recovery key. Sealed.
Set or rotate it (publicKey: base64url Ed25519 public key), or remove it (publicKey: null; an absent publicKey removes it too); the owner; cancels a recovery under way. 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
publicKey?: string | null,
confirm?: Confirm
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | BAD_RECOVERY_KEY; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/recovery/cancel
Cancel an organization recovery. Sealed.
The owner; 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/recovery/finish
Finish an organization recovery. Sealed.
The account that started it, once readyAt passed; 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{
org: string,
previousOwners: string[]
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 409 | RECOVERY_NOT_READY. details of RECOVERY_NOT_READY: a RecoveryNotReady. |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/recovery/start
Start an organization recovery. Sealed.
The recovery seed's signature handing the organization to the caller. Who: an account holder (a passkey session not bound to an app's frontend).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
nonce: string,
signature: string
}Answer (application/json)
{
startedAt: integer,
readyAt: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only); WRONG_RECOVERY_KEY |
| 409 | RECOVERY_PENDING |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/releases
Approve a mero-tee release for the organization's apps. Sealed.
The owner; 412 first.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
version: string,
approved?: boolean,
confirm?: Confirm
}Answer (application/json)
ApprovedReleases| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/teams
Create a team. Sealed.
An admin, a lead of parent, a member with CREATE_TEAM at the top, or a member who holds CREATE_CHILD_TEAM under parent (a restricted team only). A package-bound session: only its own package's teams (its app team and the teams below it): parent one of them.
Who: a passkey session (an API key is refused).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
name: string,
parent?: string,
join: TeamJoin
}Answer (application/json)
{
teamId: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /orgs/{org}/teams/{team}
One team. Sealed.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
team | path | string |
Answer (application/json)
TeamView| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/teams/{team}
Update a team. Sealed.
Rename, open or restrict, move under another parent, or set its metadata (the caller's own JSON, free-form, kept as given). parent absent leaves the team where it is; parent: null (an explicit null) moves it to the top; a team id moves it under that team. A package-bound session: only its own package's teams (its app team and the teams below it): a team below its app team, moved only within.
Who: a passkey session (an API key is refused).
| Parameter | In | Type |
|---|---|---|
org | path | string |
team | path | string |
Body (application/json)
{
name?: string,
join?: TeamJoin,
parent?: string | null,
metadata?: any
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /orgs/{org}/teams/{team}
Delete a team. Sealed.
With the teams and apps below it. A package-bound session: only its own package's teams (its app team and the teams below it): a team below its app team whose apps are all its package's.
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
team | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{
teams: string[],
apps: string[]
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/teams/{team}/members
Add or change a team member. Sealed.
A package-bound session: only its own package's teams (its app team and the teams below it).
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
team | path | string |
Body (application/json)
{
account: string,
lead?: boolean,
role?: TeamRole,
capabilities?: integer,
confirm?: Confirm
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /orgs/{org}/teams/{team}/members/{account}
Remove a team member, or leave. Sealed.
A package-bound session: only its own package's teams (its app team and the teams below it).
Who: a passkey session (an API key is refused). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
team | path | string |
account | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/upgrade
Start an upgrade run. Sealed.
Upgrade every app of the organization (or of team, with cascade its subtree) that runs package to version, with one passkey assertion over the whole run; whoever holds MANAGE_APPLICATION there. Each app is upgraded as POST /apps/{app}/upgrade would; GET /orgs/{org}/upgrades/{run} follows it.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
package: string,
version: string,
team?: string,
cascade?: boolean,
migrate?: string,
confirm?: Confirm,
operatorProof?: OperatorProof
}Answer (application/json)
UpgradeRun| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /orgs/{org}/upgrades/{run}
An upgrade run's progress. Sealed.
A member of the organization. Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
run | path | string |
Answer (application/json)
UpgradeRun| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /orgs/{org}/upgrades/{run}/retry
Retry an upgrade run's failed apps. Sealed.
As a new run under the same terms: a passkey step-up for a member's run, the operator's signature for an operator's run (with the ops token).
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
org | path | string |
run | path | string |
Body (application/json, optional): May be absent.
{
confirm?: Confirm,
operatorProof?: OperatorProof
}Answer (application/json)
UpgradeRun| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /orgs/{org}/usage
An organization's usage. Sealed.
An admin: how many apps the organization develops, what their runs used today (decimal strings) and the cluster's quotas; a member gets 403.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
org | path | string |
Answer (application/json)
{
apps: integer,
developerFuelToday: string /* decimal */,
developerWritesToday: string /* decimal */,
quotas: Quotas
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
Consent
Approvals an app's frontend asks for on the node's own consent page.
POST /consent/requests
Ask the account's owner to approve. Sealed.
From an app's frontend: a release approval, an upgrade of its instance, outbound prefixes, a new organization, a new invite or joining with one, leaving an organization, a member's removal, role, teams or capabilities, an invite's revocation, an organization's name, its deletion, defaults or all-apps grants, approved on the node's own consent page (url), which takes the passkey. What the approval made (orgId, an invite's token, the org joined, a rename's { orgId, name }, a deletion's apps) is in /consent/{request}/result's outcome. 64 KiB at most.
Who: a passkey session (an API key is refused).
Body (application/json)
{
kind: "release",
scope: "account" | {
org: string
},
subject: {
version: string,
withdraw?: boolean
},
returnTo: string
} | {
kind: "upgrade",
subject: {
app: string,
toVersion: string
},
returnTo: string
} | {
kind: "outbound",
scope: "account" | {
org: string
},
subject: {
package?: string,
prefixes?: string[]
},
returnTo: string
} | {
kind: "createOrg",
subject: {
name: string
},
returnTo: string
} | {
kind: "createInvite",
subject: {
org: string,
role: "guest" | "member" | "admin",
teams?: string[],
ttlSecs?: integer,
uses?: integer,
allApps?: boolean
},
returnTo: string
} | {
kind: "acceptInvite",
subject: {
token: string
},
returnTo: string
} | {
kind: "leaveOrg",
subject: {
org: string
},
returnTo: string
} | {
kind: "removeMember",
subject: {
org: string,
account: string
},
returnTo: string
} | {
kind: "setMemberRole",
subject: {
org: string,
account: string,
role: "guest" | "member" | "admin" | "owner"
},
returnTo: string
} | {
kind: "setMemberTeams",
subject: {
org: string,
account: string,
teams: {
team: string,
role?: "lead" | "member" | "readOnly",
capabilities?: integer
}[]
},
returnTo: string
} | {
kind: "removeMemberTeams",
subject: {
org: string,
account: string,
teams: string[]
},
returnTo: string
} | {
kind: "revokeInvite",
subject: {
org: string,
inviteKey: string
},
returnTo: string
} | {
kind: "renameOrg",
subject: {
org: string,
name: string
},
returnTo: string
} | {
kind: "deleteOrg",
subject: {
org: string
},
returnTo: string
} | {
kind: "setCapabilities",
subject: {
org: string,
account?: string,
team?: string,
capabilities: integer
},
returnTo: string
} | {
kind: "setAllApps",
subject: {
org: string,
account: string,
allApps: boolean
},
returnTo: string
}Answer (application/json)
{
requestId: string,
url: string,
code: string,
expiresAt: integer
}| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 413 | TOO_LARGE |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /consent/{request}/result
What became of a consent request. Sealed.
decidedAt (Unix seconds) is null while it is pending. outcome, once approved, is what the approval made: { orgId } for createOrg (with teamId, the asking app's own team the organization starts with, when an app's frontend asked on a cluster that makes it), { token } for createInvite, { org } for acceptInvite, { orgId, name } for renameOrg, { apps } (the apps deleted) for deleteOrg; absent for the other kinds.
Who: a passkey session (an API key is refused).
| Parameter | In | Type |
|---|---|---|
request | path | string |
Answer (application/json)
{
requestId: string,
kind: "release" | "upgrade" | "outbound" | "createOrg" | "createInvite" | "acceptInvite" | "leaveOrg" | "removeMember" | "setMemberRole" | "setMemberTeams" | "removeMemberTeams" | "revokeInvite" | "renameOrg" | "deleteOrg" | "setCapabilities" | "setAllApps",
status: "pending" | "approved" | "declined",
decidedAt: integer | null,
outcome?: {
orgId?: string,
teamId?: string,
token?: string,
org?: string,
name?: string,
apps?: string[]
}
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
| 503 | UNAVAILABLE: the cluster cannot answer now |
Sign-up and deployments
The cluster's owner: the sign-up policy, deployers and deployments.
GET /deployers
The deployers. Sealed.
The operator, or the cluster's owner: the deployments and deployers governance, the owner (null until named), and every grant (until RFC 3339 and untilSecs, null for none; grantedAt RFC 3339; deployer null for a key it cannot read).
Who: an account holder (a passkey session not bound to an app's frontend).
Answer (application/json)
{
deployments: "open" | "granted",
deployers: "operator" | "owner",
owner: Deployer | null,
grants: {
key: string,
deployer: Deployer | null,
until: string | null,
untilSecs: integer | null,
grantedAt: string,
grantedBy: string
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /deployers
Grant a deployer. Sealed.
The cluster's owner, with a passkey.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
deployer: Deployer,
until?: string,
operatorProof?: OperatorProof,
confirm?: Confirm
}Answer (application/json)
{
key: string,
deployer: Deployer,
grant: DeployerGrant
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /deployers/{key}
Revoke a deployer. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
key | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{
key: string
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /deployments
Deployments. Sealed.
The deployments the caller manages. Who: signed in (a session or an API key).
Answer (application/json)
{
deployments: Deployment[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /deployments
Create a deployment. Sealed.
A named set of releases an owner (an account or organization) offers for others to instantiate. Answers its id, the record as made (no apps yet) and its frontend host (null on a node with no apps domain).
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
name: string,
owner: Deployer,
confirm?: Confirm
}Answer (application/json)
{
id: string,
deployment: DeploymentRecord,
host: string | null
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /deployments/{id}
One deployment. Sealed.
As anyone may read it: its name, its owner's kind and name (null when unknown), and the releases it offers; never its managers or customers.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
id | path | string |
Answer (application/json)
{
id: string,
host: string | null,
name: string,
owner: {
kind: "account" | "org",
name: string | null
},
apps: {
app: string,
package: string,
version: string
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /deployments/{id}
Delete a deployment. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
id | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{
deployment: string
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /deployments/{id}/apps
Offer a release in a deployment. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
id | path | string |
Body (application/json)
{
app: string,
package: string,
version: string,
confirm?: Confirm
}Answer (application/json)
{
deployment: string,
app: string
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /deployments/{id}/apps/{app}
Withdraw an offer. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
id | path | string |
app | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
{
deployment: string,
app: string
}| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /deployments/{id}/orgs
The organizations a deployment serves. Sealed.
For its managers: each organization with instances from it, its name (null when unknown), member counts (activeMembers30d: active in the last 30 days), its instances and the releases they run, and when its first was created (RFC 3339); instances outside an organization, or in a personal organization, are only counted (outsideOrgs). Never who the members are.
Who: signed in (a session or an API key).
| Parameter | In | Type |
|---|---|---|
id | path | string |
Answer (application/json)
{
deployment: string,
orgs: {
orgId: string,
name: string | null,
memberCount: integer,
activeMembers30d: integer,
instances: integer,
apps: {
app: string,
version: string
}[],
firstCreatedAt: string
}[],
outsideOrgs: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /sign-up
The sign-up policy. Sealed.
Who may create an account here, the cluster's name and the tag a sign-in uses to pick the person's passkey for it. Who: anyone.
Answer (application/json)
{
policy: SignUp,
orgInvites: boolean,
signUpInvites: boolean,
inviteRequired: boolean,
cluster: string,
passkeyTag: string
}POST /sign-up
Set the sign-up policy. Sealed.
The cluster's owner, once named, with a passkey (412 first).
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
policy: SignUp,
operatorProof?: OperatorProof,
confirm?: Confirm
}Answer (application/json)
SignUpSet| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
GET /sign-up/invites
Cluster sign-up invites. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend).
Answer (application/json)
{
signUp: {
policy: SignUp,
orgInvites: boolean,
signUpInvites: boolean,
inviteRequired: boolean
},
runBy: "owner" | "operator",
invites: SignUpInvite[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
POST /sign-up/invites
Issue a cluster sign-up invite. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
Body (application/json)
{
uses?: integer,
ttlSecs?: integer,
confirm?: Confirm
}Answer (application/json)
{
token: string,
inviteKey: string,
uses: integer,
expiresAt: string,
expiresAtSecs: integer,
createdBy: string,
createdAt: string
}| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed; EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE; WRONG_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
DELETE /sign-up/invites/{key}
Withdraw a cluster sign-up invite. Sealed.
Who: an account holder (a passkey session not bound to an app's frontend). Step-up: answers 412 CONFIRM_REQUIRED first; send the same request again with confirm, a passkey assertion over details.challenge.
| Parameter | In | Type |
|---|---|---|
key | path | string |
Body (application/json, optional): May be absent.
ConfirmOnlyAnswer (application/json)
InviteKey| Status | Codes |
|---|---|
| 400 | EXPIRED_CHALLENGE; UNKNOWN_CHALLENGE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 412 | CONFIRM_REQUIRED: a passkey assertion is needed; details carries the challenge. details of CONFIRM_REQUIRED: a ConfirmRequired. |
| 421 | WRONG_NODE: this node runs a release the account's owners have not approved, so it neither issues nor takes the account's sessions; send it to another node of the cluster (no details; nothing was spent) |
Ops
The operator's routes: every one needs the ops token; decisions are signed with the operator key.
GET /ops/apps
What each app runs. Sealed.
Each app's bundle, package, publisher, who holds its upgrades and release approvals, its last upgrade, approved releases, replicas' releases and lastWriteAt.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
after? | query | string |
limit? | query | integer |
Answer (application/json)
{
fresh: boolean,
governance: Governance,
apps: ReportApp[],
next: string | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/apps/{app}/replicas
Move an app's replicas. Sealed.
Signed over <app> / __set_replicas / { replicas } (sorted); at least min(3, nodes) registered nodes, each on a release the app's owner approved. The set it already has answers unchanged: true. status is the app group's Raft status when the move finished (as the leader saw it).
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
replicas: integer[],
operatorProof?: OperatorProof
}Answer (application/json)
{
status: {
group: integer,
leader: integer | null,
is_leader: boolean,
term: integer,
last_log: integer | null,
applied: integer,
voters: integer[],
learners: integer[]
},
unchanged: boolean
}| Status | Codes |
|---|---|
| 400 | DUPLICATE_REPLICA; JOB_NODE; TOO_FEW; UNKNOWN_NODE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | MOVE_IN_PROGRESS; RUNTIME_TOO_OLD. details of RUNTIME_TOO_OLD: a RuntimeTooOld. |
| 421 | NOT_LEADER: send it to the leader named in details.leaderUrl. details of NOT_LEADER: a NotLeader. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/apps/{app}/restore
Restore an app from its sealed backup. Sealed.
Signed over <app> / __restore_app / { backup, sha256 }. The receiving node holds the backup (backup, else the newest, in {backup-dir}/{app}/) and seeds the restore; answers once every replica holds the restored state: the rows restored, the backup (format 0, with merod and release null, for one written before manifests) and the app group's Raft status. recovery restores from a recovery-disk file instead (in the app's holder's directory under --recover-from, else --recovery-dir), opened with the data key its holder opened from it (hex); backup is then the file's name and sha256 its body's.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
backup?: string,
recovery?: {
file: string,
key: string
},
operatorProof?: OperatorProof
}Answer (application/json)
{
app: string,
group: integer,
rows: integer,
backup: {
name: string,
index: integer,
format: integer,
merod: string | null,
release: string | null
},
status: GroupStatus
}| Status | Codes |
|---|---|
| 400 | BAD_BACKUP; BAD_RECOVERY_FILE; BAD_RECOVERY_KEY; BAD_REQUEST: the request is malformed; NOT_A_REPLICA_NODE; UNATTESTED_RECOVERY_FILE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | BACKUP_NOT_FOUND |
| 409 | BACKUP_FROM_NEWER_RELEASE; BUNDLE_GONE; MOVE_IN_PROGRESS; NO_BACKUP_DIR; RECOVERY_SEGMENTS_MISSING; UNKNOWN_BACKUP_FORMAT; UPGRADE_PENDING. details of UPGRADE_PENDING: a UpgradePending. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/apps/{app}/upgrade
Upgrade an app as the operator. Sealed.
To a release the operator installed, where the operator holds app upgrades. error is the app log's error value (null when it ran), free-form: the app's own.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
app | path | string |
Body (application/json)
{
bundle?: string,
package?: string,
version?: string,
service?: string,
migrate?: string,
operatorProof?: OperatorProof
}Answer (application/json)
{
index: integer,
status: string,
error: any,
compute: boolean
}| Status | Codes |
|---|---|
| 400 | AMBIGUOUS_COMPUTE; BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | NOT_INSTALLED; RELEASE_DEADLINE; RUNTIME_TOO_OLD. details of RELEASE_DEADLINE: a ReleaseDeadline, RUNTIME_TOO_OLD: a RuntimeTooOld. |
| 422 | UPGRADE_FAILED. details of UPGRADE_FAILED: a Applied. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/backup
Snapshot the apps this node leads. Sealed.
Into --backup-dir. With all=true, every group this node holds, leader or not: what a node of a cluster that lost a majority still has, to found the cluster again from (merod --bootstrap --restore-from). written: how many snapshots it wrote.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
all? | query | boolean |
Answer (application/json)
{
written: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
GET /ops/backup-key
The operator's backup key. Sealed.
The X25519 public key every app's recovery-disk backups are sealed to where the operator upgrades apps (key, null while none is set).
Who: the ops token.
Answer (application/json)
BackupKeyAnswer| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/backup-key
Set the operator's backup key. Sealed.
Signed over operator / __set_backup_key / { publicKey }, where the operator upgrades apps (else 403). publicKey: 64 lowercase hex, an X25519 public key whose private half the operator keeps (never a node).
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
publicKey: string,
operatorProof?: OperatorProof
}Answer (application/json)
BackupKeyAnswer| Status | Codes |
|---|---|
| 400 | BAD_BACKUP_KEY |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | FEATURE_NOT_ACTIVE. details of FEATURE_NOT_ACTIVE: a FeatureNotActive. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/cluster
The cluster's identity. Sealed.
The cluster's name and the identity this replica holds (hex). Who: the ops token.
Answer (application/json)
{
cluster: string,
identity: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/cluster-owner
Name the cluster's owner. Sealed.
The account or organization that then runs sign-up and deployers with passkeys; once.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
owner: Deployer,
operatorProof?: OperatorProof
}Answer (application/json)
{
owner: Deployer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | CONFLICT: the state does not allow it now |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/deployers
Grant a deployer. Sealed.
An account or organization that may install where deployments are granted, until an RFC 3339 time.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
deployer: Deployer,
until?: string,
operatorProof?: OperatorProof,
confirm?: Confirm
}Answer (application/json)
{
key: string,
deployer: Deployer,
grant: DeployerGrant
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
DELETE /ops/deployers/{key}
Revoke a deployer. Sealed.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
key | path | string |
Body (application/json, optional): May be absent.
ProofOnlyAnswer (application/json)
{
key: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/deployers/{key}/revoke
Revoke a deployer (POST). Sealed.
The same as the DELETE, for an HTTP client whose DELETE carries no body.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
key | path | string |
Body (application/json, optional): May be absent.
ProofOnlyAnswer (application/json)
{
key: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/deployments/granted
Require deployer grants. Sealed.
From now on only granted deployers install; once.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json, optional): May be absent.
ProofOnlyAnswer (application/json)
{
governance: Governance
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | CONFLICT: the state does not allow it now |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/job-nodes/{id}/attestation
Whether the cluster accepts a job node. Sealed.
Runs the check the leader makes before it sends a job node work: a quote that passes the release policy, this cluster and node, this cluster's identity, a release not retired (not the per-app release approval). admitted carries the attested release; refused (final), with the reason: a 400 or 404 from the node, a 2xx that is oversized or does not decode, a failed verification, or a 400 or 404 from the collateral source on the PCK certificate or TCB info request; unreachable (transient), with the reason: anything else, including no answer, any other status from the node and any other collateral failure. 503 when this node's directory is stale. A verified answer is reused for up to a minute.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
id | path | string |
Answer (application/json)
{
state: "admitted",
node: integer,
release: string
} | {
state: "refused" | "unreachable",
node: integer,
reason: string
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 503 | UNAVAILABLE: the cluster cannot answer now |
GET /ops/metrics
Prometheus metrics. Sealed.
Including per-app usage for billing. --metrics-listen ADDR also serves it as plain GET /metrics there.
Who: the ops token.
Answer (text/plain): OK: the Prometheus text format.
| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/nodes
Register a node. Sealed.
Signed with the operator key over cluster / __register_node / { id, addr, zone }. The system leader adds it as a learner and promotes caught-up learners while fewer than 3 voters are left; role: job registers a compute node (in pool).
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
id: integer,
addr: string,
zone?: string,
operatorProof?: OperatorProof,
role?: "replica" | "job",
pool?: string
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | BAD_ADDRESS; BAD_POOL; NODE_HOLDS_CLUSTER; POOL_FOR_JOB_NODES |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | ADDRESS_TAKEN |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
DELETE /ops/nodes/{id}
Remove a node. Sealed.
One no app keeps a replica on; the system leader (elsewhere 421 NOT_LEADER); signed over __remove_node / { id }.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
id | path | string |
Body (application/json, optional): May be absent.
ProofOnlyAnswer (application/json)
{
status: {
group: integer,
leader: integer | null,
is_leader: boolean,
term: integer,
last_log: integer | null,
applied: integer,
voters: integer[],
learners: integer[]
}
}| Status | Codes |
|---|---|
| 400 | LAST_NODE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 421 | NOT_LEADER: send it to the leader named in details.leaderUrl. details of NOT_LEADER: a NotLeader. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/nodes/{id}/receipt-key
A node's receipt key. Sealed.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
id | path | string |
Answer (application/json)
{
node: integer,
key: string,
release: string,
attestedAt: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
GET /ops/orgs
Each organization's approved releases. Sealed.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
after? | query | string |
limit? | query | integer |
Answer (application/json)
{
fresh: boolean,
governance: Governance,
orgs: {
org: string,
approvedReleases: string[] | null
}[],
next: string | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/orgs/{org}/upgrade
An operator's upgrade run. Sealed.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
org | path | string |
Body (application/json)
{
package: string,
version: string,
team?: string,
cascade?: boolean,
migrate?: string,
confirm?: Confirm,
operatorProof?: OperatorProof
}Answer (application/json)
UpgradeRun| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 404 | NOT_FOUND: no such object, or one the caller may not see |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/outbound
Approve outbound prefixes. Sealed.
Where the operator holds outbound approvals.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
package: string,
prefixes?: OutboundSelection,
replace?: boolean,
operatorProof?: OperatorProof
}Answer (application/json)
OutboundApproved| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/packages
The releases the operator installed. Sealed.
Who: the ops token.
Answer (application/json)
{
packages: Package[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/packages
Install an uploaded release as the operator. Sealed.
Who: the ops token.
Body (application/octet-stream): the .mpk
Answer (application/json)
{
package: string,
version: string,
signerId: string,
services: {
[key: string]: string
}
}| Status | Codes |
|---|---|
| 400 | BAD_BUNDLE; BAD_PACKAGE; COMPUTE_ABI_MISMATCH; UNSUPPORTED_BUNDLE. details of BAD_BUNDLE: a ServiceRefused, COMPUTE_ABI_MISMATCH: a ServiceRefused, UNSUPPORTED_BUNDLE: a ServiceRefused. |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/packages/install
Install a release from the registry as the operator. Sealed.
Who: the ops token.
Body (application/json)
{
package: string,
version: string
}Answer (application/json)
{
package: string,
version: string,
signerId: string,
services: {
[key: string]: string
}
}| Status | Codes |
|---|---|
| 400 | BAD_BUNDLE; COMPUTE_ABI_MISMATCH; UNSUPPORTED_BUNDLE. details of BAD_BUNDLE: a ServiceRefused, COMPUTE_ABI_MISMATCH: a ServiceRefused, UNSUPPORTED_BUNDLE: a ServiceRefused. |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
DELETE /ops/packages/{package}
Uninstall what the operator installed. Sealed.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
package | path | string |
Answer (application/json)
Uninstalled| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
DELETE /ops/packages/{package}/{version}
Uninstall one operator-installed version. Sealed.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
package | path | string |
version | path | string |
Answer (application/json)
Uninstalled| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
GET /ops/placement
Where every app's replicas are. Sealed.
Ids and counts only, read after a read index (fresh: this node caught up with the system leader); release is a node's attested release; clusterVersion is the logged cluster version (null until the system leader logs one).
Who: the ops token.
Answer (application/json)
{
fresh: boolean,
apps: {
app: string,
group: integer,
replicas: integer[]
}[],
nodes: {
id: integer,
zone: string,
role: NodeRole,
release: string | null,
apps: integer
}[],
clusterVersion: string | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
GET /ops/pools
Compute pools. Sealed.
The pools by name (absent: none set, one legacy pool), and each pool's capacity: how many runs its job nodes take at once. Who: the ops token.
Answer (application/json)
{
pools: {
[key: string]: {
runsPerNode: integer,
maxMemoryMib: integer
}
},
capacity: {
[key: string]: integer
}
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/pools
Set the compute pools. Sealed.
Signed over cluster / __set_pools / { pools }; POOL_IN_USE when a pool to remove still has job nodes or runs.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
pools: {
[key: string]: {
runsPerNode: integer,
maxMemoryMib: integer
}
},
operatorProof?: OperatorProof
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | POOL_IN_USE; UPGRADE_PENDING. details of UPGRADE_PENDING: a UpgradePending. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/prices
The price table. Sealed.
In micro-units of the billing currency; {} until one is set.
Who: the ops token.
Answer (application/json)
{
version?: integer,
fuelPerVcpuSecond?: integer,
vcpuSecond?: integer,
gibSecond?: integer,
connectorGib?: integer,
storageGibMonth?: integer,
egressGib?: integer
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/prices
Set the price table. Sealed.
Signed over cluster / __set_price_table / { table }; PRICE_VERSION unless version is the current one plus one (1 for the first), BAD_PRICES for a zero fuelPerVcpuSecond.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
table: {
version: integer,
fuelPerVcpuSecond: integer,
vcpuSecond: integer,
gibSecond: integer,
connectorGib: integer,
storageGibMonth: integer,
egressGib: integer
},
operatorProof?: OperatorProof
}Answer (application/json)
{}| Status | Codes |
|---|---|
| 400 | BAD_PRICES |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | PRICE_VERSION; UPGRADE_PENDING. details of UPGRADE_PENDING: a UpgradePending. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/quotas
The quotas. Sealed.
The per-account quotas, and the per-payer overrides under orgs.
Who: the ops token.
Answer (application/json)
QuotaSettings| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/quotas
Change quotas. Sealed.
Changes the limits the body names, the others keep their value; signed over cluster / __set_quotas / { quotas } with every limit after the change. Without org, the cluster's limits (GET /ops/quotas names them); orgs, which that answer carries, is ignored, so its answer may be sent back changed. With org: one payer's maxConcurrentRuns, computeFuel (decimal string) and maxFileBytes (null clears one, back to the cluster's), and no other limit. A property that is no limit (of the cluster's, or with org of a payer's) is refused 400 UNKNOWN_QUOTA.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
QuotaChangesAnswer (application/json)
{}| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed; UNKNOWN_QUOTA |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | UPGRADE_PENDING. details of UPGRADE_PENDING: a UpgradePending. |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/recover
Found the cluster again from its recovery disk. Sealed.
On the founder started with --bootstrap --recover-from DIR, its system state empty: the newest system file in DIR/operator/ and the apps' code files, each with the data key the operator opened from it (hex). Checked as founding from backups is (governance, operator key, no node of the old cluster answering), then the system group is seeded; each app waits for POST /ops/apps/{app}/restore { recovery }.
Who: the ops token.
Body (application/json)
{
system: {
file: string,
key: string
},
code?: {
file: string,
key: string
}[]
}Answer (application/json)
{
apps: integer,
accounts: integer,
index: integer
}| Status | Codes |
|---|---|
| 400 | BAD_RECOVERY_FILE; BAD_RECOVERY_KEY; TOO_MANY_FILES; UNATTESTED_RECOVERY_FILE |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | NOT_RECOVERING; OLD_CLUSTER_ANSWERS; OTHER_DEPLOYMENT |
GET /ops/recovery-files
The recovery files a node reads. Sealed.
In --recover-from, else --recovery-dir, of holder (operator, the default; org:<id>; account:<id>): each file's name, its header as signed (JSON text) and the node's Ed25519 signature over calimero.recovery-backup.v1\0 and those bytes (hex), for the holder's device to check before it opens a key with its own.
Who: the ops token.
| Parameter | In | Type |
|---|---|---|
holder? | query | string |
Answer (application/json)
{
holder: any,
files: {
name: string,
header: string,
signature: string
}[]
}| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 409 | NO_BACKUP_DIR |
POST /ops/releases
Approve a mero-tee release for every app. Sealed.
Where the operator holds release approvals.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
version: string,
approved?: boolean,
operatorProof?: OperatorProof
}Answer (application/json)
ApprovedReleases| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/releases/{version}/deadline
Set a release deadline. Sealed.
After after (RFC 3339), apps whose approver has not moved past the release may start no new work.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
version | path | string |
Body (application/json)
{
after?: string,
operatorProof?: OperatorProof
}Answer (application/json)
Deadlines| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
DELETE /ops/releases/{version}/deadline
Lift a release deadline. Sealed.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
version | path | string |
Body (application/json, optional): May be absent.
ProofOnlyAnswer (application/json)
Deadlines| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/served-origins
Custom domains to serve. Sealed.
Every served origin a package's manager registered, by the package's label, never its name; addedAt is RFC 3339.
Who: the ops token.
Answer (application/json)
{
fresh: boolean,
origins: {
origin: string,
host: string,
label: string,
addedAt: string
}[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/sign-up
Set the sign-up policy. Sealed.
Refused once the cluster's owner runs sign-up.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
policy: SignUp,
operatorProof?: OperatorProof,
confirm?: Confirm
}Answer (application/json)
SignUpSet| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/sign-up/invites
Cluster sign-up invites. Sealed.
Who: the ops token.
Answer (application/json)
{
signUp: {
policy: SignUp,
orgInvites: boolean,
signUpInvites: boolean,
inviteRequired: boolean
},
runBy: "owner" | "operator",
invites: SignUpInvite[]
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
POST /ops/sign-up/invites
Issue a cluster sign-up invite. Sealed.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
Body (application/json)
{
token: string,
uses?: integer,
expiresAt: string,
operatorProof?: OperatorProof
}Answer (application/json)
SignUpInvite| Status | Codes |
|---|---|
| 400 | BAD_REQUEST: the request is malformed |
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
DELETE /ops/sign-up/invites/{key}
Withdraw a cluster sign-up invite. Sealed.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
key | path | string |
Body (application/json, optional): May be absent.
ProofOnlyAnswer (application/json)
InviteKey| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
POST /ops/sign-up/invites/{key}/revoke
Withdraw a cluster sign-up invite (POST). Sealed.
For an HTTP client whose DELETE carries no body.
Who: the ops token. Operator signature: answers 428 OPERATOR_SIGNATURE_REQUIRED first; send it again with operatorProof, the operator key's signature over details.message and its nonce.
| Parameter | In | Type |
|---|---|---|
key | path | string |
Body (application/json, optional): May be absent.
ProofOnlyAnswer (application/json)
InviteKey| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | BAD_OPERATOR_SIGNATURE; FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
| 428 | OPERATOR_SIGNATURE_REQUIRED: the operator key must sign the decision; details names the statement. details of OPERATOR_SIGNATURE_REQUIRED: a OperatorSignatureRequired. |
GET /ops/status
The node and the cluster. Sealed.
Counts, Raft status and governance; never app state, names or credentials. groups: the app groups this node hosts; apps and accounts are counts; rollback is this node's rollback counter, null on a node without one.
Who: the ops token.
Answer (application/json)
{
node: integer,
system: GroupStatus,
governance: Governance,
groups: {
app: string,
status: GroupStatus
}[],
nodes: NodeRecord[],
apps: integer,
accounts: integer,
rollback: RollbackStatus | null
}| Status | Codes |
|---|---|
| 401 | UNAUTHENTICATED: no, unknown, expired or revoked credential |
| 403 | FORBIDDEN: the credential may not do this (scope, role, governance, read-only) |
Schemas
Error
An error answer: error is the code. details, absent for most codes, has the schema x-calimero-details names for the code on the operation's response (every code's: x-calimero-error-details at the document's root); a code it names no schema for carries none, or a value clients need not read.
{
status: integer,
error: string,
message: string,
details?: any
}Confirm
A passkey assertion over the challenge a 412 CONFIRM_REQUIRED named: the same request sent again with it approves exactly that request.
{
challengeId: string,
assertion: Assertion
}ConfirmRequired
details of a 412 CONFIRM_REQUIRED: the WebAuthn challenge to sign under rpId with one of the passkeys allowCredentials names (credential ids; empty: any of the account's), and the challengeId the retry's confirm names. apps: deleting a team that holds apps, the apps that go with it.
{
challengeId: string,
challenge: string,
rpId: string,
allowCredentials: string[],
apps?: string[]
}OperatorProof
The operator key's Ed25519 signature (hex) over the statement a 428 OPERATOR_SIGNATURE_REQUIRED named, with that statement's nonce.
{
nonce: string,
signature: string
}OperatorSignatureRequired
details of a 428 OPERATOR_SIGNATURE_REQUIRED: the statement to sign (args is the JSON text of its arguments, as signed) and the exact bytes to sign (message, standard base64).
{
subject: string,
method: string,
args: string,
nonce: string,
cluster: string,
message: string
}Assertion
The browser's answer to navigator.credentials.get, each field base64url.
{
credentialId: string,
authenticatorData: string,
clientDataJson: string,
signature: string
}Registration
The browser's answer to navigator.credentials.create, each field base64url.
{
attestationObject: string,
clientDataJson: string
}Session
A session: its token (15 minutes, by the issuing node) and the refresh token for /auth/refresh.
{
accountId: string,
sessionToken: string,
expiresAt: integer,
refreshToken: string
}BackupKeyAnswer
A holder's backup key: who holds it ({ kind: "operator" }, { kind: "org", id } or { kind: "account", id }), the X25519 public key the recovery disk seals their apps' backups to (null while none is set), and how many apps that covers.
{
holder: {
kind: "operator" | "org" | "account",
id?: string
},
key: {
publicKey: string,
setAt: integer,
setBy: string
} | null,
apps: integer
}Applied
An entry an app's log applied: its index, how it ended and the app's error (null when it ended ok; the app's own error value otherwise, free-form). details of a 422 UPGRADE_FAILED.
{
index: integer,
status: "ok" | "appError" | "trap",
error: any
}NotLeader
details of a 421 NOT_LEADER: the leader's URL to send the same request to, and its node id where known.
{
leaderUrl: string,
leader?: integer
}FeatureNotActive
details of a 409 FEATURE_NOT_ACTIVE: the feature the request needs, the cluster version it ships in (needs) and the version active now (null: none logged, and the nodes could not say).
{
feature: string,
needs: string,
active: string | null
}RuntimeTooOld
details of a 409 RUNTIME_TOO_OLD: the runtime the release needs and the replicas known to fall short of it, each with what it runs (a version, or { before }: a release older than that one).
{
minRuntimeVersion: string,
nodes: {
node: integer,
runtime: string | {
before: string
}
}[]
}ReleaseDeadline
details of a 409 RELEASE_DEADLINE: the mero-tee release whose deadline passed, and the deadline (after RFC 3339, afterSecs Unix seconds). Approving that release (or a newer one) lifts it.
{
release: string,
after: string,
afterSecs: integer
}UpgradePending
details of a 409 UPGRADE_PENDING: the release every node must run first, and the nodes that run an older one (release null: one this node could not attest).
{
release: string,
nodes: {
node: integer,
release: string | null
}[]
}AppError
details of a 422 APP_ERROR: the app's error code, its fields (the app's own value, free-form: the object its ABI declares for the error, or the app's message as a string when that is not JSON), and the log index of the call (absent when the node refused it before it ran: UnknownMethod, WrongKind, Forbidden, ConfirmNotAView, NotAView, ConfirmRequired).
{
index?: integer,
code: string,
fields: any
}Trap
details of a 422 TRAP: the log index of the run, how it trapped, and the engine's account of it.
{
index: integer,
kind: "OutOfFuel" | "Timeout" | "Cancelled" | "Unavailable" | "OutOfMemory" | "StackOverflow" | "Fault" | "HostDenied",
detail: string
}InitFailed
details of a 422 INIT_FAILED: the app made, and the error its init ended with (the app log's, free-form).
{
appId: string,
error: any
}RecoveryNotReady
details of a 409 RECOVERY_NOT_READY: when the recovery may finish (Unix seconds).
{
readyAt: integer
}UploadPosition
details of a 409 PART_CONFLICT, 409 PART_OUT_OF_ORDER or 409 UPLOAD_INCOMPLETE: the part the upload expects next.
{
next: integer
}RetryAfter
details of a 503 TIMEOUT or 503 FILES_UNAVAILABLE: the seconds to wait before sending the same request (with the same idempotency key) again.
{
retryAfter: integer
}ServiceRefused
details of a 400 UNSUPPORTED_BUNDLE, 400 BAD_BUNDLE or 400 COMPUTE_ABI_MISMATCH refusing one service of a release: the service, and compute: true when it was that service's compute component. Absent when the refusal is of a raw bundle.
{
service: string,
compute?: boolean
}SealedRefusal
The sealed channel's own refusal, outside the envelope and in the clear: not an Error. busy (503, with Retry-After: 1): too many sealed requests or sessions at once, send it again; the other codes (400, malformed and the like) say the envelope could not be opened.
{
error: {
code: string,
message: string
}
}Receipt
The answering node's signature (receipt key, hex) over (app, index, SHA-256(JCS(result)), node).
{
app: string,
index: integer,
resultHash: string,
node: integer,
key: string,
signature: string
}Access
Who may reach an app at all.
{
kind: "owner"
} | {
kind: "org"
} | {
kind: "public"
} | {
kind: "accounts",
accounts: string[]
} | {
kind: "team",
team: string
}OrgRole
A member's role in an organization.
"guest" | "member" | "admin" | "owner"TeamRole
A member's standing in one team.
"lead" | "member" | "readOnly"TeamJoin
Open (everyone who reaches the parent) or restricted (invite) membership.
"everyone" | "invite"OutboundSelection
manifest (every prefix the release declares) or these prefixes.
"manifest" | string[]Deployer
An account or an organization.
{
account: string
} | {
org: string
}SignUp
The cluster's sign-up policy.
"open" | "invite" | "closed"Page
A page of a list: next is the after of the next page, null on the last.
{
next: string | null
}Release
A mero-tee release.
{
version: string,
profile: string
}AttestationDoc
A node's attestation: the TDX quote (base64), the key it binds (hex) and what it was asked for. receiptKey and governance with purpose=receipts, kms with purpose=kms on a node with a KMS record, clusterIdentity with purpose=orchestrator; jobKey only from a job node, never from this API.
{
quote: string,
transportKey: string,
appHash: string,
nonce: string,
release: Release,
cluster: string,
node: integer,
mock: boolean,
receiptKey?: string,
governance?: Governance,
kms?: KmsKeys,
jobKey?: string,
clusterIdentity?: string
}KmsKeys
What a node verified of the mero-kms replicas it took its keys from: the storage key merod fetched, and the data disk's key the boot script fetched; each absent without a record.
{
storage?: KmsEvidence,
disk?: KmsEvidence
}KmsEvidence
The KMS quote a node accepted a key under: the KMS host, the mero-kms release (and image profile) whose signed policy it matched, the quote's registers (hex), its TCB status, SHA-256 and when it was verified (Unix seconds); mock (absent: false) in development builds only.
{
kmsHost: string,
release: string,
profile?: string,
mrtd: string,
rtmr0: string,
rtmr1: string,
rtmr2: string,
rtmr3: string,
tcbStatus?: string,
quoteSha256: string,
verifiedAt: integer,
mock?: boolean
}GroupStatus
A Raft group's status as one node sees it: the leader (null: none known), whether this node is it, the term, the last log index (null: an empty log), the applied index, and the voters and learners.
{
group: integer,
leader: integer | null,
is_leader: boolean,
term: integer,
last_log: integer | null,
applied: integer,
voters: integer[],
learners: integer[]
}RollbackStatus
A node's rollback counter: the cluster's epoch (rollbacks forced so far), its generation and mark, whether this start was forced (--accept-rollback), and the seconds since mero-kms last acknowledged a checkpoint.
{
epoch: integer,
generation: integer,
mark: integer,
forced: boolean,
sinceCheckpointSecs: integer
}NodeRole
What a node does: hold app replicas, or run compute jobs.
"replica" | "job"NodeRecord
A registered node: its id, address, zone, role and (a job node's) compute pool, absent for none.
{
id: integer,
addr: string,
zone: string,
role: NodeRole,
pool?: string
}Quotas
The per-account limits, and the compute and file limits of each organization (or personal account) that has no override. maxFuelPerDeveloperPerDay (0: no limit) is a decimal string; the others are JSON numbers.
{
maxAppsPerAccount: integer,
maxBundleBytesPerAccount: integer,
maxApiKeysPerAccount: integer,
maxOrgsPerAccount: integer,
maxAccounts: integer,
maxFileBytesPerOrg: integer,
maxConcurrentRunsPerOrg: integer,
computeFuelPerOrg: integer,
maxFuelPerDeveloperPerDay: string /* decimal */
}OrgQuotas
One payer's limits in place of the cluster's; a limit left out is the cluster's.
{
maxConcurrentRuns?: integer,
computeFuel?: string /* decimal */,
maxFileBytes?: integer
}QuotaSettings
GET /ops/quotas: the cluster's limits and, under orgs, each payer's overrides by payer id.
{
maxAppsPerAccount: integer,
maxBundleBytesPerAccount: integer,
maxApiKeysPerAccount: integer,
maxOrgsPerAccount: integer,
maxAccounts: integer,
maxFileBytesPerOrg: integer,
maxConcurrentRunsPerOrg: integer,
computeFuelPerOrg: integer,
maxFuelPerDeveloperPerDay: string /* decimal */,
orgs: {
[key: string]: OrgQuotas
}
}UsageDay
What an app's runs used on one UTC day (date, YYYY-MM-DD), each figure a decimal string; wallMs is information only.
{
date: string,
runs: string /* decimal */,
fuel: string /* decimal */,
wallMs: string /* decimal */,
writes: string /* decimal */,
bytesWritten: string /* decimal */,
events: string /* decimal */
}RunFile
A file a run reads or wrote: its id, and its plaintext size and SHA-256 (hex) only for a caller who may list the app's files.
{
id: string,
size?: integer,
sha256?: string
}Run
A compute run's record, without its arguments or keys: its method, state, caps (fuel a JSON number here), inputs, attempts (tsMs Unix milliseconds) and final outcome (null while it runs; message the failure text, null unless the caller may list the app's files). progress is the leader's last poll (null elsewhere, when it is not active, or to a caller who may not list files); queue where the run waits for a job node, to a caller who may list files only.
{
run: string,
method: string,
state: "queued" | "running" | "done" | "failed" | "cancelled",
cancelRequested: boolean,
startTsMs: integer,
caps: {
fuel: integer,
memoryMib: integer,
wallSecs: integer
},
inputs: RunFile[],
attempts: {
attempt: integer,
node: integer,
tsMs: integer
}[],
final: {
attempt: integer,
outcome: {
kind: "done"
} | {
kind: "failed",
reason: "fuel" | "memory" | "trap" | "app-error" | "integrity" | "cancelled" | "lost" | "refused" | "timeout" | "quota" | "not-granted" | "too-large"
} | {
kind: "cancelled"
},
outputs: RunFile[],
usage: {
cpuMicros: integer,
gibMicros: integer,
fuel: integer
},
tsMs: integer,
message: string | null
} | null,
progress: {
percent: integer,
step: string
} | null,
queue?: {
state: "unplaced" | "waiting" | "granted",
capacity: integer,
pool: string,
reason?: "NO_CAPACITY" | "POOL_FULL" | "PAYER_AT_RUN_QUOTA" | "PAYER_AT_FUEL_QUOTA"
}
}AccountProof
A statement, signed with the answering node's receipt key (hex, Ed25519 over the statement's canonical JSON after its domain), that the account asked to bind nonce for audience, valid from issuedAt to expiresAt (Unix seconds).
{
statement: AccountStatement,
key: string,
signature: string
}AccountStatement
What an account proof states: the cluster and node, the account, the nonce and audience it binds, and when it was issued and expires (Unix seconds).
{
cluster: string,
node: integer,
account: string,
nonce: string,
audience: string,
issuedAt: integer,
expiresAt: integer
}PackageOrigin
A custom frontend origin of a package: the rp-id its passkeys use, who registered it and when (RFC 3339), and whether the cluster serves the package's frontend there.
{
package: string,
origin: string,
rpId: string,
addedBy: string,
addedAt: string,
served: boolean
}SignUpState
The sign-up policy and what it implies: whether organization invites and cluster sign-up invites admit a new account, and whether one is required.
{
policy: SignUp,
orgInvites: boolean,
signUpInvites: boolean,
inviteRequired: boolean
}ApprovedReleases
The mero-tee releases the scope approves now, after the change.
{
approvedReleases: string[]
}OutboundApproved
The outbound approval the scope holds now for the package's publisher (signer), after the change.
{
signer: string,
approval: OutboundApproval
}Uninstalled
The versions an uninstall removed.
{
removed: string[]
}Deadlines
Every release deadline after the change, oldest release first (after RFC 3339, afterSecs Unix seconds).
{
deadlines: {
version: string,
after: string,
afterSecs: integer
}[]
}SignUpSet
The cluster's governance and sign-up policy after the change.
{
governance: Governance,
signUp: SignUpState
}InviteKey
The key of the cluster sign-up invite withdrawn.
{
inviteKey: string
}UpgradeRun
An organization-wide upgrade run: the apps it targets, those done, and why each failed one failed.
{
runId: string,
package: string,
version: string,
team?: string,
cascade: boolean,
by: string,
startedAt: integer,
apps: string[],
done: string[],
failed: {
[key: string]: any
},
finished: boolean
}App
An app instance (a context) as the directory records it. executor is absent for an SDK 0.12 app (wasmer), which this node lists but does not run; release is the package release it runs, absent for a record from before or a raw upload; restore is a restore from a backup under way.
{
appId: string,
name: string,
group: integer,
bundle: string,
owner: string,
org: string | null,
access: Access,
confirmMethods: string[],
executor?: "component" | "wasmer",
replicas: integer[],
createdAt: integer,
initArgs: any,
computeBundle?: string,
components?: "computeOnly",
metadata: any,
lastUpgrade?: Upgrade,
deployment?: string,
release?: PackageRef,
restore?: {
seed?: integer,
source?: {
name: string,
sha256: string,
index: integer
}
}
}AppEntry
An app as GET /apps lists it: package and version name the release its bundle came from (null for a raw upload), deployment the deployment it was created from (null for none; absent from an older node, as 1.0.0-rc.1).
{
appId: string,
name: string,
owner: string,
org: string | null,
bundle: string,
package: string | null,
version: string | null,
deployment?: string | null
}PackageRef
One service of one package release: service is absent for a single-service bundle, compute (absent: false) marks the service's compute component.
{
package: string,
version: string,
service?: string,
compute?: boolean
}Upgrade
The last upgrade tried on an app, done or failed: from and to are bundle hashes, by the account (or operator), run the organization-wide run it was part of, apiKey the upgrade key that made it.
{
from: string,
to: string,
at: integer,
by: string,
ok: boolean,
error?: any,
run?: string,
apiKey?: string,
fromRelease?: PackageRef,
toRelease?: PackageRef
}Package
A package and the releases of it the caller may see, oldest first; latest is the newest of those.
{
package: string,
signerId: string,
owner: string,
latest: string,
versions: {
version: string,
mpk: string,
size: integer,
source: "registry" | "upload",
services: {
[key: string]: string
},
metadata: any,
outbound: string[],
installedBy: string,
installedAt: integer
}[]
}ApiKey
An API key as the account's list shows it (never its secret): apps and methods are null for every one; upgrades makes it an upgrade key.
{
keyId: string,
account: string,
label: string,
apps: string[] | null,
methods: string[] | null,
readOnly: boolean,
allowConfirm: boolean,
expiresAt: integer,
upgrades?: {
app: string,
package: string,
signer: string,
proofKey: string
}
}Org
An organization as GET /orgs/{org} answers it. members maps each account to its role, capabilities and defaultCapabilities are capability bits, outboundApprovals is keyed by package signer, upgradeRuns by run id; recovery is absent when the organization set no recovery key, allApps when no member gets every app added later, personal unless it is its owner's personal organization (where instances created without naming an organization go).
{
orgId: string,
name: string,
members: {
[key: string]: OrgRole
},
teams: {
[key: string]: Team
},
defaultCapabilities: integer,
capabilities: {
[key: string]: integer
},
approvedReleases: string[],
outboundApprovals: {
[key: string]: OutboundApproval
},
metadata: any,
memberMetadata: {
[key: string]: any
},
upgradeRuns: {
[key: string]: UpgradeRun
},
recovery?: {
publicKey: string,
setAt: integer,
pending: {
account: string,
startedAt: integer,
readyAt: integer
} | null
},
allApps?: string[],
personal?: boolean,
mode?: "legacy" | "standalone" | "shared",
releaseApprovers?: string[],
publishes?: string[],
newWorkStopped?: {
release: string,
after: string
} | null
}Team
A team as its organization records it: members maps each direct row to whether it is a lead; capabilities are capability bits per row; defaultCapabilities is absent when unset.
{
teamId: string,
name: string,
parent: string | null,
join: TeamJoin,
members: {
[key: string]: boolean
},
readOnly: string[],
capabilities: {
[key: string]: integer
},
metadata: any,
removed: string[],
defaultCapabilities?: integer
}TeamView
A team as GET /orgs/{org}/teams/{team} answers it: each member's row, the child teams the caller sees, its apps, and the caller's own row (myRole, null for none) and membership (member). package names the package of an app team; it and defaultCapabilities are absent from an older node (1.0.0-rc.1 sends neither).
{
teamId: string,
name: string,
parent: string | null,
join: TeamJoin,
metadata: any,
package?: string | null,
defaultCapabilities?: integer | null,
members: {
account: string,
role: TeamRole,
capabilities: integer
}[],
children: string[],
apps: {
appId: string,
name: string,
contextId: string
}[],
myRole: TeamRole | null,
member: boolean
}Deployment
A deployment as its managers list it. host is its frontend host, null on a node with no apps domain; times are RFC 3339.
{
id: string,
host: string | null,
name: string,
owner: Deployer,
apps: {
app: string,
package: string,
version: string,
addedBy: string,
addedAt: string
}[],
createdBy: string,
createdAt: string
}DeadLetter
A cross-app call that was never delivered: its sequence number, the target app and method, why, and when (atMs, Unix milliseconds).
{
seq: integer,
app: string,
method: string,
reason: string,
atMs: integer
}Governance
Who decides what on this cluster: release approvals, app upgrades and outbound approvals (owner: each app's owner; operator: the operator), and, left out at their defaults, deployments (open), deployers (operator) and signUp (open).
{
releases: "owner" | "operator",
appUpgrades: "owner" | "operator",
outbound: "owner" | "operator",
deployments?: "granted" | "open",
deployers?: "owner" | "operator",
signUp?: "invite" | "closed" | "open"
}OutboundApproval
What an owner approved for one publisher's apps to call out to: the approved URL prefixes, and every prefix it was shown.
{
prefixes: string[],
reviewed: string[]
}AppScope
The scope whose approvals cover an app: its organization (personal: true when it is its owner's personal organization). account is only GET /auth/apps' own scope: the apps the account owns, wherever they are.
{
kind: "org",
org: string,
personal?: boolean
} | {
kind: "account"
}ClusterRelease
A mero-tee release the cluster's nodes run: how many run it, and whether the scope approved it (true where nothing was ever recorded).
{
release: string,
nodes: integer,
approved: boolean
}BundleRelease
A bundle by its digest, with the release it came from where the reader may see it.
{
bundle: string,
package?: string,
version?: string
}ReportUpgrade
An app's last upgrade as a report shows it. actor, error, run and apiKey are shown to the app's people, never to the operator.
{
from: BundleRelease,
to: BundleRelease,
at: integer,
ok: boolean,
actorKind: "owner" | "member" | "operator",
actor?: string,
error?: any,
run?: string,
apiKey?: string
}ReportApp
One app in a release report (GET /auth/apps, GET /orgs/{org}/apps, GET /ops/apps): its bundle and release (package, null where the reader may not see it), the publisher's key and bound organization, who holds its upgrades and release approvals, its last upgrade, the releases approved to hold it (null: unrestricted), each replica's release, and lastWriteAt (Unix seconds, null when unknown). name, team, availableVersions (newer releases, oldest first), latestReachable and latestBlocked (the newest release and why an upgrade would not take it) are for the app's people, never the operator.
{
app: string,
group: integer,
scope: AppScope,
bundle: string,
package: {
package: string,
version: string,
service?: string | null
} | null,
publisher: {
signer: string,
org: string | null
} | null,
upgradesHeldBy: "operator" | "owner" | "publisher",
releasesApprovedBy: "operator" | "publisher" | "owner",
lastUpgrade: ReportUpgrade | null,
approvedReleases: string[] | null,
replicas: {
node: integer,
release: string | null,
approved: boolean
}[],
lastWriteAt: integer | null,
name?: string,
team?: string,
availableVersions?: string[],
latestReachable?: string | null,
latestBlocked?: {
version: string,
reason: "authority" | "runtime",
message: string,
minRuntimeVersion?: string,
nodes?: {
node: integer,
runtime: string | {
before: string
} | null
}[]
}
}DeploymentRecord
A deployment as the directory records it: the release it offers by app name (addedAt Unix seconds), who created it and when (Unix seconds).
{
id: string,
name: string,
owner: Deployer,
apps: {
[key: string]: {
package: string,
version: string,
addedBy: string,
addedAt: integer
}
},
createdBy: string,
createdAt: integer
}DeployerGrant
A grant to install where deployments are granted: until when (Unix seconds; absent: it does not end), when and by whom it was granted.
{
until?: integer,
grantedAt: integer,
grantedBy: string
}SignUpInvite
A cluster sign-up invite, never its token: uses left, when it expires (expiresAt RFC 3339, expiresAtSecs Unix seconds), who made it and when (RFC 3339).
{
inviteKey: string,
uses: integer,
expiresAt: string,
expiresAtSecs: integer,
createdBy: string,
createdAt: string
}ProofOnly
What an operator decision that names nothing in its body may carry: none at first, the operator's proof after the 428.
{
operatorProof?: OperatorProof
}ConfirmOnly
The body of a step-up that names nothing else: none (or {}) at first, the passkey assertion after the 412.
{
confirm?: Confirm
}QuotaChanges
The limits POST /ops/quotas changes, each optional: without org, the cluster's (those GET /ops/quotas answers, maxFuelPerDeveloperPerDay a decimal string); with org, one payer's (maxConcurrentRuns, computeFuel a decimal string, maxFileBytes; null clears one). orgs is ignored. Any other property is refused 400 UNKNOWN_QUOTA.
{
org?: string,
operatorProof?: OperatorProof,
orgs?: any,
maxAppsPerAccount?: integer,
maxBundleBytesPerAccount?: integer,
maxApiKeysPerAccount?: integer,
maxOrgsPerAccount?: integer,
maxAccounts?: integer,
maxFileBytesPerOrg?: integer,
maxConcurrentRunsPerOrg?: integer,
computeFuelPerOrg?: integer,
maxFuelPerDeveloperPerDay?: string /* decimal */,
maxConcurrentRuns?: integer | null,
computeFuel?: string /* decimal */ | null,
maxFileBytes?: integer | null
}