Engineering Runtime API

Examples

Copy-paste requests for the flows people actually run.

Every example below runs against the live host. Export a base URL first and paste as-is:

export ER_API=https://api.engineeringruntime.com

Publish a policy and watch a runtime pick it up

Publish a new version:

curl -s -X POST "$ER_API/api/public/policies" \
  -H 'Content-Type: application/json' \
  -d '{
    "version": "v13",
    "name": "enterprise-policy",
    "description": "Deny production writes outside change windows",
    "updated_by": "kishore",
    "yaml": "version: v13\nrules:\n  - id: deny-prod-write\n    effect: deny\n    match:\n      provider: github\n      operation: write\n"
  }'

201 Created comes back with the stored document, and the previous active version is deactivated in the same transaction.

Confirm what a runtime would fetch:

curl -s "$ER_API/api/public/policies?active=true" \
  -H 'X-Runtime-Client: engineering-runtime'

Then sync a runtime and check it landed:

export RUNTIME_PORTAL_ENABLED=true
export RUNTIME_PORTAL_BASE_URL=$ER_API
export RUNTIME_PORTAL_PATH_PREFIX=/api/public

runtime portal sync
runtime policy show

Publishing v13 twice returns 409 — versions are immutable so that audit records stay resolvable.

Ingest a batch of audit events

curl -s -X POST "$ER_API/api/public/audit" \
  -H 'Content-Type: application/json' \
  -d '{
    "events": [
      {
        "executor": "kishore",
        "consumer": "human",
        "command": "github repo list",
        "provider": "github",
        "policy_decision": "ALLOWED",
        "status": "success",
        "duration_ms": 84
      },
      {
        "executor": "claude",
        "consumer": "ai",
        "command": "files write /etc/hosts",
        "provider": "files",
        "policy_decision": "DENIED",
        "reason": "path outside allowed roots",
        "status": "denied",
        "ai": true,
        "duration_ms": 12
      }
    ]
  }'

Response: {"accepted": 2, "events": [...]} with the stored records, ids and ingested_at filled in.

Page through audit history

# Denied commands attributed to AI consumers, newest first
curl -s "$ER_API/api/public/audit?decision=denied&consumer=ai&limit=25"

# Free-text across command, executor, resource, provider, capability
curl -s "$ER_API/api/public/audit?q=repo%20list&limit=10"

# Second page
curl -s "$ER_API/api/public/audit?limit=25&offset=25"

Read total for the count and step offset by limit; returned tells you how many came back in this response.

Read the catalog

# Providers with live status merged from audit
curl -s "$ER_API/api/public/providers"

# Capabilities for one provider
curl -s "$ER_API/api/public/capabilities?provider=github"

# Search capabilities
curl -s "$ER_API/api/public/capabilities?q=secret"

The catalog and generated_at fields in each response tell you which generated document answered — useful when a provider you expect is missing and you need to know whether to redeploy.

Check the fleet

curl -s -X POST "$ER_API/api/public/fleet/heartbeat" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "ci-runner-01",
    "version": "0.9.3",
    "policy_version": "v13",
    "hostname": "gh-runner-7",
    "os": "linux"
  }'

curl -s "$ER_API/api/public/fleet"

Heartbeats upsert on (organization, name), so a runtime reporting every few minutes updates one row rather than accumulating history. Status is derived on read: online under 15 minutes, idle under 24 hours, offline beyond.

Enterprise: log in and manage keys (issued access)

Creating and listing API keys is an enterprise step. Credentials are issued on request via app.engineeringruntime.com — this portal does not publish a password or a sample key. To try the API without access, use the /api/public examples above (or the demo UI at demo.engineeringruntime.com).

With credentials you were issued:

TOKEN=$(curl -s -X POST "$ER_API/api/v1/auth/login" \
  -H 'Content-Type: application/json' \
  -d '{"email":"YOUR_EMAIL","password":"YOUR_PASSWORD"}' \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')

curl -s "$ER_API/api/v1/api-keys" -H "Authorization: Bearer $TOKEN"

curl -s -X POST "$ER_API/api/v1/api-keys" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"ci-runner","scopes":"runtime"}'

The plaintext key appears once, in the create response. Store it before you close the terminal — only its hash is kept.

Use a key from a runtime (after you have one)

export RUNTIME_PORTAL_ENABLED=true
export RUNTIME_PORTAL_BASE_URL=$ER_API
export RUNTIME_PORTAL_PATH_PREFIX=/api/v1
export RUNTIME_PORTAL_API_KEY=erk_…   # from the create response above

runtime portal status
runtime portal sync

For Community / demo try-out without a key, set RUNTIME_PORTAL_PATH_PREFIX=/api/public and omit RUNTIME_PORTAL_API_KEY.

Discover the API from a script

# What is this host, and where are its contracts?
curl -s "$ER_API/"

# Every documented operation, flattened
curl -s "$ER_API/metadata/apis" \
  | python3 -c 'import sys,json
for op in json.load(sys.stdin)["operations"]:
    print(f"{op[\"method\"]:6} {op[\"path\"]}")'

# What does this deployment actually enforce?
curl -s "$ER_API/metadata/authentication"

Generate a client from the contract

curl -sO "$ER_API/openapi.yaml"
openapi-generator-cli generate -i openapi.yaml -g typescript-fetch -o ./er-client

Smoke-test a deployment

curl -fsS "$ER_API/health"
curl -fsS "$ER_API/version"
curl -fsS "$ER_API/api/public/health"
curl -fsS "$ER_API/api/v1/health"
curl -fsS "$ER_API/openapi.yaml" > /dev/null && echo "contract ok"