HTTP API
The backend speaks two versions of its API. v2 streams the agent's work and is what the Allay plugin uses. v1 returns one JSON answer and stays for the archived Telegram bot and plugins before 2.0. The full contract is docs/protocol-v2.md; a Postman collection sits in postman.json.
#Who asks and who pays: the headers
Since 6.0 every request but health, a new license, and Telegram's webhook carries Authorization: Bearer …: the server's license on a hosted backend, PLUGIN_TOKEN on a self-hosted one. Without it the answer is 401. A server with its own key adds X-Provider-Key: <key> and a provider block in the body. See Security and privacy and Who pays for the model.
Everything about a player is filed under the calling server's tenant: a request reaches only its own server's players, whatever user_id it names.
#v1: one JSON answer
POST /api/ask answers a question; POST /api/askx turns a request into commands. They run the same agent without game tools.
curl -X POST https://allay.chat/api/ask \
-H "Authorization: Bearer $LICENSE" -H "Content-Type: application/json" \
-d '{"question": "How do I craft a diamond pickaxe?", "platform": "telegram", "user_id": "42"}'
{"answer": "...", "status": "success", "timestamp": "...", "platform": "telegram", "user_id": "42"}
#v2: a stream of events
The plugin opens one POST /api/v2/chat per question:
curl -N -X POST https://allay.chat/api/v2/chat \
-H "Authorization: Bearer $LICENSE" -H "Content-Type: application/json" -H "Accept: text/event-stream" \
-d '{"mode": "ask", "message": "what should I do next?", "user_id": "5627dd98-...", "player": {"name": "Steve"}, "tools": ["get_inventory"]}'
The server answers with Server-Sent Events while the agent works:
startnames the run and the model.reasoningcarries pieces of the model's reasoning, when the model exposes it.tool_callasks the plugin to run a game tool, such as the inventory. The plugin posts the result toPOST /api/v2/chat/{run_id}/tools/{call_id}, with the sameAuthorization; another server's result gets404.tool_statustells what the agent does right now: reading the inventory, searching the web.textstreams the answer as it's written, thenusageanddoneclose the run.
For /askx, a commands event with the command list replaces the text. An error event ends a failed run.
mode is ask, askx, or task (a wake of an automation agent). visibility: "public" marks a question everyone online sees.
#Other endpoints
| Request | What it does |
|---|---|
GET /api/health |
The name, status, version, and whether billing is on; open to anyone |
GET /api/v2/users/{user_id} |
Everything kept about the player: their name, memories, consent, session, agents' threads, runs |
PUT /api/v2/server |
The plugin registers its server at start: name, MOTD, address, versions. A name another tenant's server holds answers 409 NAME_TAKEN |
PUT /api/v2/users/{user_id}/privacy |
Full privacy on or off ({ "full": true }): on, the admin panel forgets the player's name, UUID, and face |
DELETE /api/v2/users/{user_id} |
Erases the player: their name, memories, consent, session, threads, and traces go; runs keep only numbers |
GET, PUT, DELETE /api/v2/users/{user_id}/consent |
Reads, records ({ "version": 1 }), or withdraws the player's agreement to the plugin's notice. Since 6.1 |
DELETE /api/v2/users/{user_id}/session |
Clears the player's session; memories stay |
GET, POST, DELETE /api/v2/users/{user_id}/memories |
Lists, adds, or deletes all of the player's memories |
DELETE /api/v2/users/{user_id}/memories/{id} |
Deletes one memory |
GET, POST /api/v2/license |
A license and its status; POST without a license makes one, free and open to anyone |
POST /api/v2/admin/init |
A one-time setup or recovery link for the admin panel; wants PLUGIN_TOKEN |
POST /api/telegram/webhook |
The payment bot's updates |
/api/admin/* |
The admin panel's own API |
#Errors
Before a stream starts, errors come as { "error": { "code", "message" } } with an HTTP status. After it starts, they come as an error event. The codes are listed in Troubleshooting and in the protocol.
Next: Architecture