Call your agent from code

One HTTP API runs the web page, the terminal and your own programs. Open on your machine, behind tokens when you share it. Call it with curl, the BoxLang client or any OpenAPI tool.

On this page

Call your agent from code

Every built agent serves one HTTP API at /__bxagents. The web chat page, the terminal chat and the gateways use the same one, so anything they do, your program can do. This guide is the tour; every route, with its request and answer, is in the OpenAPI document the server hands out, and the settings are in agentApi.

The project in examples/api-agent/ runs everything below.

Open or behind a token

Two ways to run, chosen by agentApi in Agent.yaml.

SettingsWho may call
Open (the default)nothingAnyone who can reach the port. Everyone is one user, local. Keep it on 127.0.0.1; serve prints a warning when an open API listens on every interface.
TokentokenEnvVar: MY_SECRET, and/or tokens: trueCallers that send x-bxagents-token. The shared secret is an admin; issued tokens are chat or admin. Everything else gets 401.

You can also narrow who may call with allowedIPs and cap how often with rateLimit; both work open or closed.

agentApi:
  tokenEnvVar: TOKEN_FOR_ADMIN   # the NAME of an environment variable
  tokens: true                   # also accept tokens made with `bxAgents token create`
  manageTokens: true             # an admin may make and revoke tokens over the API

With curl

export T="x-bxagents-token: $TOKEN_FOR_ADMIN"

curl -H "$T" http://127.0.0.1:8080/__bxagents/whoami

curl -H "$T" -H "Content-Type: application/json" \
     -d '{"input":"What can you do?"}' \
     http://127.0.0.1:8080/__bxagents/invoke

invoke answers { "success": true, "output": "...", "threadId": "..." }. Send conversationId to carry on a conversation; the agent remembers it for you.

With BoxLang

import bxModules.bxagents.models.api.AgentApiClient;

client = new AgentApiClient( url = "http://127.0.0.1:8080", token = getSystemSetting( "TOKEN_FOR_ADMIN" ) );

first = client.invoke( "What can you do?" );
println( first.output );

// the text as it is written
client.stream( "Say it shorter.", ( text ) => print( text ), first.threadId );

Build the client with named arguments. There is one method for each route: invoke, stream, events, resume, cancel, steer, sessions, history, export, notes, preferences, command, tokens and the rest. A bad request comes back as { success: false, error, code }; a refused token, a missing route or a server failure is thrown. Pass path when the server moved the API with agentApi.path, and source to name your program in the conversation list.

Streams

stream and events answer server-sent events: each frame is event: <name> then data: <json>.

FrameMeaning
threadFirst frame: the run's id, for cancel, steer and resume.
chunkA piece of what the model is saying.
toolA tool call started (running) or finished (ok). events only.
suspendedThe run paused for approval. Answer with resume. events only.
errorThe run failed.
doneLast frame.

stream carries thread, chunk and done. events carries all of them, and the client turns them into events for your callback: thread, delta, reasoning, tool, suspended, error.

Run control

A run belongs to the caller who started it.

CallDoes
cancel( threadId )Stops it. Only its owner, or an admin.
steer( threadId, input )Adds a message to a run that is going.
pending( threadId ) and resume( threadId, decision )Approve, reject or edit what a paused run wants to do.

Conversations, notes and settings

Conversations belong to the caller too: sessions() lists them, newest first (an admin may pass all = true for everyone's), and createSession, renameSession, forkSession, deleteSession, history and export work on one. notes() and preferences() keep what the agent should remember about the caller. command( "/context" ) runs any slash command the caller may use.

Access tokens over the API

With manageTokens: true an admin can make tokens without a shell on the server:

made = client.createToken( name = "ci", scope = "chat", expires = "90d" );
println( made.token );        // shown once; the server keeps only a fingerprint
client.revokeToken( "ci" );

The same list, create and revoke are in the Tokens panel of the web page (shown to admins on a server that allows it). A chat token gets 403. Leave manageTokens off and the routes do not exist.

Errors

Every error is { "success": false, "error": "text for people", "code": "machine_code" }.

StatusCodes
400bad_request, bad_profile, bad_attachment
401unauthorized
403forbidden, csrf, not_your_run
404not_found, no_notes
405method_not_allowed
409busy (a run is already going in that conversation)
429rate_limited from a token check; the rateLimit guard (cbSecurity's Throttle) answers { "error": true, "messages": [...] } with a Retry-After header

The OpenAPI document

curl -H "$T" http://127.0.0.1:8080/__bxagents/openapi > agent-api.json

It is an OpenAPI 3 document of the routes this server really has: every route, what it takes and answers, the token header on a closed API, and the stream frames. Feed it to a client generator or an API tool such as Swagger UI or Postman. The routes, the document and the BoxLang client are all made from one list, and a test fails when they disagree.

Edit this page Download Markdown Last updated Nov 6, 2026, 4:00:25 PM Report an issue