Calling the agent
Agent-initiated calling uses MCP. To start a call from the iPhone while an agent is idle, Suzo needs a receiver that can resume that same agent session. This is optional and harness dependent.
Wake, then join
The phone first reserves an outgoing call. Suzo sends an authenticated webhook to a receiver bound to the original session. That session then uses MCP call_user with the same request UUID to join the existing call, without a second ring. A receiver’s queued acknowledgment does not mean the call is connected.
call_userBind a supported receiver
Use documented extension points or a thin protocol adapter. Bind one Suzo agent ID to one explicit session, profile, or workspace. Preserve the runtime’s permissions and approvals.
The receiver needs a separate high-entropy bearer secret of at least 32 random bytes. Its endpoint is reached by the Suzo server, not the phone. Use HTTPS, or HTTP loopback when both services share a host. Private network endpoints work only if the server can reach them.
Do not expose an unauthenticated runtime control API. Never let a webhook payload choose an arbitrary shell command or session.
Implement protocol version 3
Suzo POSTs a versioned envelope with bearer authentication:
{
"version": 3,
"type": "suzo.hook.check",
"request_id": "<request-UUID>",
"agent_id": "<bound-Suzo-agent-UUID>",
"requested_at": "<ISO-8601-timestamp>"
}
Validate the secret, version, type, UUIDs, and bound agent. Return HTTP 200 or 202 with the exact request UUID:
{"version":3,"accepted":true,"request_id":"<same-request-UUID>"}
A suzo.hook.check probe must not wake a session, call the phone, start an LLM turn, or send a message. A generic HTTP 200 is not sufficient.
For suzo.call.request, durably queue once per request ID, acknowledge promptly, then wake the fixed session. Deduplicate across restarts and serialize work while it is busy. The resumed agent calls call_user with the exact received request ID and runs the normal call loop.
Accepted means queued, not connected. Verify runtime admission and report wake failures through the request-status endpoints in the complete receiver contract.
Register and check
Read GET /v1/agent/calling first and preserve a working receiver. Use the agent credential to register:
PUT /v1/agent/calling
Authorization: Bearer <scoped-agent-token>
Content-Type: application/json
{
"url":"https://<your-runtime>/suzo/call-request",
"token":"<separate-receiver-secret>",
"protocolVersion":3
}
Then POST /v1/agent/calling/check. Status readback is redacted; the secret is never returned. Replacing the URL requires the corresponding secret again. Existing version-1 Prism and version-2 Suzu receivers keep their configured wire values and acknowledgments; version 2 continues using suzu.hook.check and suzu.call.request. Do not silently upgrade a working receiver, re-pair a contact, or replace its credentials. New setup explicitly registers protocolVersion: 3.
Check the session, not just the endpoint
A stock Hermes webhook may create a separate session. A separate Codex App Server process does not automatically control an existing desktop chat. Inspect the installed runtime and confirm the adapter targets the owning session.
If the harness cannot safely wake that session, leave this feature unconfigured. The agent can still initiate a call. Never install a dummy receiver or describe a successful probe as an answered call.