Aegis Orchestrator
Reference

REST API Reference

Full HTTP API surface of the AEGIS Orchestrator — all routes, request/response schemas, and authentication.

REST API Reference

The AEGIS Orchestrator exposes an HTTP API on port 8080 (default). All request and response bodies are JSON unless otherwise noted.


Authentication

Route groupMechanism
Most endpointsKeycloak Bearer JWT: Authorization: Bearer <token>
POST /v1/webhooks/{source}HMAC-SHA256 signature: X-Aegis-Signature: sha256=<hex>
POST /v1/dispatch-gatewayInternal — no external auth (agent containers only)
GET /healthNone

Service Account Tenant Delegation

Service accounts (M2M clients using client credentials) may include an X-Tenant-Id: {tenant-slug} request header to scope operations to a specific user tenant. Without this header, service account requests scope to the aegis-system tenant by default.

This header is ignored for all other identity types (consumer users, operator users).


Agents

GET /v1/agents/lookup/{name}

Look up a deployed agent by its unique name. Returns the agent's ID and manifest metadata.

Path parameters:

ParameterDescription
nameThe unique name of the agent (e.g. code-reviewer)

Request headers:

HeaderRequiredDescription
AuthorizationBearer JWT
X-Tenant-IdNoFor service accounts: scope the lookup to this tenant instead of the default aegis-system tenant

Response 200:

{
  "agent_id": "agt-uuid",
  "name": "code-reviewer",
  "tenant_id": "tenant-slug"
}

Errors:

HTTPBodyCause
404{"error": "Agent not found"}No agent with that name exists in the resolved tenant

GET /v1/agents

List all deployed agents visible to the caller's resolved tenant context.

Request headers:

HeaderRequiredDescription
AuthorizationBearer JWT
X-Tenant-IdNoFor service accounts: scope the listing to this tenant instead of the default aegis-system tenant

Response 200:

{
  "agents": [
    {
      "agent_id": "agt-uuid",
      "name": "code-reviewer",
      "tenant_id": "tenant-slug"
    }
  ]
}

Executions

POST /v1/executions

Start an agent execution. Returns immediately with the execution_id; use the SSE stream to follow progress.

Request headers:

HeaderRequiredDescription
AuthorizationBearer JWT
X-Tenant-IdNoFor service accounts: scope the execution to this tenant instead of the default aegis-system tenant

Request body:

{
  "agent_id": "agt-uuid",
  "input": "Write a function that checks if a number is prime."
}
FieldTypeRequiredDescription
agent_idstring (UUID)ID of a deployed agent
inputstringTask input passed to the agent

Response 200:

{
  "execution_id": "exec-uuid"
}

Errors:

HTTPBodyCause
400{"error": "Invalid agent ID"}agent_id is not a valid UUID
500{"error": "<message>"}Execution failed to start

GET /v1/executions/{id}/stream

Stream execution events as Server-Sent Events (SSE). Returns Content-Type: text/event-stream.

Each data: line is a JSON-encoded ExecutionEvent object. Events match the types defined in the gRPC API reference.

Example stream:

data: {"execution_started":{"execution_id":"exec-uuid","agent_id":"agt-uuid","started_at":"2026-03-05T14:00:00Z"}}

data: {"iteration_started":{"execution_id":"exec-uuid","iteration_number":1,"action":"Write a primality check","started_at":"2026-03-05T14:00:01Z"}}

data: {"iteration_completed":{"execution_id":"exec-uuid","iteration_number":1,"output":"def is_prime(n): ...","completed_at":"2026-03-05T14:00:15Z"}}

data: {"execution_completed":{"execution_id":"exec-uuid","final_output":"def is_prime(n): ...","total_iterations":1,"completed_at":"2026-03-05T14:00:15Z"}}

Example (JavaScript EventSource):

const es = new EventSource(
  `https://your-aegis-node/v1/executions/${executionId}/stream`,
  { headers: { Authorization: `Bearer ${token}` } }
);

es.onmessage = (e) => {
  const event = JSON.parse(e.data);
  if (event.execution_completed) {
    console.log('Output:', event.execution_completed.final_output);
    es.close();
  }
};

Human Approvals

GET /v1/human-approvals

List all pending human approval requests.

Response 200:

{
  "pending_requests": [
    {
      "id": "req-uuid",
      "execution_id": "exec-uuid",
      "prompt": "Review the draft and approve or reject.",
      "created_at": "2026-03-05T14:00:00Z",
      "timeout_seconds": 86400
    }
  ]
}

GET /v1/human-approvals/{id}

Get a specific pending approval request.

Response 200:

{
  "request": {
    "id": "req-uuid",
    "execution_id": "exec-uuid",
    "prompt": "Review the draft and approve or reject.",
    "created_at": "2026-03-05T14:00:00Z",
    "timeout_seconds": 86400
  }
}

