The product API is one socket: ws://localhost:8000/ws (override with NEXT_PUBLIC_PORTO_WS_URL). Every client frame is JSON with a type. The server replies with JSON (type plus payload). Include trace_id if you want it echoed on errors.
v1 is single-user. The socket is not a public multi-tenant API. Treat it as a local control plane for your own stack.

Connect

On drop, reconnect and send resume_from with the last seq you saw. The server replays the missed tail or answers reset.

Minimum loop to talk

1

Open a project

After you create one in the UI (or already have an id):
2

Connect a provider (cloud / local)

Success: { "type": "credential_set", "provider": "ollama", "auth_type": "api_key" }.provider values: claude, openai, gemini, deepseek, xai, openrouter, ollama, local, mistral, mistral_vibe. CLI harnesses (claude_code, codex, grok) do not take a key here.For local, you may also send nickname and instance_id (omit instance_id to add a new row).
3

List live models (optional)

Reply: { "type": "provider_models", "provider": "ollama", "models": [ … ] }.
4

Add an agent

Success: { "type": "agent_added", "agent_id": "…", "handle": "ollama", "room_id": "…" }.
5

Chat

The broker streams turn deltas, then a completion event. Cancel with cancel_chat. Emergency halt: emergency_stop.

Credential messages

Agent messages

Useful add_agent fields (all optional except room_id + provider):
string
Display name. Empty → provider label.
string
Pin. Omit for the provider default.
string
Role string. Shapes default grants and charter.
string
Local / network host already saved in Settings.
string
Which Local / network row to use.
string[]
["file_ops","web"], ["*"], or [].

Errors

Handler failures return:
Unknown type is a structured error, not a socket close. The connection stays open.

What this is not

There is no public REST CRUD for agents. The Next app is the supported client. Use this page when you are scripting a local smoke test or debugging with a raw socket.