On this page
← DocsDOCS · API REFERENCE
Integration API for external systems
A REST API reference for teams building their own agent applications on Vantisso, or embedding Vantisso control and management into an enterprise IT operations portal or ITSM system.
Last updated · 2026-07-28
API call basics
| Item | Scope | Value |
|---|---|---|
| Base URL | All requests | http://<host>:3000 (control plane) |
| Authorization | All requests | Authorization: Bearer <token> on every call(omit only for token-less local development) |
| Content-Type | Requests with a body | JSON for both request and response (application/json) |
Authentication & authorization
1 · Token-based authentication
Tokens are issued by a Vantisso operator, and you authenticate simply by sending that token in the `Authorization: Bearer` header. During local development you can turn authentication off and call the API without a token, in which case Vantisso treats you as an operator.
curl -H "Authorization: Bearer $TOKEN" http://host:3000/whoami{ "name": "acme-portal", "role": "user", "auth_disabled": false }2 · Role- and ownership-based authorization
Every API call is evaluated on two independent checks: whether your assigned role is allowed to perform the requested action, and whether you may access the target object. Both must pass for the call to succeed.
| Check | What it determines | How it applies |
|---|---|---|
| Role | Which actions you may call | Limited to what the token’s role — operator or user — permits |
| Ownership | Which objects you may access | Only the objects you created |
By design, the operator role bypasses the ownership check and can access every object.
3 · Choosing the right token for the job
| What you’re building | Token to use | Why |
|---|---|---|
| A multi-tenant agent application | a user token per customer | Ownership automatically isolates each customer’s agents from every other customer’s |
| A backend service that operates the whole platform | an operator token | It needs full access to every endpoint and object |
| Local development and testing | no token | Skip authentication entirely for convenience (the caller acts as an operator) |
4 · A caveat when spawning a single agent
Vantisso treats a standalone VM as shared infrastructure that belongs to no one. Because of that, a `user` token cannot create a standalone VM on its own — a POST /vms call made with a user token returns 403. What a user token *can* do is create an agent group first (POST /groups) and then spawn VMs inside that group, where they inherit the group’s owner. So keep this in mind: with a `user` token, even when you need just one agent, you must create a group that has a single member.
5 · Reading the auth errors
| Code | Meaning | What to do |
|---|---|---|
401 | Token missing, invalid, or expired | Check the Authorization header and whether the token has expired |
403 | Your role isn’t permitted to perform the action — or the trial has expired (trial_expired) | Use an operator token for infrastructure actions; check remaining time with GET /license |
404 | You don’t own the object, or it doesn’t exist | If you’re sure the ID exists, you’re using the wrong token — switch to the one that created the object |
6 · Multi-tenant isolation: a recipe
- Issue one `user` token per tenant. A “tenant” is whatever unit you want to isolate — a customer, a portal login, a project workspace — and Vantisso maps each tenant to a single token. You can also give a tenant a TTL through the
expiresfield. - Have each tenant create its own groups and run its agents inside them. Every agent in a group inherits the same
owner id. - From there the server enforces isolation automatically: list calls return only the caller’s own resources, and any action aimed at an agent the tenant doesn’t own is rejected with a
404.
If a tenant token is lost, deleting it and recreating one with the same name does not restore access to the previous data — so store tenant tokens securely. Note too that Vantisso’s multi-tenant isolation governs only visibility and action enforcement; it does not partition or guarantee resource quotas per tenant.
Single agent
To run a single agent without creating a group, you must spawn the VM that runs it with an `operator` token — this is mandatory, since a user token cannot create a standalone VM.
1. Spawn a VM : An optional {"profile":"…"} applies a customized sizing / model / system prompt; omit it and the default profile is applied automatically.
curl -sX POST http://host:3000/vms \
-H "Authorization: Bearer $OP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"profile":"support-agent"}'201 Created
{
"vm_id": "vm-1720982400000000000",
"guest_ip": "10.0.1.5",
"runtimed_url": "http://10.0.1.5:8080",
"profile": "support-agent",
"provider": "google",
"model": "gemini-2.0-flash",
"runtimed_token": "…"
}The call blocks until the agent is ready — typically under a second, up to 60 seconds. The runtimed_token is returned only once and is never reissued; in practice you rarely need it directly, because the control-plane proxy holds it centrally and injects it into each VM on demand. If host disk is exhausted, the spawn returns 507; if the evaluation license has expired, it returns 403 trial_expired.
2. Run a task : The control-plane token is all you need; the prompt is proxied to the agent automatically. An agent processes one task at a time and returns 503 while it is busy.
curl -sX POST http://host:3000/vms/$VM_ID/tasks \
-H "Authorization: Bearer $OP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"prompt":"Summarize ticket INC-4821 and propose a resolution."}'{ "output": "…the agent's final answer…", "error": "" }- Multi-turn : pass
"session":"<your-id>"to continue one conversation thread across calls. Session state lives in the memory of the agent runtime inside the VM, in a namespace fully isolated per VM. Unlike tokens, the session id is not managed by the control plane — it is passed straight through. - Streaming : add
?stream=1to receive the response as NDJSON (see Streaming, below).
3. Tear down : The VM, its network, and its disk are all released automatically.
curl -sX DELETE http://host:3000/vms/$VM_ID -H "Authorization: Bearer $OP_TOKEN"The private IP in runtimed_url is host-only and cannot be reached from your application network. Always drive agents through the control plane (/vms/{id}/…).
Single-agent endpoints
| Method & path | Description |
|---|---|
POST/vms | Spawn a VM. Operator only. Optional body {"profile":"…"}. |
GET/vms | List running VMs. An operator sees every VM; a user sees only the ones it owns. |
DELETE/vms/{id} | Graceful teardown of a VM. |
POST/vms/{id}/tasks | Run an agent task. Add ?stream=1 to enable streaming. In the body, prompt carries the prompt and session enables a multi-turn conversation. |
GET/vms/{id}/health | Health-check an agent; the response reports whether it is idle or busy. |
GET/vms/{id}/stats | A snapshot of CPU usage, total and in-use memory, network in/out, uptime, and agent idle/busy state. |
GET/vms/{id}/sessions | List the multi-turn chat sessions on this VM. |
GET/vms/{id}/sessions/{name}/transcript | Retrieve every turn of a given session — useful for reconstructing the conversation when resuming. |
Agent team
Vantisso lets you operate agents as a team: you create an agent group, and the agents spawned under it collaborate as one team.
1. Create the team : You can create a group with either a `user`-class or an `operator`-class token. With a user token, an Owner id is assigned and propagated to every agent in the group, making the group’s ownership explicit; a group created with an operator token, by contrast, isn’t bound to any tenant and is treated as shared infrastructure. Each role listed in the body’s `roles` field becomes one agent VM instance, and the vCPU count and memory each VM receives are drawn from the resource profile predefined for that role.
curl -sX POST http://host:3000/groups \
-H "Authorization: Bearer $TENANT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"task": "Draft the release notes for v1.4",
"roles": ["orchestrator","writer","reviewer"],
"max_agents": 5
}'201 Created
{
"group_id": "group-1720982500000000000",
"task": "Draft the release notes for v1.4",
"agents": [
{ "agent_id": "orchestrator-1", "role": "orchestrator", "profile": "orchestrator",
"vm_id": "vm-…", "runtimed_url": "http://10.0.1.6:8080", "status": "ready" },
{ "agent_id": "writer-1", "role": "writer", "profile": "writer",
"vm_id": "vm-…", "runtimed_url": "http://10.0.1.7:8080", "status": "ready" },
{ "agent_id": "reviewer-1", "role": "reviewer", "profile": "reviewer",
"vm_id": "vm-…", "runtimed_url": "http://10.0.1.8:8080", "status": "ready" }
],
"runtimed_tokens": { "orchestrator-1": "…", "writer-1": "…", "reviewer-1": "…" },
"feed_url": "/groups/group-…/feed",
"post_url": "/groups/group-…/post"
}As the example response above shows, each agent’s id is the role name plus an index number (writer-1, writer-2, …). The runtimed_tokens are the credentials used to talk to the agents directly, and they are returned in the response only once, at creation.
2. Run tasks : To send a prompt to a single member of the group, address it by that agent’s vm_id (POST /vms/{id}/tasks). To fan a prompt out to every member at once, use the broadcast endpoint, as shown below.
curl -sX POST http://host:3000/groups/$GID/broadcast \
-H "Authorization: Bearer $TENANT_TOKEN" \
-H "Content-Type: application/json" -d '{"body":"Status check: where are we?"}'3. Tear down the team : Deleting an agent group also tears down every agent VM that belongs to it.
curl -sX DELETE http://host:3000/groups/$GID -H "Authorization: Bearer $TENANT_TOKEN"Agent team endpoints
| Method & path | Description |
|---|---|
POST/groups | Create a team: one VM is spawned per role in roles, each agent is given an id combining its role name and index, and the agents start. If any agent fails to launch, the entire creation is rolled back. |
GET/groups | List teams, filtered by ownership. |
GET/groups/{id} | Detail for one team: its agents’ roles, profiles, and status, whether the group is paused, and its creation time. |
DELETE/groups/{id} | Tear down a team: every member VM is destroyed, the group metadata is deleted, and the handoff artifact store is removed. |
POST/groups/{id}/broadcast | Fan a prompt out to every agent in the group. Each agent returns ok, busy, or error; agents that are busy running a task are skipped. The call blocks until the fan-out completes. |
POST/groups/{id}/pause · /resume | Pause or resume every agent in the group. If a pause partially fails, agents already paused are resumed as a rollback. |
POST/groups/{id}/post | Post a message to the group’s shared feed, attributed to the agent as its author. |
GET/groups/{id}/feed | Open a live SSE stream to receive updates to the shared feed in real time. |
GET/groups/{id}/feed/history | Read the feed’s stored history, with filter/search support. |
GET/groups/{id}/handoff | List the keys that identify handoff artifacts. |
PUTGETDELETE/groups/{id}/handoff/{key} | Store (body = arbitrary JSON), read, or delete the handoff artifact at the given key. |
POST/groups/{id}/agents | Add an agent to the group; set its role and an optional profile. Exceeding the group’s configured maximum agent count returns 400. |
DELETE/groups/{id}/agents/{agent_id} | Remove an agent. |
PATCH/groups/{id}/agents/{agent_id} | Change an existing agent’s role on the fly. |
POST/groups/{id}/agents/{agent_id}/restart | Restart an agent on a new VM while keeping the same agent id. |
Handoff caveat
Each write to a handoff artifact is atomic, and concurrent writes to the same key are serialized so that only one agent writes at a time. Reads of the same artifact, however, are parallelized for throughput. As a result, if two or more independent calls each read an artifact and then update it based on what they read, the parallel reads can cause the final stored content to differ from what you intended (a lost update). To prevent this at the root, designate a single writer agent per handoff artifact.
Transcripts
A live chat session lives only in the RAM assigned to its VM, so it disappears the moment that VM shuts down. Vantisso persists each agent’s chat session to the host as a snapshot at teardown, so the conversation survives events such as a VM restart. Vantisso calls this the transcript feature.
| Method & path | Description |
|---|---|
GET/transcripts | List stored transcripts. Search by vm_id, group_id, or both; results are sorted newest-first and return metadata only, without the turn contents. |
GET/transcripts/{session} | Retrieve the metadata and full turn contents of the single session identified by session. |
DELETE/transcripts/{session} | Delete the transcript for the given session (only if you own it). |
An example transcript record:
{
"schema_version": 1,
"session": "INC-4821",
"vm_id": "vm-…",
"group_id": "group-…",
"agent_id": "writer-1",
"owner": "acme-portal",
"profile": "support-agent",
"title": "Summarize ticket INC-4821",
"turns": [
{ "role": "user", "text": "Summarize ticket INC-4821…" },
{ "role": "assistant", "text": "…" }
],
"saved_at": "2026-07-15T09:12:00Z"
}Reference data
These read-only endpoints provide the core information you need when building a custom UI for composing and managing agent teams on Vantisso.
| Method & path | Description |
|---|---|
GET/config/profiles · /config/profiles/{name} | List the profile templates that define a group’s agents, and read each template’s detail: sizing, model, system prompt, built-in tools, and MCP bindings. |
GETPUT/config/profiles/{name}/stream | Read or toggle live token streaming for a profile. A profile is a global template with no ownership, so both operator and user tokens may call it. |
GET/config/providers · /presets · /builtins | Catalogs of, respectively, LLM providers, VM sizing tiers, and built-in tools. |
Streaming
Rather than returning the whole result in a single buffered object, POST /vms/{id}/tasks?stream=1 streams the response as newline-delimited JSON (NDJSON) — one frame per line. As the example below shows, frames come in three types.
{ "type": "progress", "text": "running shell: grep -n …" }
{ "type": "token", "text": "The " }
{ "type": "token", "text": "root cause " }
{ "type": "result", "output": "…final answer…", "error": "" }type: "progress"— emitted at each defined step as the agent loop runs and calls tools. A frame may arrive with an emptytextfield, acting as a heartbeat; retry hints, such as backing off under an LLM’s rate limits, are also delivered as progress frames.type: "token"— an incremental piece of the output text, sent only when the profile’s live token streaming (described earlier) is enabled; concatenate these in order to reconstruct the model’s full response.type: "result"— delivered exactly once, as the final frame of the stream; reading just this frame reproduces the buffered object. An emptyerrorfield means success, a non-empty one means failure.
Because an HTTP response sends its status line and headers before the body, streaming NDJSON means the status must be committed to 200 OK before the first frame goes out. Once the stream has started there is no way to take that 200 OK back — so if the task fails partway through, the already-sent 200 OK cannot be turned into a 500. Success or failure therefore has to be carried in the result frame’s error field: you cannot judge a task’s outcome from the HTTP status alone, but only after reading the full response. When building a custom agent UI, set a generous client read timeout to allow for long-running tasks, which can take several minutes.
Status codes
- Error message format : every error is returned as a JSON object of the form
{"error":"…"}.
| Code | Meaning |
|---|---|
400 | Input error — a missing or empty required field, invalid JSON, a failed validation, or an out-of-range value. |
401 | Missing or mismatched Bearer token. |
403 | An authorization violation — e.g. a user token calling an operator-only action — or an expired license. |
404 | The resource doesn’t exist, or you don’t own it — returned instead of 403 to hide whether the resource exists. |
405 | HTTP method not allowed on this path. |
409 | A state conflict or precondition failure — e.g. deleting a profile still in use, deleting the last remaining operator, or deleting the source snapshot of a running VM. |
413 | Payload too large — a handoff artifact over 1 MiB, or a system.md file over 64 KiB. |
500 | An unexpected server error. |
502 | Failed to reach the in-VM agent runtime (runtimed). |
503 | Agent busy — it is already running a task (one at a time per VM). |
507 | Insufficient host storage to spawn a VM. |
508 | Nested-task depth exceeded — a guard against runaway agent-to-agent task hops. |
Trial license (403 detail)
Once the trial period has passed and the license expires, spawning an agent VM or team (POST /vms, POST /groups) returns 403 {"error":"trial_expired"}. Only new creation is affected — reading existing agents and groups, running tasks, and tearing down VMs all keep working after expiry. You can check the time remaining before expiry with the GET /license call, as shown below.
GET /license
→ {
"type": "evaluation", // or "commercial"
"status": "active", // "active" | "grace" | "expired"
"started_at": "2026-07-01T00:00:00Z",
"expires_at": "2026-07-31T00:00:00Z",
"days_left": 21,
"enforced": true
}