Errors:

HTTPBodyCause
400{"error": "Invalid request ID"}Not a valid UUID
200{"error": "Request not found or already completed"}Request expired or already resolved

POST /v1/human-approvals/{id}/approve

Approve a pending request and resume the workflow.

Request:

{
  "feedback": "Looks good, approved for production.",
  "approved_by": "alice@example.com"
}

Both fields are optional.

Response 200:

{ "status": "approved" }

POST /v1/human-approvals/{id}/reject

Reject a pending request and transition the workflow to the rejection path.

Request:

{
  "reason": "Needs more citations.",
  "rejected_by": "bob@example.com"
}

reason is required. rejected_by is optional.

Response 200:

{ "status": "rejected" }

SEAL Endpoints

POST /v1/seal/attest

Attestation handshake — used by bootstrap.py at the start of each agent execution to establish an SEAL session.

Request:

{
  "agent_id": "agt-uuid",
  "execution_id": "exec-uuid",
  "container_id": "container-hash",
  "agent_public_key": "<base64-encoded Ed25519 public key>"
}

Response 200:

{
  "security_token": "<JWT>",
  "session_id": "session-uuid",
  "expires_at": "2026-03-05T15:00:00Z"
}

See SEAL Architecture for the full attestation flow.


POST /v1/seal/invoke

SEAL-wrapped tool invocation. Called by bootstrap.py to invoke a tool through the orchestrator proxy. The body is a SealEnvelope containing a signed MCP tool call.

POST /v1/seal/invoke is the spec-compliant path. POST /v1/invoke is also registered as a convenience alias and remains fully functional.

See Tool Routing for the three routing paths and wire format.


Dispatch Gateway

POST /v1/dispatch-gateway

The inner-loop communication endpoint between bootstrap.py and the orchestrator. Handles the full LLM → tool call → LLM cycle.

This endpoint is called by bootstrap.py inside agent containers. It is bound to the internal Docker network and is not exposed externally.

Request — initial generate:

{
  "type": "generate",
  "agent_id": "agt-uuid",
  "execution_id": "exec-uuid",
  "iteration_number": 1,
  "model_alias": "default",
  "prompt": "Task: Write a primality check\n\nInput: in Python",
  "messages": []
}

Request — dispatch result:

{
  "type": "dispatch_result",
  "execution_id": "exec-uuid",
  "dispatch_id": "dispatch-uuid",
  "exit_code": 0,
  "stdout": "All tests passed.\n",
  "stderr": "",
  "duration_ms": 1243,
  "truncated": false
}

Response — final:

{
  "type": "final",
  "content": "def is_prime(n): ...",
  "tool_calls_executed": 2,
  "conversation": [...]
}

Response — dispatch a command:

{
  "type": "dispatch",
  "dispatch_id": "dispatch-uuid",
  "action": "exec",
  "command": "python",
  "args": ["-m", "pytest", "test_prime.py"],
  "cwd": "/workspace",
  "env_additions": {},
  "timeout_secs": 60,
  "max_output_bytes": 524288
}

Stimulus Ingestion

POST /v1/stimuli

Ingest a stimulus from an internal service or operator. Authenticated by Keycloak Bearer JWT.

Request:

{
  "source": "http_api",
  "content": "Deploy release v2.1.0 to production.",
  "idempotency_key": "deploy-v2.1.0"
}
FieldTypeRequiredDescription
sourcestringSource identifier. Use "http_api" or a custom source name.
contentstringStimulus payload — natural language or JSON string.
idempotency_keystringDeduplication key. Scoped to (source, key) with 24-hour TTL.

Response 200:

{
  "stimulus_id": "stim-uuid",
  "workflow_execution_id": "wfex-uuid"
}

Errors:

HTTPCodeCause
409idempotent_duplicateAlready processed within TTL window
422classification_failedRouterAgent confidence below threshold
422no_router_configuredNo direct route and no RouterAgent
500workflow_errorWorkflow execution failed to start

POST /v1/webhooks/{source}

Ingest a webhook from an external system. Authenticated by HMAC-SHA256.

Required headers:

HeaderFormatDescription
X-Aegis-Signaturesha256=<hex>HMAC-SHA256 of the raw body using the source's shared secret
X-Idempotency-Keyany stringOptional — enables duplicate delivery detection

Body: Any content type. The raw body bytes are used for HMAC verification and forwarded as the stimulus content.

Response 200:

{
  "stimulus_id": "stim-uuid",
  "workflow_execution_id": "wfex-uuid"
}

Errors:

HTTPCodeCause
401missing_signatureX-Aegis-Signature header absent
401invalid_signatureHMAC digest mismatch
401secret_not_foundAEGIS_WEBHOOK_SECRET_<SOURCE> not set
400malformed_signatureHeader not in sha256=<hex> format
409idempotent_duplicateSame delivery already processed
422classification_failedRouterAgent confidence below threshold

