Xeonr Developer Docs
API SpecificationApps

Watch App

POST
/containers.api.v1.AppService/WatchApp

Streams the App and its live instances, re-sent every 3 seconds until the client disconnects.

Access: namespace VIEWER or above (read)

Authorization

BearerAuth
AuthorizationBearer <token>

A namespace-scoped API key (cpk_…) for machines, or a Xeonr Auth OIDC token for humans. The key's namespace and role are pinned server-side.

In: header

Header Parameters

Connect-Protocol-Version?number

Define the version of the Connect protocol

Connect-Timeout-Ms?number

Define the timeout, in ms

Request Body

application/connect+json

appId?string
Length1 <= length <= 64
[key: string]?never

Response Body

application/connect+json

application/connect+json

curl -X POST "https://containers.xeonr.io/containers.api.v1.AppService/WatchApp" \  -H "Connect-Protocol-Version: 1" \  -H "Connect-Timeout-Ms: 1000" \  -H "Content-Type: application/connect+json" \  -d ''
{
  "app": {
    "appId": "string",
    "namespace": "string",
    "label": "string",
    "scaling": {
      "minInstances": 0,
      "maxInstances": 0,
      "concurrency": 0,
      "idleTimeoutSec": 0,
      "activationTimeoutSec": 0
    },
    "resources": {
      "cpuMillis": 0,
      "memoryMb": 0,
      "ephemeralMb": 0,
      "pids": 0
    },
    "env": {
      "property1": "string",
      "property2": "string"
    },
    "egress": {
      "egressPolicyId": "string"
    },
    "state": "APP_STATE_UNSPECIFIED",
    "createdAtUnix": "string",
    "updatedAtUnix": "string",
    "hostname": "string",
    "activeVersionId": "string",
    "autoStart": true,
    "access": "APP_ACCESS_UNSPECIFIED",
    "key": "string"
  },
  "instances": [
    {
      "instanceId": "string",
      "appId": "string",
      "podName": "string",
      "address": "string",
      "state": "APP_INSTANCE_STATE_UNSPECIFIED",
      "readyAtUnix": "string"
    }
  ]
}
{
  "code": "not_found",
  "message": "string",
  "details": [
    {
      "type": "string",
      "value": "string",
      "debug": {}
    }
  ]
}

Update App POST

Changes an App's operational envelope in place: scaling, resources, env, egress and label. Only fields named in update_mask are applied; an empty mask applies all of them (scaling only when set). An egress change takes effect by replacing replicas once the App is idle. Also repairs a stored hostname or a missing key. access and auto_start are not applied by this call today. **Access:** namespace OPERATOR or above (write)

containers.api.v1.ClusterService

ClusterService manages where namespaces run (BYOC, platform-docs container-platform/docs/BYOC.md §2). A cluster is one operator install: one enrolment, one credential, one owner team. Two teams installing on the same physical cluster produce two records, and the platform neither knows nor needs to know that they share hardware. The platform's own fleet is a cluster like any other, flagged GLOBAL and `default`, which is where a namespace lands when nothing names a cluster. A namespace is placed on exactly one cluster when it is created (Namespace.cluster_id) and everything beneath it — sandboxes, jobs, apps, environments, volumes, pools, keys — runs there. Placement is immutable: moving a namespace is a migration, not an update. Who may place a namespace on a cluster is its visibility: PRIVATE is the owner team only; SHARED adds the teams holding a grant; GLOBAL is every team, within the everyone-grant. A grant also caps how much of the cluster that team's namespaces may hold in total (BYOC.md §5.4): the sum of a team's namespace quotas on a cluster must fit its grant, and the owner team's grant is implicit and unbounded. GetCluster and ListClusters carry allow_api_keys: a namespace key reaches the cluster its namespace is placed on and nothing else. The mutations do not, for the reason CreateNamespace does not: each needs a team role, and no key holds one.