Examples
Copyable request/response pairs for every operation, using placeholder hosts and credentials.
Every example below targets your own app-api origin — shown here as https://your-app-api-host.example, never this site's own hostname — and uses placeholder credentials. Request and response shapes are copied from the current app-api handlers, not reconstructed from memory; field names and status codes are exact.
Log in and read the current session
POST /api/v1/auth/login
Content-Type: application/json
{ "email": "you@example.com", "password": "<password>" }
200 OK
{
"token": "<jwt>",
"expires_at": "2026-09-08T13:00:00Z",
"user": { "id": "...", "email": "you@example.com", "name": "...", "role": "admin", "organization_id": "..." }
}
GET /api/v1/auth/me
Authorization: Bearer <jwt>
200 OK
{ "id": "...", "email": "you@example.com", "name": "...", "role": "admin", "organization_id": "..." }
Register a Runtime
POST /api/v1/runtime/register
X-API-Key: erk_rt_v1_<lookup>_<secret>
Content-Type: application/json
{
"installation_id": "<stable local install identifier>",
"name": "ci-runner-1",
"version": "0.9.8",
"hostname": "ci-runner-1.internal",
"os": "linux",
"nonce": "<32 random bytes, base64url, unpadded>"
}
201 Created
{
"runtime_id": "...",
"name": "ci-runner-1",
"status": "registered",
"bundle": { "envelope": { "domain": "engineeringruntime.sync-bundle/v1", "..." }, "policy": "...", "config": "...", "public_key": "..." },
"receipt": { "domain": "engineeringruntime.registration-receipt/v1", "nonce": "...", "origin": "...", "..." }
}
Fetch the active sync bundle — with and without changes
GET /api/v1/sync-bundles/active
X-API-Key: erk_rt_v1_<lookup>_<secret>
200 OK
ETag: "1.3-9f2c..."
{ "envelope": { "..." }, "policy": "...", "config": "...", "public_key": "..." }
Repeating the request with the ETag you were given:
GET /api/v1/sync-bundles/active
X-API-Key: erk_rt_v1_<lookup>_<secret>
If-None-Match: "1.3-9f2c..."
304 Not Modified
Publish a policy version
POST /api/v1/policies
Authorization: Bearer <jwt>
Content-Type: application/json
{ "version": "v2026090801", "name": "enterprise-policy", "yaml": "<policy YAML>" }
201 Created
{ "version": "v2026090801", "name": "enterprise-policy", "active": true, "updated_at": "...", "updated_by": "you@example.com", "description": "", "yaml": "<policy YAML>" }
Publishing the same version twice is a conflict, not a silent overwrite — versions are immutable so audit records stay resolvable against the exact policy that produced them:
409 Conflict
{ "error": "policy version v2026090801 already exists — versions are immutable so audit records stay resolvable" }
POST /api/v1/configurations follows the identical shape and the identical 409 behavior for managed Runtime configuration.
Create and replace an API key
POST /api/v1/api-keys
Authorization: Bearer <jwt>
Content-Type: application/json
{ "name": "ci-runner-1" }
201 Created
{
"id": "...",
"name": "ci-runner-1",
"state": "unclaimed",
"api_key": "erk_rt_v1_<lookup>_<secret>",
"expires_at": "2026-09-09T12:00:00Z",
"warning": "copy this key now; it will not be shown again"
}
The api_key field is show-once — it is never returned again by GET /api/v1/api-keys, which instead shows a truncated prefix. To rotate credentials for an already-registered Runtime without re-registering it:
POST /api/v1/api-keys/{id}/replace
Authorization: Bearer <jwt>
201 Created
{ "id": "...", "name": "ci-runner-1 replacement", "state": "pending_replacement", "api_key": "erk_rt_v1_<lookup>_<secret>", "expires_at": "2026-09-08T13:00:00Z", "warning": "copy this key now; it will not be shown again" }
The replacement key activates — and its predecessor is revoked — the moment the Runtime authenticates with it for the first time, not when it is created. See Authentication for the full lifecycle.
Read the fleet and the catalog
GET /api/v1/fleet
Authorization: Bearer <jwt>
200 OK
{ "runtimes": [ { "name": "ci-runner-1", "status": "online", "version": "0.9.8", "policy_version": "v2026090801", "last_seen": "...", "hostname": "...", "os": "linux" } ] }
GET /api/v1/providers
Authorization: Bearer <jwt>
200 OK
{ "providers": [ { "id": "github", "name": "GitHub", "status": "connected", "capabilities": 42, "operations": 12, "auth": "token", "last_used": "...", "scope": "" } ], "catalog": "...", "generated_at": "..." }
GET /api/v1/capabilities
Authorization: Bearer <jwt>
200 OK
{ "capabilities": [ { "id": "github/pr-list", "name": "List pull requests", "provider": "github", "description": "...", "path": "..." } ], "total": 1, "catalog": "...", "generated_at": "..." }
GET /api/v1/specifications
Authorization: Bearer <jwt>
200 OK
{ "specifications": [ "..." ], "runtime": "0.9.8", "generated_at": "..." }