Skip to content

Runtime API overview

alquimia-runtime exposes a single HTTP API for agent inference, registry management, session state, webhooks, and knowledge operations. It is the boundary between your applications and the Alquimia Platform execution engine.

The runtime API handles:

  • Authentication — API tokens, JWT, and Keycloak OIDC.
  • Inference — synchronous and streaming agent execution via SSE.
  • Registry — storing, versioning, and retrieving agent configurations.
  • State — querying and resuming task state.
  • Channels — webhook endpoints for WhatsApp, Slack, Email, and custom adapters.
  • Webhooks — subscribing to and emitting platform events.

Inference is non-blocking. A client posts a request and receives a task identifier, then opens an SSE stream to receive progress events and the final response.

POST /event/infer/{assistant_id}
│
▼
task_id returned
│
▼
GET /event/stream/{task_id}
│
▼
SSE events ──► final response

This design keeps long-running agents from tying up HTTP connections and lets workers scale independently.

All endpoints except /health/* and the channel webhook paths require a Bearer token in the Authorization header when AUTH_PROVIDER=api_token (the default).

MethodPathAuthSummary
GET/health/livenessNoLiveness probe
GET/health/readinessNoReadiness probe (checks DB + Redis)
POST/auth/refreshNoRefresh a Keycloak access token
POST/event/infer/{assistant_id}YesTrigger agent inference
GET/event/infer/{assistant_id}/{channel_id}Channel verifierChannel webhook challenge
POST/event/infer/{assistant_id}/{channel_id}Channel verifierChannel inference
GET/event/stream/{task_id}YesStream inference events (SSE)
GET / POST/streaming/{assistant_id}/{channel_id}/twimlNoTwiML callback that bridges a Twilio call into the streaming WebSocket
WS/streaming/{assistant_id}/{channel_id}Channel verifierReal-time bidirectional audio stream for Twilio Media Streams
WS/live/{assistant_id}/{channel_id}YesBrowser-native held-open live audio stream
POST/event/tool-approvalYesSubmit human tool approval
POST/event/tool-completionYesSubmit client-side tool result
POST/context/persistNoPersist conversation context
GET/context/retrieveYesRetrieve conversation context
POST/context/blob/uploadYesUpload a blob to session context
GET/context/blob/download/{blob_id}YesDownload a session blob
GET/registry/YesGet a registry (agentspace)
POST/registry/YesCreate a registry
PUT/registry/YesUpdate a registry
DELETE/registry/YesDelete a registry
POST/registry/queryYesQuery registries by filter
POST/registry/validateYesValidate and migrate agent specs
POST/registry/agentYesCreate or update an agent
POST/registry/agent/queryYesQuery agents by filter
DELETE/registry/agentYesDelete agents by filter
PUT/registry/agent/hold/{assistant_id}YesPut an agent on hold
PUT/registry/agent/unhold/{assistant_id}YesRemove an agent from hold
POST/registry/secretYesAdd a secret to a registry
GET/registry/secretYesList secrets in a registry
POST/registry/secret/queryYesQuery secrets by filter
POST/registry/secret/inspect/{assistant_id}YesInspect secrets for an agent
DELETE/registry/secretYesDelete secrets by filter
POST/registry/modelYesAdd a model registration to a registry
GET/registry/modelYesList model registrations in a registry
POST/registry/model/queryYesQuery model registrations by filter
DELETE/registry/modelYesDelete model registrations by filter
POST/registry/brainYesRegister a Boltzmann brain
PUT/registry/brain/{brain_id}YesUpdate a brain registration
GET/registry/brainYesList registered brains
GET/registry/brain/{brain_id}YesGet one brain registration
POST/registry/brain/queryYesQuery brains by filter
DELETE/registry/brainYesDeregister brains by filter
POST/registry/parametersYesAdd parameters to a registry
POST/registry/parameters/queryYesQuery parameters by filter
DELETE/registry/parametersYesDelete parameters by filter
GET/registry/explore/reposYesList OCI registry repositories
GET/registry/explore/tagsYesList tags for an OCI repository
PUT/registry/publishYesPublish a registry to OCI
PUT/registry/unpublishYesRemove a registry from OCI
PUT/registry/pullYesPull a registry from OCI and overwrite the local workspace
PUT/registry/fetchYesPull an OCI tag into a cached versioned snapshot
PUT/registry/load-versionYesLoad a cached versioned snapshot for inference
GET/registry/versionsYesList cached versioned snapshots
DELETE/registry/version/{tag}YesDelete a cached versioned snapshot
GET/toolsYesList tool registrations
GET/tools/{registered_tool_id}YesGet a tool registration
POST/toolsYesRegister or update a tool (admin only)
PUT/tools/{registered_tool_id}/operationsYesReplace a tool’s operations (admin only)
DELETE/tools/{registered_tool_id}YesDelete a tool registration (admin only)
GET/knowledge/topicsYesList knowledge topics
GET/knowledge/topics/{topic_id}YesGet a topic by ID
POST/knowledge/topicsYesCreate a topic
DELETE/knowledge/topics/{topic_id}YesDelete a topic
PUT/knowledge/topics/{topic_id}/updateYesUpdate a topic
PUT/knowledge/topics/{topic_id}/tagYesTag a topic
PUT/knowledge/topics/{topic_id}/untagYesUntag a topic
PUT/knowledge/topics/{topic_id}/policyYesUpdate a topic’s access policy
POST/knowledge/topics/search/{topic_id}YesSemantic search within a topic
PUT/knowledge/topics/{topic_id}/add/{file_id}YesAdd a file to a topic
PUT/knowledge/topics/{topic_id}/remove/{file_id}YesRemove a file from a topic
GET/knowledge/filesYesList knowledge files
POST/knowledge/files/uploadYesUpload a knowledge file
GET/knowledge/files/download/{file_id}YesDownload a knowledge file
DELETE/knowledge/files/delete/{file_id}YesDelete a knowledge file
PUT/knowledge/files/{file_id}/tagYesTag a knowledge file
PUT/knowledge/files/{file_id}/untagYesUntag a knowledge file
PUT/task/state/{task_id}/{state_id}YesUpdate controller state (run/stop/restart)
GET/worklog/YesList inference runs (paginated, with filters)
GET/worklog/{task_id}YesFull detail for one inference run
GET/worklog/{task_id}/eventsYesAll worklog events for a task
GET/worklog/{task_id}/verifyYesVerify the tamper-evident hash chain for a task
POST/webhooks/YesRegister a webhook subscription
GET/webhooks/YesList webhook subscriptions for an agentspace
GET/webhooks/{id}YesGet a webhook subscription
PUT/webhooks/{id}YesUpdate a webhook subscription (URL, event types, active, rotate key)
DELETE/webhooks/{id}YesDelete a webhook subscription

The two /event/infer/{assistant_id}/{channel_id} endpoints are public webhook URLs intended to be called by external channel providers (WhatsApp, Slack, email gateways, etc.). Authentication is provider-specific and implemented by the channel itself.

Trigger inference for a named agent. Returns a CommonAttributes object containing the task_id you can use to stream results.

Path parameter: assistant_id — the agent identifier in the registry. As of runtime 0.5.1, the identifier may include a version tag: <assistant_id>:<tag>.

Query parameter: agentspace_id (default: "default") — the registry namespace.

Request body

FieldTypeRequiredDescription
querystring or arrayNoPlain text or OpenAI-style content parts for multimodal input. At least one of query or input_audio must be provided
input_audioBlobNoBase64-encoded audio data for audio-only inference (Core 0.5.1+)
task_idstringNoAuto-generated if omitted
session_idstringNoAuto-generated if omitted
user_idstringNoAuto-generated if omitted
extra_instructionsobjectNoKey-value pairs injected as prompt clauses
evaluation_strategyobjectNoOverride the agent’s evaluation strategy
knowledge_basearrayNoAdditional knowledge bases to include

The resolved version_tag is returned in the response and propagated through inference entry points (event, streaming, live, and channel_notifications).

Responses

CodeDescription
200CommonAttributes with task_id, session_id, assistant_id, agentspace_id, and version_tag
400Agent not found, on hold, or missing secrets
500Connection error (Redis, Kafka, or downstream service)

Example:

Terminal window
curl -X POST http://localhost:8080/event/infer/support-bot \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "What is your return policy?",
"session_id": "session-abc123",
"user_id": "user-42"
}'

Stream inference progress as Server-Sent Events. Poll this after calling /event/infer/.

Terminal window
curl -N http://localhost:8080/event/stream/task-abc123 \
-H "Authorization: Bearer $API_TOKEN"

The stream emits WorklogRecord events and closes when an AssistantInferenceResponse event is received.

Open a real-time bidirectional audio stream for a held phone or WebRTC call. The runtime validates the channel configuration, performs Twilio Account SID verification on the start event, enforces per-source session limits, and segments turns with energy-based VAD. Assistant replies are streamed back as μ-law audio.

The WebSocket path is:

ws://localhost:8080/streaming/{assistant_id}/{channel_id}
  • assistant_id may include a version tag (support-bot:v1.2.0).
  • channel_id must match a streaming_channels entry in the agent spec.
  • Close code 1008 is returned for policy violations (for example, an invalid Account SID or rate limit exceeded).
  • Close code 1011 is returned for internal server errors.

Streaming sessions are governed by the STREAMING_CHANNEL_* runtime settings. See Runtime configuration reference and Connect a messaging or voice channel for details.

GET/POST /streaming/{assistant_id}/{channel_id}/twiml

Section titled “GET/POST /streaming/{assistant_id}/{channel_id}/twiml”

Return TwiML that instructs Twilio to open a Media Stream to the matching WebSocket endpoint. Configure this HTTPS URL as the Twilio Voice webhook for inbound or outbound calls.

The optional token query parameter is forwarded into the WebSocket URL so the streaming upgrade can authenticate when STREAMING_CHANNEL_AUTH_REQUIRED is enabled.

Terminal window
curl "https://runtime.example.com/streaming/support-bot/twilio-phone/twiml?token=$API_TOKEN"

Response:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect>
<Stream url="wss://runtime.example.com/streaming/support-bot/twilio-phone?token=..." />
</Connect>
</Response>

Open a browser-native held-open live audio stream. Unlike the Twilio /streaming endpoint, /live speaks a simple JSON envelope over RFC 6455 WebSocket and exchanges PCM s16le 16 kHz mono audio. No Twilio Media Streams framing is required, so it can be used directly from a browser or any client that can encode and decode PCM audio.

After the WebSocket upgrade, the client sends JSON messages such as:

{ "event": "audio", "payload": "<base64 pcm_s16le 16khz mono>" }

The runtime validates the bearer token, enforces per-source session limits, segments turns with energy-based VAD, evaluates each utterance through the agent, and streams the assistant reply back in the same JSON envelope. The client may send {"event": "stop"} to end the session gracefully.

The WebSocket path is:

wss://runtime.example.com/live/{assistant_id}/{channel_id}
  • assistant_id may include a version tag (support-bot:v1.2.0).
  • channel_id must match a streaming_channels entry in the agent spec with provider_id: browser-media-stream.
  • Requires a Bearer token in the Authorization header or a token query parameter.
  • Close code 1008 is returned for policy violations (for example, rate limit exceeded or missing audio config).
  • Close code 1011 is returned for internal server errors.
  • Per-utterance turns are persisted to PostgreSQL and copied to the Redis event stream, so live browser calls share the runtime worklog and SSE stream.
Terminal window
curl -i -N \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Sec-WebSocket-Key: $(openssl rand -base64 16)" \
-H "Sec-WebSocket-Version: 13" \
https://runtime.example.com/live/support-bot/browser-audio

See Agent specification reference for the browser-media-stream configuration and Connect a messaging or voice channel for setup steps.

Query the persistent inference history stored in PostgreSQL. Supports filtering by session_id, user_id, assistant_id, agentspace_id, final_status, started_after, and started_before. Paginated via limit (1–200) and offset.

Terminal window
curl "http://localhost:8080/worklog/?assistant_id=support-bot&limit=20" \
-H "Authorization: Bearer $API_TOKEN"

Verify the tamper-evident hash chain for a task. The endpoint walks every worklog event in insertion order and checks that previous_hash links and entry_hash values match the canonical payload. If any row has been modified or reordered, the first break is returned.

Terminal window
curl "http://localhost:8080/worklog/task-abc123/verify" \
-H "Authorization: Bearer $API_TOKEN"

Validates all agent specs in a registry and applies automatic migrations. Use dry_run=true to preview changes without committing them.

Terminal window
curl -X POST "http://localhost:8080/registry/validate?agentspace_id=default&dry_run=true" \
-H "Authorization: Bearer $API_TOKEN"

Register an external HTTP endpoint to receive CloudEvents when inference events fire. The signing_key is returned only on creation.

Request body

FieldTypeRequiredDescription
agentspace_idstringYesAgentspace scope
sink_urlstringYeshttp:// or https:// endpoint
assistant_idstringNoLimit delivery to one agent
event_typesarrayNoEvent types to forward; empty = all
signing_keystringNo64-character hex HMAC-SHA256 key; auto-generated if omitted

Every POST to your sink includes:

  • Content-Type: application/cloudevents+json
  • X-Webhook-Signature: sha256=<hex>
  • X-Webhook-Event
  • X-Alquimia-Agentspace

Verify the signature with HMAC-SHA256 of the raw request body using the signing key.

The /registry/* endpoints mutate the local TinyDB agentspace store. In production, registry write endpoints should only be reachable from the master instance; workers mount the registry read-only.

GET /registry/, POST /registry/, PUT /registry/, DELETE /registry/

Section titled “GET /registry/, POST /registry/, PUT /registry/, DELETE /registry/”

Create, read, update, and delete agentspaces.

Terminal window
# Create an agentspace
curl -X POST http://localhost:8080/registry/ \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "production", "namespace": "production"}'

Create or update an agent in the agentspace. The body is a full AssistantConfig JSON document.

Terminal window
curl -X POST http://localhost:8080/registry/agent?agentspace_id=default \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d @support-bot.json

PUT /registry/publish and PUT /registry/pull

Section titled “PUT /registry/publish and PUT /registry/pull”

Publish pushes the agentspace as a signed OCI artifact. Pull fetches an artifact and rehydrates local knowledge bases.

As of runtime 0.5.4, PUT /registry/publish accepts the following query parameters:

ParameterTypeDescription
agentspace_idstringAgentspace to publish (default: default)
tagstringVersion tag, e.g. v1.0.0
targetstringOptional OCI repository to push to; defaults to the deployment namespace
include_agentsstring[]Optional agent IDs to include; validation is scoped to this subset
exclude_agentsstring[]Optional agent IDs to exclude from the publish
include_secretsbooleanAlso push secret metadata (key, scope, dtype, required) — values are never included

PUT /registry/unpublish accepts agentspace_id, tag, and an optional target.

Terminal window
curl -X PUT "http://localhost:8080/registry/publish?agentspace_id=default&tag=v1.0.0" \
-H "Authorization: Bearer $API_TOKEN"
# Publish only a subset of agents and include secret metadata
curl -X PUT "http://localhost:8080/registry/publish?agentspace_id=default&tag=v1.0.0&include_agents=support-bot,billing-bot&include_secrets=true" \
-H "Authorization: Bearer $API_TOKEN"
curl -X PUT "http://localhost:8080/registry/pull?agentspace_id=default&source_repo_id=ghcr.io/acme/alquimia/default:v1.0.0" \
-H "Authorization: Bearer $API_TOKEN"

As of alquimia-core 0.5.5, PUT /registry/publish supports target, include_agents, exclude_agents, and include_secrets query parameters, matching the CLI. PUT /registry/unpublish supports target. OCI push, delete_manifest, and pull run in an asyncio thread pool with a timeout controlled by ALQUIMIA_OCI_SUBPROCESS_TIMEOUT (default 120s). A subprocess timeout returns HTTP 504; an OCI runtime error returns HTTP 502.

Runtime 0.5.1 adds API operations for cached, versioned registry snapshots. These let you pull and run a specific OCI tag without overwriting the workspace dist.json.

MethodPathDescription
PUT/registry/fetchPull an OCI tag into a cached <tag>.json snapshot
PUT/registry/load-versionLoad a cached snapshot so subsequent inferences resolve against it
GET/registry/versionsList cached snapshots for an agentspace
DELETE/registry/version/{tag}Remove a cached snapshot
Terminal window
# Fetch a versioned snapshot
curl -X PUT "http://localhost:8080/registry/fetch?agentspace_id=default&tag=v1.2.0" \
-H "Authorization: Bearer $API_TOKEN"
# List cached versions
curl "http://localhost:8080/registry/versions?agentspace_id=default" \
-H "Authorization: Bearer $API_TOKEN"
# Run inference against a tagged assistant
curl -X POST "http://localhost:8080/event/infer/support-bot:v1.2.0?agentspace_id=default" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "What is the refund policy?"}'

The resolved version_tag is returned in CommonAttributes and propagated through inference entry points.

See Publish and pull an agentspace and Registry & OCI.

POST /registry/secret/inspect/{assistant_id}

Section titled “POST /registry/secret/inspect/{assistant_id}”

Returns the resolved status of every secret referenced by an agent, which is useful when inference fails with missing-secret errors.

Terminal window
curl -X POST "http://localhost:8080/registry/secret/inspect/support-bot?agentspace_id=default" \
-H "Authorization: Bearer $API_TOKEN"

Tool registration endpoints are admin-only in most deployments because a tool’s connection config and operation classification form the trust boundary.

Register or update a ToolRegistration, including per-operation classification.

Terminal window
curl -X POST http://localhost:8080/tools \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"registered_tool_id": "filesystem-tools",
"provider_id": "mcp",
"connection_config": {"url": {"$secretRef": "MCP_PROVIDER_URL"}},
"operations": [
{"name": "list_files", "match": "exact", "severity": "read-only", "tier_grants": ["reader", "editor", "operator"]},
{"name": "delete_*", "match": "glob", "severity": "destructive", "tier_grants": ["operator"], "approval_required": true}
]
}'

See Authorization policies for how tier_grants and severity interact with agent role tiers.

Create a topic. The vector-store provider is controlled by ALQUIMIA_KNOWLEDGE_PROVIDER; do not pass distanceMetric, vectorSize, or a per-topic connector.

Terminal window
curl -X POST http://localhost:8080/knowledge/topics?agentspace_id=default \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "product-docs",
"description": "Product documentation",
"is_active": true
}'

The response contains the generated id (the topic’s UUID).

Upload a file. The response contains the file’s generated id.

Terminal window
curl -X POST "http://localhost:8080/knowledge/files/upload?agentspace_id=default" \
-H "Authorization: Bearer $API_TOKEN" \
-F "file=@release-notes.pdf"

PUT /knowledge/topics/{topic_id}/add/{file_id}

Section titled “PUT /knowledge/topics/{topic_id}/add/{file_id}”

Associate an uploaded file with a topic. Passing ?hydrate=true chunks and indexes the file through the configured knowledge provider.

Terminal window
curl -X PUT "http://localhost:8080/knowledge/topics/550e8400-e29b-41d4-a716-446655440000/add/6ba7b810-9dad-11d1-80b4-00c04fd430c8?hydrate=true" \
-H "Authorization: Bearer $API_TOKEN"

As of runtime 0.5.4, this endpoint still accepts a TextSplitterConfig body for backward compatibility but ignores it — core 0.5.5 handles chunking internally. The response no longer returns chunk contents; only totalDocuments is populated.

PUT /knowledge/topics/{topic_id}/remove/{file_id}

Section titled “PUT /knowledge/topics/{topic_id}/remove/{file_id}”

Remove a file from a topic. As of runtime 0.5.4, this deletes the file registration entirely (vectors plus the unreferenced blob), not just the topic association.

Run a semantic search within a topic. As of runtime 0.5.1, SearchInTopic supports search_mode, brain_ref, and modules for brain-mode and direct-mode queries.

Terminal window
curl -X POST "http://localhost:8080/knowledge/topics/search/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "return policy", "k": 4}'

Update a topic’s access policy using the TopicPolicyInUpdate schema.

Terminal window
curl -X PUT "http://localhost:8080/knowledge/topics/550e8400-e29b-41d4-a716-446655440000/policy" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"access_policy": {
"severity": "read-only",
"tier_grants": ["reader", "editor", "operator"]
}
}'

The standalone /knowledge/tags/* endpoints have been removed. Use /knowledge/topics/{topic_id}/tag/untag and /knowledge/files/{file_id}/tag/untag instead.

See How to ingest files into a topic for the full workflow.

Update the controller state of an inference task. Supported states are typically run, stop, and restart.

Terminal window
curl -X PUT http://localhost:8080/task/state/task-abc123/stop \
-H "Authorization: Bearer $API_TOKEN"

The two /event/infer/{assistant_id}/{channel_id} endpoints are public webhook URLs:

  • GET handles provider challenge handshakes via the channel’s resolve_challenge method.
  • POST accepts inbound messages and calls the channel’s verify_inbound method before running inference.

As of runtime 0.5.4, both endpoints accept an optional user_id query parameter. When provided, the authenticated user identifier is propagated through secret resolution, enabling per-user local and shared secrets with fallback to scope defaults.

A channel that does not implement provider-specific auth is rejected unless CHANNEL_AUTH_REQUIRED=false.

Select the auth backend with AUTH_PROVIDER:

ModeHow it works
api_token (default)Pass Authorization: Bearer $API_TOKEN on every request
jwtSet JWT_SECRET and pass a signed JWT as the Bearer token
keycloakValidate tokens against a Keycloak realm; use /auth/refresh to refresh access tokens

See Authentication & authorization for deployment guidance.