-
Notifications
You must be signed in to change notification settings - Fork 1
API Reference
Complete reference documentation for the Stark Orchestrator REST and WebSocket APIs.
| Environment | URL |
|---|---|
| Development | https://localhost:443 |
| Production | https://your-orchestrator.example.com |
All API requests (except health check and initial setup) require authentication via Bearer token.
Authorization: Bearer <access-token>Obtain tokens via the login endpoint or CLI.
Health check endpoint. No authentication required.
Response:
{
"status": "healthy",
"timestamp": "2026-02-02T10:00:00.000Z",
"version": "0.0.1"
}Check if initial admin setup is needed.
Response:
{
"setupRequired": true
}Create the initial admin user. Only works when no users exist.
Request:
{
"email": "admin@example.com",
"password": "secure-password",
"displayName": "Admin User"
}Response:
{
"user": {
"id": "user-uuid",
"email": "admin@example.com",
"role": "admin"
},
"session": {
"access_token": "...",
"refresh_token": "..."
}
}Register a new user.
Request:
{
"email": "user@example.com",
"password": "secure-password",
"displayName": "User Name"
}Authenticate and receive tokens.
Request:
{
"email": "user@example.com",
"password": "secure-password"
}Response:
{
"user": {
"id": "user-uuid",
"email": "user@example.com",
"role": "user"
},
"session": {
"access_token": "...",
"refresh_token": "...",
"expires_at": 1706961600
}
}Logout current session.
List all users (admin only).
Response:
{
"users": [
{
"id": "user-uuid",
"email": "admin@example.com",
"role": "admin",
"created_at": "2026-01-01T00:00:00.000Z"
}
]
}Create a new user (admin only).
Request:
{
"email": "newuser@example.com",
"password": "secure-password",
"role": "node"
}List all accessible packs.
Query Parameters:
| Parameter | Description |
|---|---|
namespace |
Filter by namespace |
visibility |
Filter by visibility (private, public) |
Response:
{
"packs": [
{
"id": "pack-uuid",
"name": "my-app",
"latestVersion": "1.2.0",
"runtime": "node",
"visibility": "private",
"ownerId": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z"
}
]
}Register a new pack.
Request:
{
"name": "my-app",
"version": "1.0.0",
"runtime": "node",
"visibility": "private",
"content": "<base64-encoded-bundle>"
}Response:
{
"pack": {
"id": "pack-uuid",
"name": "my-app",
"version": "1.0.0",
"runtime": "node"
}
}List all versions of a pack.
Response:
{
"versions": [
{
"version": "1.0.0",
"createdAt": "2026-01-15T10:00:00.000Z"
},
{
"version": "1.1.0",
"createdAt": "2026-01-20T12:00:00.000Z"
}
]
}List all pods.
Query Parameters:
| Parameter | Description |
|---|---|
namespace |
Filter by namespace |
status |
Filter by status |
node |
Filter by node ID |
pack |
Filter by pack name |
Response:
{
"pods": [
{
"id": "pod-uuid",
"packName": "my-app",
"packVersion": "1.0.0",
"nodeId": "node-uuid",
"namespace": "default",
"status": "running",
"labels": {"app": "web"},
"createdAt": "2026-01-20T10:00:00.000Z"
}
]
}Create a new pod.
Request:
{
"packName": "my-app",
"packVersion": "1.0.0",
"nodeId": "node-uuid",
"namespace": "default",
"priority": 100,
"labels": {"app": "web"},
"nodeSelector": {"env": "production"},
"tolerations": [{"key": "dedicated", "value": "gpu", "effect": "NoSchedule"}],
"resources": {
"cpu": 500,
"memory": 256
}
}Response:
{
"pod": {
"id": "pod-uuid",
"status": "pending"
}
}Get pod details.
Response:
{
"pod": {
"id": "pod-uuid",
"packName": "my-app",
"packVersion": "1.0.0",
"nodeId": "node-uuid",
"nodeName": "my-node",
"namespace": "default",
"status": "running",
"labels": {"app": "web"},
"resources": {"cpu": 500, "memory": 256},
"createdAt": "2026-01-20T10:00:00.000Z",
"scheduledAt": "2026-01-20T10:00:01.000Z",
"startedAt": "2026-01-20T10:00:02.000Z"
}
}Rollback pod to a previous version.
Request:
{
"version": "0.9.0"
}Delete a pod.
List all nodes.
Response:
{
"nodes": [
{
"id": "node-uuid",
"name": "my-node",
"runtime": "node",
"status": "ready",
"labels": {"env": "production"},
"taints": [],
"allocatable": {"cpu": 2000, "memory": 4096, "pods": 20},
"allocated": {"cpu": 500, "memory": 512, "pods": 2},
"lastHeartbeat": "2026-02-02T10:00:00.000Z"
}
]
}Get node details by ID.
Get node details by name.
List all namespaces.
Response:
{
"namespaces": [
{
"id": "ns-uuid",
"name": "default",
"createdAt": "2026-01-01T00:00:00.000Z"
},
{
"id": "ns-uuid-2",
"name": "production",
"createdAt": "2026-01-15T00:00:00.000Z"
}
]
}Create a namespace.
Request:
{
"name": "production"
}Delete a namespace.
Connect to /ws for real-time communication.
const ws = new WebSocket('wss://localhost/ws');
// Include auth token in connection (implementation may vary)
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'auth',
payload: { token: 'your-access-token' }
}));
};All messages follow this structure:
{
"type": "message-type",
"payload": { ... }
}Register a node with the orchestrator.
Send:
{
"type": "node:register",
"payload": {
"name": "my-node",
"runtimeType": "node",
"labels": {"env": "production"},
"taints": [],
"allocatable": {
"cpu": 2000,
"memory": 4096,
"pods": 20
}
}
}Receive:
{
"type": "node:registered",
"payload": {
"nodeId": "node-uuid"
}
}Send periodic heartbeat to indicate node is alive.
Send:
{
"type": "node:heartbeat",
"payload": {
"nodeId": "node-uuid",
"timestamp": "2026-02-02T10:00:00.000Z"
}
}Received when a pod is assigned to the node.
Receive:
{
"type": "pod:assign",
"payload": {
"podId": "pod-uuid",
"packName": "my-app",
"packVersion": "1.0.0",
"packContent": "<bundle-content>"
}
}Send pod status updates.
Send:
{
"type": "pod:status",
"payload": {
"podId": "pod-uuid",
"status": "running",
"message": "Pod started successfully"
}
}Received when a pod should be stopped.
Receive:
{
"type": "pod:stop",
"payload": {
"podId": "pod-uuid"
}
}Subscribe to real-time updates for resources.
PodGroup operations use the group:* message namespace. The orchestrator manages a central PodGroupStore — all membership state is authoritative and in-memory.
Full reference: PodGroups & Ephemeral Data Plane
Join or refresh membership in a PodGroup.
Send:
{
"type": "group:join",
"correlationId": "req-200",
"payload": {
"podId": "pod-abc-123",
"groupId": "demo:podgroup-chat",
"ttl": 120000,
"metadata": { "role": "echo" }
}
}Receive:
{
"type": "group:join:ack",
"correlationId": "req-200",
"payload": {
"membership": {
"podId": "pod-abc-123",
"joinedAt": 1707700000000,
"lastRefreshedAt": 1707700000000,
"ttl": 120000,
"metadata": { "role": "echo" }
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
podId |
string | Yes | The pod joining the group |
groupId |
string | Yes | Group identifier |
ttl |
number | No | Membership TTL in ms (default: 60000, 0 = infinite) |
metadata |
object | No | Arbitrary metadata attached to the membership |
Identity enforcement: Pod-type connections can only join as themselves. A podId mismatch returns group:error.
Leave a specific PodGroup.
Send:
{
"type": "group:leave",
"correlationId": "req-201",
"payload": {
"podId": "pod-abc-123",
"groupId": "demo:podgroup-chat"
}
}Receive:
{
"type": "group:leave:ack",
"correlationId": "req-201",
"payload": { "removed": true }
}Leave all groups. Typically sent during graceful shutdown.
Send:
{
"type": "group:leave-all",
"correlationId": "req-202",
"payload": { "podId": "pod-abc-123" }
}Receive:
{
"type": "group:leave-all:ack",
"correlationId": "req-202",
"payload": { "removedFrom": ["demo:podgroup-chat", "room:lobby"] }
}List all members of a PodGroup.
Send:
{
"type": "group:get-pods",
"correlationId": "req-203",
"payload": { "groupId": "demo:podgroup-chat" }
}Receive:
{
"type": "group:get-pods:ack",
"correlationId": "req-203",
"payload": {
"members": [
{ "podId": "pod-abc-123", "joinedAt": 1707700000000, "lastRefreshedAt": 1707700060000, "ttl": 120000, "metadata": { "role": "echo" } },
{ "podId": "pod-def-456", "joinedAt": 1707700010000, "lastRefreshedAt": 1707700070000, "ttl": 120000, "metadata": { "role": "greeter" } }
]
}
}List all groups a pod belongs to.
Send:
{
"type": "group:get-groups",
"correlationId": "req-204",
"payload": { "podId": "pod-abc-123" }
}Receive:
{
"type": "group:get-groups:ack",
"correlationId": "req-204",
"payload": { "groups": ["demo:podgroup-chat", "room:lobby"] }
}Returned when a group operation fails.
Receive:
{
"type": "group:error",
"correlationId": "req-200",
"payload": { "error": "Missing podId or groupId" }
}Automatic cleanup: When a pod's WebSocket connection closes, the server automatically removes it from all groups.
All endpoints return consistent error responses:
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Pod not found",
"details": {
"podId": "invalid-id"
}
}
}| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 409 | Conflict |
| 500 | Internal Server Error |
GET /api/secrets
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
namespace |
string | Filter by namespace |
type |
string | Filter by type (opaque, tls, docker-registry) |
Response:
{
"secrets": [
{
"id": "secret-uuid",
"name": "db-creds",
"type": "opaque",
"namespace": "default",
"keyCount": 2,
"injection": { "mode": "env", "prefix": "DB_" },
"createdAt": "2026-02-10T12:00:00.000Z",
"updatedAt": "2026-02-10T12:00:00.000Z"
}
]
}Note: Secret data (values) are never included in list responses.
POST /api/secrets
Request Body:
{
"name": "db-creds",
"type": "opaque",
"namespace": "default",
"data": {
"username": "admin",
"password": "s3cret"
},
"injection": {
"mode": "env",
"prefix": "DB_"
}
}Response: 201 Created
{
"secret": {
"id": "secret-uuid",
"name": "db-creds",
"type": "opaque",
"namespace": "default",
"keyCount": 2,
"injection": { "mode": "env", "prefix": "DB_" },
"createdAt": "2026-02-10T12:00:00.000Z"
}
}GET /api/secrets/name/:name
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
namespace |
string | Namespace (default: default) |
Response:
{
"secret": {
"id": "secret-uuid",
"name": "db-creds",
"type": "opaque",
"namespace": "default",
"keyCount": 2,
"keys": ["username", "password"],
"injection": { "mode": "env", "prefix": "DB_" },
"createdAt": "2026-02-10T12:00:00.000Z",
"updatedAt": "2026-02-10T12:00:00.000Z"
}
}Note: Only key names are returned, never values.
PATCH /api/secrets/name/:name
Request Body:
{
"namespace": "default",
"data": {
"username": "new-admin",
"password": "new-s3cret"
},
"injection": {
"mode": "volume",
"mountPath": "/etc/secrets/db"
}
}Response: 200 OK
DELETE /api/secrets/name/:name
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
namespace |
string | Namespace (default: default) |
Response: 204 No Content
POST /api/volumes
Request Body:
{
"name": "counter-data",
"nodeId": "node-uuid"
}| Field | Type | Description |
|---|---|---|
name |
string | Volume name (lowercase alphanumeric + hyphens, 1–63 chars) |
nodeId |
string | Target node UUID |
Response: 201 Created
{
"success": true,
"data": {
"volume": {
"id": "volume-uuid",
"name": "counter-data",
"nodeId": "node-uuid",
"createdAt": "2026-02-15T12:00:00.000Z",
"updatedAt": "2026-02-15T12:00:00.000Z"
}
}
}Errors:
| Code | Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Invalid name or missing nodeId |
CONFLICT |
409 | Volume name already exists on the node |
GET /api/volumes
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
nodeId |
string | Filter by node UUID (optional) |
Response: 200 OK
{
"success": true,
"data": {
"volumes": [
{
"id": "volume-uuid",
"name": "counter-data",
"nodeId": "node-uuid",
"createdAt": "2026-02-15T12:00:00.000Z",
"updatedAt": "2026-02-15T12:00:00.000Z"
}
]
}
}GET /api/volumes/name/:name
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
nodeId |
string | (required) Node UUID |
Response: 200 OK
{
"success": true,
"data": {
"volume": {
"id": "volume-uuid",
"name": "counter-data",
"nodeId": "node-uuid",
"createdAt": "2026-02-15T12:00:00.000Z",
"updatedAt": "2026-02-15T12:00:00.000Z"
}
}
}GET /api/volumes/name/:name/download
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
nodeId |
string | (required) Node UUID |
Response: 200 OK with Content-Type: application/x-tar
Returns volume contents as a tar archive. In V1 this is a placeholder — full content retrieval from remote nodes is planned.
- Home
- Getting Started
- Concepts
- Core Architecture
- Tutorials
- Reference
- Advanced Topics
- Contribution