Workflow Definitions and Executions

Workflow definition and execution management endpoints are available under /v1/workflows. The key response fields related to output schemas are documented below.

Workflow Definition Response Fields

When retrieving a workflow definition, the response includes the full manifest metadata:

FieldTypeDescription
metadata.output_schemaobjectJSON Schema declaring the workflow's output shape (if declared).
metadata.output_templatemap[string, string]Handlebars expressions for extracting final output (if declared).

These fields appear alongside existing metadata fields (name, version, input_schema, etc.).

Workflow Execution Response Fields

When retrieving a workflow execution (e.g. GET /v1/workflows/executions/{id}), the response includes:

FieldTypeDescription
final_outputobjectStructured output produced at workflow completion, if the workflow declares output_template. null when the workflow has no output template or has not yet completed.

The final_output value is the rendered and type-coerced result of evaluating the workflow's output_template against the final Blackboard. It is also returned as last_output in aegis.workflow.wait tool responses.


Billing

All billing endpoints require a valid Keycloak Bearer JWT (Authorization: Bearer <token>). They return 501 Not Implemented if STRIPE_SECRET_KEY is not configured on the orchestrator.

GET /v1/billing/prices

List all available pricing tiers with their Stripe price IDs.

Response 200:

{
  "tiers": [
    {
      "tier": "pro",
      "product_id": "prod_xxx",
      "name": "Pro",
      "description": "For professionals and small teams",
      "included_seats": 1,
      "monthly": { "price_id": "price_xxx", "amount": 2900, "currency": "usd" },
      "annual": { "price_id": "price_yyy", "amount": 29000, "currency": "usd" },
      "seat_monthly": { "price_id": "price_seat_m", "amount": 1500, "currency": "usd" },
      "seat_annual": { "price_id": "price_seat_a", "amount": 15000, "currency": "usd" }
    }
  ]
}
FieldTypeDescription
tiers[].tierstringTier slug (pro, business, enterprise)
tiers[].product_idstringStripe Product ID
tiers[].namestringHuman-readable tier name
tiers[].descriptionstringTier description
tiers[].included_seatsintegerNumber of seats included in the base price
tiers[].monthlyobject or nullMonthly price (price_id, amount in cents, currency)
tiers[].annualobject or nullAnnual price
tiers[].seat_monthlyobject or nullMonthly per-seat price
tiers[].seat_annualobject or nullAnnual per-seat price

POST /v1/billing/checkout

Create a Stripe Checkout Session for subscribing to a plan.

Request body:

{
  "price_id": "price_xxx",
  "seat_price_id": "price_seat_xxx",
  "seats": 5
}
FieldTypeRequiredDescription
price_idstringYesStripe Price ID from GET /v1/billing/prices
seat_price_idstringNoStripe Price ID for per-seat billing
seatsintegerNoNumber of additional seats

Response 200:

{
  "url": "https://checkout.stripe.com/c/pay/cs_live_..."
}

Redirect the user's browser to the returned url to complete payment.


POST /v1/billing/portal

Create a Stripe Customer Portal session for managing payment methods, viewing invoices, and cancelling subscriptions.

Response 200:

{
  "url": "https://billing.stripe.com/p/session/..."
}

GET /v1/billing/subscription

Get the current user's subscription details.

Response 200:

{
  "tier": "pro",
  "status": "active",
  "current_period_end": "2026-05-15T00:00:00Z",
  "cancel_at_period_end": false,
  "stripe_customer_id": "cus_..."
}
FieldTypeDescription
tierstringCurrent subscription tier (free, pro, business, enterprise)
statusstringStripe subscription status (active, past_due, canceled, trialing, etc.)
current_period_endstring (ISO 8601)End of the current billing period
cancel_at_period_endbooleanWhether the subscription will cancel at period end
stripe_customer_idstringThe Stripe Customer ID associated with this user

GET /v1/billing/invoices

List invoices for the current user.

Response 200:

{
  "invoices": [
    {
      "id": "in_...",
      "amount": 2900,
      "currency": "usd",
      "status": "paid",
      "created": "2026-04-01T00:00:00Z",
      "pdf_url": "https://pay.stripe.com/invoice/..."
    }
  ]
}
FieldTypeDescription
idstringStripe Invoice ID
amountintegerInvoice amount in the smallest currency unit (e.g., cents)
currencystringThree-letter ISO currency code
statusstringInvoice status (draft, open, paid, void, uncollectible)
createdstring (ISO 8601)Invoice creation timestamp
pdf_urlstringURL to download the invoice PDF

Health

GET /health

Liveness probe. Returns 200 OK when the orchestrator is running.

Response 200:

{ "status": "ok" }

See Also

On this page