The management API
There is no bearer-key HTTP API for managing agents, keys or usage. A secret
key (sk_…) starts calls; it does not create agents, mint keys or read your
account. The programmatic management surface is the MCP
server, and the interactive one is the console.
That is worth saying plainly, because it is the opposite of what most products do, and because you can waste an afternoon looking for the endpoint that would have done it.
The one route your own code calls
Section titled “The one route your own code calls”Exactly one route accepts a key rather than a console session, and it does one thing: start a call.
POST https://app.voqalize.com/api/v1/sessions.connectAuthorization: Bearer sk_…Content-Type: application/jsonIt answers with the pipecat transport’s argument and nothing else —
webrtc_request_params and session_id. Relay that body to the browser
verbatim: it is what startBotAndConnect takes, so there is no field to pick
out and no object to rebuild.
There was once a create_meeting then start_meeting pair. It is gone: nothing
ever created a connection and then declined to use it, and the gap between the
two steps was a state nobody guarded. Start one call. There is no second
step.
The route was called sessions.create until 2026-08-26. That name is gone,
not aliased: it answers 404. If you find it in an older example, change the
word — the body and the credential are unchanged, and the response is the
connect params rather than the whole session record every caller had to dig
through for the three fields it wanted. If you want the record too, read it back
with get_session — over MCP or in the console,
where reads belong.
The body
Section titled “The body”One required field, and four optional ones. It is strict: an undeclared
top-level key is a 422 naming it, rather than a session that quietly runs on
defaults.
| Field | ||
|---|---|---|
agent_id | required | Which agent answers. The key is scoped to it. |
init | optional | The opaque blob your brain reads as session.init. Same word at every hop. Send identifiers, not personal data — it is stored on the session record. |
config | optional | This call’s tts, stt and idle, plus record. Parsed as canonical proto3 JSON, so a bad field or an unservable language is a 400 naming it — see error codes. |
display_name | optional | A label for your own console and lists. |
metadata | optional | Your own flat string map for correlating a call with your systems. At most 10 keys, each value at most 256 characters. |
Which key signs the request, how a publishable key differs, and what the browser does with the response are all on connect a browser — that page owns the handshake and this one does not repeat it.
Everything else is MCP
Section titled “Everything else is MCP”Creating an agent, pointing its brain_url at your route, minting and revoking
keys, listing sessions, reading logs and usage — every one of those is an MCP
tool, authenticated over OAuth, rate limited at 300 requests per minute per
workspace. The MCP server is the reference for all of them.
This is not a workaround. The audience for a management API is a developer and the developer’s coding agent, and MCP is the surface an agent already holds: the tools describe themselves, the auth is interactive and revocable, and there is no long-lived credential sitting in an environment variable to leak.
Why not a REST management API
Section titled “Why not a REST management API”The obvious design is a tenant-scoped bearer key. We had one, called ak_, and
removed it on 2026-08-12.
Every key now names an agent, of every kind. ak_ did not, which meant a
credential could start a session for any agent in the tenant — so a key
baked into one public demo page could spend on every other agent that tenant
owned. Nothing was narrowing it. A credential that names no resource is one
whose blast radius can only be discovered by reading code.
Reintroducing a bearer key for management reintroduces exactly that: the operations a management API is for — create an agent, mint a key — cannot be authorized by a credential issued by one agent, so such a key has to be tenant-wide by construction. It would be the same key, with the same reach, back under a different name.
The OpenAPI document is generated by the service and served in development only, for the same reason: publishing a schema for routes whose only credential is a console cookie describes a surface nobody can call.
If you need it, say so
Section titled “If you need it, say so”This is a decision about defaults, not a refusal. If your integration genuinely cannot hold an OAuth client — a CI job that provisions agents, a product creating tenants on behalf of its own customers, a stack where MCP is not available — HTTP access can be enabled for your account. Ask us, and tell us which operations you need; the narrower the answer, the faster it is.
What we will not do is hand every account a tenant-wide key by default and call it convenience.
Read next
Section titled “Read next”- The MCP server — the management surface, tool by tool.
- Connect a browser — the handshake, and which key to hold.
- Keys —
sk_andpk_, and how rotation works. - Usage and limits — the counters behind the calls.