Skip to content

Voice

create_voice_agent(*, api, settings, payload)

Create a voice agent. REQUIRED: name, config; project_id is filled in automatically.

config REQUIRES instructions and a mode, and the mode decides which stages it carries:

pipeline (default) -> stt, llm and tts, all three, and NO realtime realtime -> realtime alone, and none of stt/llm/tts

Each stage is {"provider", "model", "connection_id", ...}; connection_id is a Nexus connection UUID and the agent cannot run without it. Optional: welcome_message, tools, mcp_servers, transfer, end_call_enabled, recording_enabled, advanced.

Creating does not deploy. Nothing can call the agent until voice deploy.

Source code in dynamiq/cli/commands/voice.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@voice.command("create")
@click.argument("payload")
@with_api_and_settings
def create_voice_agent(*, api: ApiClient, settings: Settings, payload: str):
    """Create a voice agent. REQUIRED: `name`, `config`; `project_id` is filled in automatically.

    `config` REQUIRES `instructions` and a `mode`, and the mode decides which stages it carries:

      pipeline (default) -> `stt`, `llm` and `tts`, all three, and NO `realtime`
      realtime           -> `realtime` alone, and none of stt/llm/tts

    Each stage is {"provider", "model", "connection_id", ...}; `connection_id` is a Nexus
    connection UUID and the agent cannot run without it. Optional: `welcome_message`, `tools`,
    `mcp_servers`, `transfer`, `end_call_enabled`, `recording_enabled`, `advanced`.

    Creating does not deploy. Nothing can call the agent until `voice deploy`.
    """
    body = read_json_arg(payload)
    body.setdefault("project_id", require_project(settings))
    echo_response(api.post(f"{BASE}/agents", json=body))

delete_voice_agent(*, api, settings, agent_id)

Delete the agent permanently.

Source code in dynamiq/cli/commands/voice.py
172
173
174
175
176
177
178
@voice.command("delete")
@click.argument("agent_id")
@click.confirmation_option(prompt="Delete this voice agent?")
@with_api_and_settings
def delete_voice_agent(*, api: ApiClient, settings: Settings, agent_id: str):
    """Delete the agent permanently."""
    echo_response(api.delete(f"{BASE}/agents/{agent_id}"))

deploy_voice_agent(*, api, settings, agent_id)

Deploy the agent so it can take calls.

Returns before it is live. Poll voice get <id> until status settles; a failure lands in deploy_error on the agent, which is the first thing to read when a deploy does not take.

Source code in dynamiq/cli/commands/voice.py
74
75
76
77
78
79
80
81
82
83
@voice.command("deploy")
@click.argument("agent_id")
@with_api_and_settings
def deploy_voice_agent(*, api: ApiClient, settings: Settings, agent_id: str):
    """Deploy the agent so it can take calls.

    Returns before it is live. Poll `voice get <id>` until `status` settles; a failure lands in
    `deploy_error` on the agent, which is the first thing to read when a deploy does not take.
    """
    echo_response(api.post(f"{BASE}/agents/{agent_id}/deploy"))

duplicate_voice_agent(*, api, settings, agent_id)

Copy an agent, config and all - the safe way to try a change on a live one.

Source code in dynamiq/cli/commands/voice.py
164
165
166
167
168
169
@voice.command("duplicate")
@click.argument("agent_id")
@with_api_and_settings
def duplicate_voice_agent(*, api: ApiClient, settings: Settings, agent_id: str):
    """Copy an agent, config and all - the safe way to try a change on a live one."""
    echo_response(api.post(f"{BASE}/agents/{agent_id}/duplicate"))

get_call(*, api, settings, agent_id, call_id)

One call, including its transcript.

Source code in dynamiq/cli/commands/voice.py
111
112
113
114
115
116
117
@voice.command("call")
@click.argument("agent_id")
@click.argument("call_id")
@with_api_and_settings
def get_call(*, api: ApiClient, settings: Settings, agent_id: str, call_id: str):
    """One call, including its transcript."""
    echo_response(api.get(f"{BASE}/agents/{agent_id}/calls/{call_id}"))

get_recording(*, api, settings, agent_id, call_id)

A short-lived URL for the call recording.

Treat it like a connect link: give it to the user, do not open it yourself.

Source code in dynamiq/cli/commands/voice.py
120
121
122
123
124
125
126
127
128
129
@voice.command("recording")
@click.argument("agent_id")
@click.argument("call_id")
@with_api_and_settings
def get_recording(*, api: ApiClient, settings: Settings, agent_id: str, call_id: str):
    """A short-lived URL for the call recording.

    Treat it like a connect link: give it to the user, do not open it yourself.
    """
    echo_response(api.get(f"{BASE}/agents/{agent_id}/calls/{call_id}/recording-url"))

get_telephony(*, api, settings, agent_id)

Phone numbers and SIP trunks attached to this agent.

Source code in dynamiq/cli/commands/voice.py
132
133
134
135
136
137
@voice.command("telephony")
@click.argument("agent_id")
@with_api_and_settings
def get_telephony(*, api: ApiClient, settings: Settings, agent_id: str):
    """Phone numbers and SIP trunks attached to this agent."""
    echo_response(api.get(f"{BASE}/agents/{agent_id}/telephony"))

get_voice_agent(*, api, settings, agent_id)

Fetch one voice agent - status, deploy_error and phone_numbers live here.

