API reference¶
A quick reference to the HTTP endpoints you are most likely to call directly — for scripting, automation, or debugging. TheYgent has two services, each with its own base URL:
- Control plane —
http://localhost:8080— agents, runs, sessions, triggers, connections, artifacts, observability. - Inference plane —
http://localhost:8081— the OpenAI-compatible data plane (/v1/*) and model management (/admin/*).
The interface uses these same endpoints, so anything you can do in the UI you can do here. This page lists the user-facing surface; it is not the full internal API.
Wire conventions
Control-plane request bodies and stored run/session records use snake_case (session_id, content_hash). The immediate run result envelope and streaming (SSE) frames use camelCase (runId). The inference plane (/v1/* and /admin/*) is camelCase throughout. The graph document (ir) is always camelCase. Keep them straight when you assemble a body.
Authentication
Every control-plane endpoint below requires a bearer token — Authorization: Bearer <token> — where the token is either your interactive session or, for scripts and your own frontends, an API key minted from your profile. Endpoints are gated by role (viewer / editor / admin); see Users, roles & sign-in. Three surfaces differ: /healthz + /readyz are open, webhook delivery POST /hooks/{id} carries an HMAC signature instead, and POST /agents/{id}/invoke accepts an API key or the shared THEYGENT_INVOKE_TOKEN. The inference plane is a separate, locally-trusted service — still do not expose either plane to an untrusted network.
Control plane¶
Health¶
| Method | Path | Purpose |
|---|---|---|
| GET | /healthz |
Liveness — is the process up? Returns {"status":"ok"}. |
| GET | /readyz |
Readiness — 200 when ready, 503 not-ready naming the down dependency (database or inference plane). |
Agents¶
Published agents are immutable, content-addressed versions. See Drafts & publishing and Agent versioning.
| Method | Path | Purpose |
|---|---|---|
| POST | /agents |
Publish a new agent from an IR document. Body {ir, name?}. 201; reusing an existing id → 409 agent_exists. |
| GET | /agents |
List agents, newest first (limit 1–200 default 50, before cursor). |
| GET | /agents/{id} |
One agent with its versions, newest first. |
| POST | /agents/{id}/versions |
Publish a new version. Identical content under an existing version is an idempotent 200; different content under the same version → 409 version_conflict. |
| GET | /agents/{id}/versions/{version} |
The full stored IR + canvas layout for one version. |
| GET / PUT | /agents/{id}/io-policy |
Read/set the per-agent I/O capture policy. PUT body {io_capture, io_retention_seconds?, redact_rules?}. Setting it never changes the content hash. |
| DELETE | /agents/{id} |
Delete the whole agent: all its versions, its triggers (schedules stop firing), and its I/O policy, in one step. 204; unknown id → 404 agent_not_found. Past runs, chats, and drafts survive — they keep the agent id and content hash as breadcrumbs. |
Individual versions are immutable — there is no endpoint to edit or delete a single version. Deleting the agent removes every version at once; there is no delete for runs.
Samples¶
The shipped example-agent catalog. Installing publishes an ordinary agent (same registry, same
gate as POST /agents) with your chosen models stamped into its bindings, creating any MCP
connections the sample needs. See Sample agents.
| Method | Path | Purpose |
|---|---|---|
| GET | /samples |
The catalog: title, capabilities, model slots, connections, and per-sample installed state. Any signed-in role. |
| POST | /samples/install |
Install by catalog id. Body {ids, models: {slot: {logical_id, binding}}}. Editor role. Unfilled slots → 400 sample_models_required, an illegal binding → 400 sample_model_invalid (nothing written in either case); unknown id → 404 sample_not_found. Beyond agents (children first for composition samples), an install creates the sample's MCP connections and RAG sources (reused by name on reinstall) and registers any shipped trigger disabled. The response report carries one entry per sample — installed, already_installed, or error (that sample rolled back and persisted nothing; the rest of the batch still ran) — with connections, rag_sources, and warnings (degraded-install notes, e.g. seed ingest could not start). Reinstalling after deleting only some of a sample's agents repairs the missing pieces. |
Drafts¶
The editor's autosave tier: mutable work-in-progress graphs. A draft is never validated as a graph (a half-wired document must still save; only "the ir is a JSON object" is enforced → 400 invalid_draft) and never hashed. The canvas layout (view) is stored alongside the document. See Drafts & publishing.
| Method | Path | Purpose |
|---|---|---|
| POST | /drafts |
Create a draft. Body {ir, agent_id?} — agent_id links the draft to the published agent it edits (optional, immutable after create). 201. |
| PUT | /drafts/{id} |
Replace the draft's document (the autosave write). Body {ir}. |
| GET | /drafts |
List drafts, most recently edited first (limit 1–200 default 50, before cursor, optional agent_id filter). Summaries only — no ir/view. |
| GET | /drafts/{id} |
The full draft, ir + view — what the editor reloads. |
| DELETE | /drafts/{id} |
Discard a draft. 204. |
Unknown ids are 404 draft_not_found. Unlike versions, drafts are freely deletable — the editor deletes the working draft itself after a successful publish.
Runs¶
Statuses: created → streaming → waiting → completed | failed. See Runs & sessions.
| Method | Path | Purpose |
|---|---|---|
| POST | /runs |
Plain prompt run. Body {input, model, params?, stream?, session_id?}. model is a logical id. Streams SSE by default. |
| POST | /graphs/runs |
Run an inline IR graph — no publish needed (this is what the editor's Test panel uses). Body {ir, input, stream?, session_id?}. Invalid IR → 400 invalid_ir (no run row created). |
| POST | /agents/{id}/runs |
Run a published agent by reference. Body {input, version?, content_hash?, session_id?, stream?}. |
| POST | /agents/{id}/invoke |
Token-authed, non-interactive sibling of the above. Same body but stream defaults false. Requires a bearer token. |
| POST | /agents/{id}/durable-runs |
Run a published agent on the durable runtime (the only way to run human/subgraph/loop/map agents). Returns 202 {run_id}; poll GET /runs/{id}. Needs durable mode. |
| GET | /runs |
List runs, newest first (limit, before). |
| GET | /runs/{id} |
Run detail, including output, error, content_hash, trigger_id, awaiting_node, completed_at. |
| POST | /runs/{id}/resume |
Deliver input to a run paused (waiting) at a human node. Body {input}. Returns 202. |
Start a streaming prompt run:
curl -N -X POST http://localhost:8080/runs \
-H 'Content-Type: application/json' \
-d '{"input": "Summarize the theory of relativity.", "model": "triage-fast", "stream": true}'
The stream is Server-Sent Events: run (status frames), delta (answer tokens), reasoning (model thinking, kept out of the output), terminated by data: [DONE]. Set "stream": false for a single JSON response {runId, status, output}.
Run a published agent (non-streaming) with a session:
curl -X POST http://localhost:8080/agents/agent.support/runs \
-H 'Content-Type: application/json' \
-d '{"input": {"question": "Where is my order?"}, "session_id": "ses_abc", "stream": false}'
Invoke an agent with the invoke token:
curl -X POST http://localhost:8080/agents/agent.support/invoke \
-H 'Authorization: Bearer YOUR_INVOKE_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"input": {"question": "Where is my order?"}}'
Resume a waiting run:
curl -X POST http://localhost:8080/runs/RUN_ID/resume \
-H 'Content-Type: application/json' \
-d '{"input": {"approved": true}}'
Observability¶
Per-run trace data. See Observability.
| Method | Path | Purpose |
|---|---|---|
| GET | /runs/{id}/trace |
The persisted span tree (timing, status, attribution) — no payloads. |
| GET | /runs/{id}/trace/stream |
Live SSE overlay: events span.open, span.close, done; : keepalive comment every 15s. |
| GET | /runs/{id}/nodes/{node_id}/io |
Lazy per-node input/output payloads, gated by the capture policy (a gated state is a reason, never an error). |
Triggers & webhooks¶
A trigger deploys a published, pinned agent behind an unattended entry point. See Triggers & webhooks.
| Method | Path | Purpose |
|---|---|---|
| POST | /triggers |
Create a trigger. Body {agent_id, kind, version?|content_hash?, config, enabled?}. Pin exactly one of version/content_hash. |
| GET | /triggers |
List triggers (webhook secrets redacted to "***"). |
| GET / PATCH / DELETE | /triggers/{id} |
Read / update (enabled, config only — kind and pin are immutable) / delete a trigger. |
| POST | /hooks/{id} |
Fire a webhook trigger. The raw JSON body is the run input; requires the X-TheYgent-Signature header. Returns 202. |
Trigger config keys: schedule needs config.cron (a valid cron expression) and takes optional config.input; webhook needs config.secret (the inbound signing secret).
Fire a webhook — the signature is the HMAC-SHA256 of the raw request body keyed by the trigger's secret:
BODY='{"question":"Where is my order?"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "YOUR_WEBHOOK_SECRET" | awk '{print $2}')
curl -X POST http://localhost:8080/hooks/TRIGGER_ID \
-H "X-TheYgent-Signature: sha256=$SIG" \
-H 'Content-Type: application/json' \
-d "$BODY"
A bad or missing signature → 401 invalid_signature; a disabled trigger → 409 trigger_disabled.
Sessions¶
Opt-in conversational memory. See Runs & sessions.
| Method | Path | Purpose |
|---|---|---|
| GET | /sessions |
List sessions, newest activity first. |
| GET | /sessions/{id} |
Session detail with messages in order. |
| POST | /sessions |
Create/ensure a session. Body {id?, metadata?}; a missing id is minted server-side. |
| POST | /sessions/{id}/turns |
Append a {user_content, assistant_content} pair (both non-blank). |
| DELETE | /sessions/{id} |
Delete the session and its messages; its runs are detached, not deleted. |
Connections¶
Named tool/MCP credentials. The secret is write-only and never returned. See Tools and MCP servers.
| Method | Path | Purpose |
|---|---|---|
| POST | /connections |
Create. Body {name, kind, config, secret?, enabled?}. kind is http_auth or mcp_server. |
| GET | /connections |
List (responses expose hasSecret only; secret-ish config keys redacted). |
| GET / PATCH / DELETE | /connections/{id} |
Read / update (a non-empty secret rotates in place without changing any content hash) / delete. |
RAG sources¶
Retrieval collections agents search through the rag node. See RAG sources.
| Method | Path | Purpose |
|---|---|---|
| POST | /rag/sources |
Create. Body {name, kind, embedding_model, config}. kind is upload or crawl; for crawl, config carries root_url (required), max_pages?, render_js?. embedding_model is a logical id, never an engine name. |
| GET | /rag/sources |
List (keyset pagination via limit + before). |
| GET / PATCH / DELETE | /rag/sources/{id} |
Read (status + live ingest progress) / rename or edit crawl config / delete with all documents and vectors. |
| GET | /rag/sources/{id}/documents |
The source's documents with per-document status, chunk counts, and errors. |
| POST | /rag/sources/{id}/documents?filename=… |
Upload one document as a raw body (the Content-Type header is the file's mime; 50 MiB cap). Returns 202; poll the source for progress. |
| POST | /rag/sources/{id}:ingest |
Start (or re-run) the crawl. 202; unchanged pages are hash-skipped. 409 while an ingest is already running. |
| POST | /rag/sources/{id}:cancel |
Cancel the in-flight ingest (a no-op on a settled source). |
| POST | /rag/sources/{id}/query |
Run the same hybrid retrieval a rag node runs. Body {query, top_k?, min_similarity?}; returns the match list. |
curl -X POST "http://localhost:8080/rag/sources/rag_01ABC/documents?filename=handbook.pdf" \
-H 'Content-Type: application/pdf' \
--data-binary @handbook.pdf
Artifacts¶
Audio/image blobs by reference. See Voice.
| Method | Path | Purpose |
|---|---|---|
| POST | /artifacts |
Upload raw bytes (the Content-Type header is the stored mime). Returns 201 {ref, contentType, bytes}. |
| GET | /artifacts/{ref} |
Fetch a stored art_… blob (only art_* ids are served). |
| PUT | /artifacts/{ref} |
Store raw bytes under a ref you supply — the restore path an import uses so refs embedded in imported runs keep resolving. The ref must be a full art_ + 26-character id exactly as POST /artifacts mints them (400 invalid_artifact_ref otherwise). An existing ref is never overwritten: a fresh write returns 201 {ref, contentType, bytes, created: true}, a ref that already exists returns 200 with the stored artifact's metadata and created: false. |
curl -X POST http://localhost:8080/artifacts \
-H 'Content-Type: audio/webm' \
--data-binary @recording.webm
MCP servers¶
Register external tool servers. See MCP servers and MCP tools.
Name-keyed registrations (plain stdio/remote servers, no secrets — openapi/graphql must be created as connections instead):
| Method | Path | Purpose |
|---|---|---|
| PUT / GET / DELETE | /admin/mcp/servers/{name} |
Register / read / remove a server config. |
| GET | /admin/mcp/servers |
List registered servers (env values are never echoed). |
| GET | /admin/mcp/servers/{name}/tools |
List the server's tools (lazy-connects; unreachable → 503 mcp_unavailable). |
| POST | /admin/mcp/servers/{name}:warm / :close |
Start / stop the server process. |
Connection-backed servers (everything the MCP page creates — hub installs, remote servers with auth, OpenAPI/GraphQL servers) get the same operational surface through their connection id:
| Method | Path | Purpose |
|---|---|---|
| GET | /connections/{id}/mcp/tools |
List the server's tools through the connection (lazy-connects; unreachable → 503 mcp_unavailable). |
| POST | /connections/{id}/mcp:warm / :close |
Connect the server now / tear down the live connection (the connection row is kept). |
| POST | /connections/{id}/mcp-oauth:start |
Begin interactive authorization for an auth.type: oauth connection. Returns {status, authorizationUrl?} — open the URL in a browser; the provider redirects back to /mcp/oauth/callback. |
| GET | /connections/{id}/mcp-oauth |
Authorization status: {authorized, pending, lastError, connected}. Tokens are never returned. |
MCP hubs (catalog)¶
Browse MCP registries and install published servers. Bodies and responses on this surface are camelCase. See MCP servers.
| Method | Path | Purpose |
|---|---|---|
| GET | /admin/mcp/registries |
The browsable registries: the two built-ins plus any from THEYGENT_MCP_REGISTRIES. |
| GET | /admin/mcp/catalog |
One page of a registry's servers (registry, search, limit 1–100, cursor); entries carry installed-state stamps. A registry that can't be reached → 502 mcp_registry_error. |
| GET | /admin/mcp/catalog/entry |
One server (registry, name, version default latest) with its install candidates and their declared inputs. |
| POST | /admin/mcp/catalog/install |
Install a candidate as an mcp_server connection. Body {registry, name, version?, candidateId, connectionName, values, useOauth?}. Secret-flagged values go to the encrypted store server-side. Returns 201 with the connection. |
| POST | /admin/mcp/generated:preview |
The tools an OpenAPI/GraphQL server would derive — nothing is created. Body {kind, spec?|specUrl?, url?, allowMutations?}. |
Bench store¶
The Bench records results and presets here; testing itself runs against the inference plane. See The Bench.
| Method | Path | Purpose |
|---|---|---|
| POST / GET | /bench/runs |
Record / list bench results (filter by logical_id, agent_id, suite_id, case_id). |
| GET | /bench/compare?a=&b= |
Per-metric deltas between two saved results. |
| POST / GET / DELETE | /bench/presets |
Save / list / delete named param presets. |
| POST / GET | /bench/suites |
Store / list golden-case suites (API-only; no UI yet). |
Import & export¶
The control-plane half of the transfer bundle — the Settings Import / Export tab drives these plus the inference plane's pair below. See Import & export.
| Method | Path | Purpose |
|---|---|---|
| POST | /export |
Build a bundle. Body {"include": [...]} — any non-empty subset of agents, runs, traces, sessions, mcp, rag (traces implies runs); anything else → 400 invalid_include. Returns the bundle JSON. Never contains secret values, secret refs, webhook signing secrets, or MCP env/header values (key names only). |
| POST | /import |
Apply a bundle (the same shape; sections optional). Id-preserving, idempotent, skip-on-exists; one bad entry never aborts the rest. Returns {report} with per-section counts and a flat warnings list. Not a bundle → 400 invalid_bundle; a future format_version → 400 unsupported_bundle_version. |
curl -X POST http://localhost:8080/export \
-H 'Content-Type: application/json' \
-d '{"include": ["agents", "sessions"]}' -o control-plane.json
curl -X POST http://localhost:8080/import \
-H 'Content-Type: application/json' \
--data-binary @control-plane.json
Inference plane¶
The data plane is OpenAI-compatible. In every /v1/* call, the model field is a logical id you registered — never an engine name. See Models & engines.
Data plane (/v1/*)¶
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/models |
List registered logical ids as OpenAI model objects. |
| POST | /v1/chat/completions |
Chat (and vision — messages content may be text + image_url parts). Streaming and non-streaming. |
| POST | /v1/embeddings |
Embeddings. input is a string or list of strings. |
| POST | /v1/audio/transcriptions |
Speech-to-text. Multipart form with model + file. |
| POST | /v1/audio/speech |
Text-to-speech. {model, input, voice?}; returns raw audio bytes. |
| POST | /v1/images/generations |
Text-to-image. {model, prompt, size?, n?, steps?}; returns {data:[{b64_json}]}. |
curl http://localhost:8081/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model": "triage-fast", "messages": [{"role":"user","content":"Hello"}]}'
Model management (/admin/*)¶
| Method | Path | Purpose |
|---|---|---|
| PUT | /admin/models/{id} |
Register/replace a model under a logical id. |
| GET | /admin/models |
List registered models with live state. |
| GET / DELETE | /admin/models/{id} |
Read one / unregister (evicts then deletes). |
| GET | /admin/models/{id}/capabilities |
Probe tool-calling, vision, reasoning, max context, modalities. |
| POST | /admin/models/{id}:warm / :evict |
Pre-load / free the engine. |
| GET | /admin/engines |
Currently resident engines and maxResident. |
| GET | /admin/credentials |
List local credential names with hasValue (values are never read back). |
| PUT / DELETE | /admin/credentials/{name} |
Set / remove a local credential (values are write-only). |
| GET | /admin/catalog/models |
Browse installable models (search, sort, limit, engines, size, modality). |
| GET | /admin/catalog/models/{repo} |
Model detail with per-quant variants and RAM fit badges. |
| POST | /admin/catalog/install |
Start a download+install job. Body {repo, engine, variantId, logicalId}. |
| GET | /admin/catalog/downloads / /{job_id} |
Track download progress. |
| POST | /admin/catalog/downloads/{job_id}:cancel |
Cancel an in-flight install. |
| GET | /admin/export |
The registry as a bundle: every registration verbatim (runtime state stripped), catalog-install provenance, and credential names only — never values or weights. See Import & export. |
| POST | /admin/import |
Apply a registry bundle: already-registered ids are skipped; catalog-installed models re-download their weights in-plane (returned in downloads); a local-path model without install provenance registers with a weights_unavailable warning. Malformed body → 400 invalid_bundle. |
Register a hosted, OpenAI-compatible model:
curl -X PUT http://localhost:8081/admin/models/claude-fast \
-H 'Content-Type: application/json' \
-d '{"binding":"openai-compatible","baseUrl":"https://api.example.com/v1","model":"provider-model-name","credentialRef":"secret://MY_API_KEY"}'
See Remote models for the reachable-binding fields.
Health¶
| Method | Path | Purpose |
|---|---|---|
| GET | /healthz |
Liveness. |
| GET | /readyz |
Per-(engine, modality) readiness — each slot with a reason and install hint when not ready. Stays 200 while any engine is available. |
Related pages¶
- Environment variables — the
THEYGENT_*knobs these services read. - Troubleshooting — what the error codes mean and how to fix them.
- Glossary — terms used above (logical id, binding, run, trigger, artifact).