Source code in dynamiq/cli/commands/voice.py
57
58
59
60
61
62
@voice.command("get")
@click.argument("agent_id")
@with_api_and_settings
def get_voice_agent(*, api: ApiClient, settings: Settings, agent_id: str):
    """Fetch one voice agent - `status`, `deploy_error` and `phone_numbers` live here."""
    echo_response(api.get(f"{BASE}/agents/{agent_id}"))

list_calls(*, api, settings, agent_id, page, page_size, fetch_all, compact)

Calls this agent has handled - the proof it is actually working.

Source code in dynamiq/cli/commands/voice.py
102
103
104
105
106
107
108
@voice.command("calls")
@click.argument("agent_id")
@pagination_options
@with_api_and_settings
def list_calls(*, api: ApiClient, settings: Settings, agent_id: str, page, page_size, fetch_all, compact):
    """Calls this agent has handled - the proof it is actually working."""
    echo_list(api, f"{BASE}/agents/{agent_id}/calls", None, page, page_size, fetch_all, compact)

list_simulations(*, api, settings, agent_id, page, page_size, fetch_all, compact)

Simulation runs and their results.

Source code in dynamiq/cli/commands/voice.py
155
156
157
158
159
160
161
@voice.command("simulations")
@click.argument("agent_id")
@pagination_options
@with_api_and_settings
def list_simulations(*, api: ApiClient, settings: Settings, agent_id: str, page, page_size, fetch_all, compact):
    """Simulation runs and their results."""
    echo_list(api, f"{BASE}/agents/{agent_id}/simulations", None, page, page_size, fetch_all, compact)

list_voice_agents(*, api, settings, page, page_size, fetch_all, compact)

List voice agents in the current project.

Source code in dynamiq/cli/commands/voice.py
27
28
29
30
31
32
@voice.command("list")
@pagination_options
@with_api_and_settings
def list_voice_agents(*, api: ApiClient, settings: Settings, page, page_size, fetch_all, compact):
    """List voice agents in the current project."""
    echo_list(api, f"{BASE}/agents", {"project_id": require_project(settings)}, page, page_size, fetch_all, compact)

simulate(*, api, settings, agent_id, payload)

Run a simulated call against the agent - a test that needs no phone.

Use this as the "does it work" gate before telling anyone the agent is ready.

Source code in dynamiq/cli/commands/voice.py
140
141
142
143
144
145
146
147
148
149
150
151
152
@voice.command("simulate")
@click.argument("agent_id")
@click.argument("payload")
@with_api_and_settings
def simulate(*, api: ApiClient, settings: Settings, agent_id: str, payload: str):
    """Run a simulated call against the agent - a test that needs no phone.

    Use this as the "does it work" gate before telling anyone the agent is ready.
    """
    # Each attempt creates a simulation. A retry after a timed-out response leaves a second
    # record behind, and there is no idempotency key to tell them apart.
    echo_response(api.post(f"{BASE}/agents/{agent_id}/simulations", json=read_json_arg(payload),
                           timeout=EXECUTION_TIMEOUT))

undeploy_voice_agent(*, api, settings, agent_id)

Take the agent offline. Calls to it stop being answered.

Source code in dynamiq/cli/commands/voice.py
86
87
88
89
90
91
@voice.command("undeploy")
@click.argument("agent_id")
@with_api_and_settings
def undeploy_voice_agent(*, api: ApiClient, settings: Settings, agent_id: str):
    """Take the agent offline. Calls to it stop being answered."""
    echo_response(api.post(f"{BASE}/agents/{agent_id}/undeploy"))

update_voice_agent(*, api, settings, agent_id, payload)

Update name, description or config. A deployed agent needs redeploying to pick it up.

Source code in dynamiq/cli/commands/voice.py
65
66
67
68
69
70
71
@voice.command("update")
@click.argument("agent_id")
@click.argument("payload")
@with_api_and_settings
def update_voice_agent(*, api: ApiClient, settings: Settings, agent_id: str, payload: str):
    """Update name, description or config. A deployed agent needs redeploying to pick it up."""
    echo_response(api.put(f"{BASE}/agents/{agent_id}", json=read_json_arg(payload)))

voice_catalog(*, api, settings)

Providers, models and voices this platform can serve.

Run this BEFORE writing a config: every provider/model/voice in a voice agent comes from here, and a name that is merely plausible fails at deploy time rather than at create.

Source code in dynamiq/cli/commands/voice.py
16
17
18
19
20
21
22
23
24
@voice.command("catalog")
@with_api_and_settings
def voice_catalog(*, api: ApiClient, settings: Settings):
    """Providers, models and voices this platform can serve.

    Run this BEFORE writing a config: every `provider`/`model`/`voice` in a voice agent comes
    from here, and a name that is merely plausible fails at deploy time rather than at create.
    """
    echo_response(api.get(f"{BASE}/catalog"))

voice_deployments(*, api, settings, agent_id)

Deployment history for a voice agent.

Source code in dynamiq/cli/commands/voice.py
94
95
96
97
98
99
@voice.command("deployments")
@click.argument("agent_id")
@with_api_and_settings
def voice_deployments(*, api: ApiClient, settings: Settings, agent_id: str):
    """Deployment history for a voice agent."""
    echo_response(api.get(f"{BASE}/agents/{agent_id}/deployments"))