From b02c282e721f533f2ee93f0312d69994db13450f Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Aug 2026 05:19:17 +0900 Subject: [PATCH] =?UTF-8?q?docs(agents):=20outbound=20calls=20=E2=80=94=20?= =?UTF-8?q?guide,=20API=20reference,=20and=20public=20spec=20(FA-227)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Outbound calls (POST /v1/agent/phone-calls) shipped in platform-api #1355 but were never documented. Adds: - agents/telephony/outbound-calls.mdx: placing calls, request fields, Idempotency-Key retry semantics, dial outcome via webhook or polling, allowed destinations (US/CA/JP, JP trunk-zero normalization, BYO exemption), workspace limits, and the machine-readable reason errors. - api-reference/endpoint/agent/create-phone-call.mdx plus the endpoint in openapi.json (refreshed from prod, with /v1/agent/phone-calls merged from platform-api #1433 pending its deploy; the next spec sync converges). - Cross-links from webhooks, BYO SIP, and the errors reference. Co-Authored-By: Claude Fable 5 --- agents/monitor/webhooks.mdx | 2 +- agents/telephony/byo-sip.mdx | 2 +- agents/telephony/outbound-calls.mdx | 170 +++ api-reference/agent-errors.mdx | 1 + .../endpoint/agent/create-phone-call.mdx | 7 + api-reference/openapi.json | 1089 ++++++++++++++--- docs.json | 8 + 7 files changed, 1116 insertions(+), 163 deletions(-) create mode 100644 agents/telephony/outbound-calls.mdx create mode 100644 api-reference/endpoint/agent/create-phone-call.mdx diff --git a/agents/monitor/webhooks.mdx b/agents/monitor/webhooks.mdx index 3647c48..5be58a1 100644 --- a/agents/monitor/webhooks.mdx +++ b/agents/monitor/webhooks.mdx @@ -4,7 +4,7 @@ description: "Get an HTTP POST when a call ends and when its analysis settles, w icon: "bell" --- -Point your agent at one or more endpoints on your server and Fish Audio calls them when things happen: `call.ended` the moment a session reaches a terminal state, `call.analyzed` when [post-call analysis](/agents/monitor/post-call-analysis) settles, and, on outbound phone calls, `phone_call.dial_finished` as soon as the dial attempt resolves. Use them to write results into your CRM, ticketing system, or data warehouse without polling the sessions API. +Point your agent at one or more endpoints on your server and Fish Audio calls them when things happen: `call.ended` the moment a session reaches a terminal state, `call.analyzed` when [post-call analysis](/agents/monitor/post-call-analysis) settles, and, on [outbound phone calls](/agents/telephony/outbound-calls), `phone_call.dial_finished` as soon as the dial attempt resolves. Use them to write results into your CRM, ticketing system, or data warehouse without polling the sessions API. ## Events diff --git a/agents/telephony/byo-sip.mdx b/agents/telephony/byo-sip.mdx index 9024ae8..4457c6d 100644 --- a/agents/telephony/byo-sip.mdx +++ b/agents/telephony/byo-sip.mdx @@ -139,7 +139,7 @@ What an imported number can do depends on whether you configured a termination: | **Warm transfers** | No | Yes; the consult leg dials through your trunk | | **Outbound calls** | No | Yes; caller ID is the imported number | -The number object reports this as `supports_outbound`. +The number object reports this as `supports_outbound`. Place calls with the same API as purchased numbers; see [Outbound calls](/agents/telephony/outbound-calls). ## Update the configuration diff --git a/agents/telephony/outbound-calls.mdx b/agents/telephony/outbound-calls.mdx new file mode 100644 index 0000000..394edbb --- /dev/null +++ b/agents/telephony/outbound-calls.mdx @@ -0,0 +1,170 @@ +--- +title: "Outbound Calls" +description: "Place calls from your phone numbers over the API; the agent speaks when the callee answers" +icon: "phone-arrow-up-right" +--- + +Dial any allowed number from one of your workspace numbers and the agent takes the call the moment the callee picks up. Outbound calls are ordinary agent sessions with `direction: "outbound"`: they appear in session history, they are [stored](/agents/monitor/conversation-history#what-gets-stored) and analyzed under the same per-agent settings as any other conversation, and they trigger the same webhooks plus one extra, [`phone_call.dial_finished`](/agents/monitor/webhooks), that reports how the dial attempt ended. + + + + Get a number that can place calls. + + + Get the dial outcome pushed to your backend. + + + Personalize the call with per-call values. + + + +## Place a call + + + + Any [purchased number](/agents/telephony/phone-numbers) can place calls. An [imported BYO number](/agents/telephony/byo-sip) can too, once its termination is configured; the number object reports this as `supports_outbound`. The number you dial from is the caller ID the callee sees. + + + Outbound calls run the agent's published configuration, not the draft. [Publish](/agents/deploy/versions-publishing) before dialing. + + + ```bash + curl --request POST https://api.fish.audio/v1/agent/phone-calls \ + --header "Authorization: Bearer $FISH_API_KEY" \ + --header "Content-Type: application/json" \ + --header "Idempotency-Key: order-4711-reminder-1" \ + --data '{ + "agent_id": "YOUR_AGENT_ID", + "phone_number_id": "YOUR_PHONE_NUMBER_ID", + "to_number": "+14155550123" + }' + ``` + + The request returns `201` as soon as the dial is dispatched: + + ```json + { "session_id": "9c41f0d2e8a34b7f", "status": "queued" } + ``` + + + + +This endpoint requires an API key; there is no anonymous variant. See the [API reference](/api-reference/endpoint/agent/create-phone-call) for the full schema. + +### Request fields + +| Field | Description | +| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `agent_id` | Required: the agent that speaks on the call. Must have a published version. | +| `phone_number_id` | Required: the workspace number to dial from. | +| `to_number` | Required: the destination in E.164, for example `+14155550123`. | +| `dynamic_variables` | Optional: per-call values for `{{placeholders}}` in the agent's configured text, same rules as [session creation](/agents/build/dynamic-variables). Up to 50 entries. | +| `overrides` | Optional: replace whole configuration fields for this call, subject to the agent's [override allowlist](/agents/deploy/authenticated-sessions#overrides). | +| `metadata` | Optional: your own JSON object, returned verbatim on session reads and in webhook payloads. Never interpreted. | + +The session's [time and timezone context](/agents/build/time-timezone) resolves from the destination number when the agent has no fixed timezone configured, so "tomorrow morning" means the callee's morning. + +### Retry safely with an Idempotency-Key + +Outbound dials spend money and ring real phones, so put an `Idempotency-Key` header on every create. For 24 hours, repeating the same key with the same body returns the call already placed instead of dialing again. The same key with a **different** body is refused with `422 idempotency_key_reuse`, and a retry that races an in-flight first attempt gets `409 idempotency_key_conflict`; back off and retry the same request. If the create fails with an ambiguous network error, retry with the same key: you get the placed session back if the first attempt went through. + +## The dial outcome + +Ringing is never billed; metering starts when the callee answers. A call that is never answered is not billed and not analyzed. + +You learn how the dial ended in either of two ways: + +- **Push**: subscribe to the [`phone_call.dial_finished` webhook](/agents/monitor/webhooks). It fires exactly once per outbound call, whether or not anyone picked up, before `call.ended`. +- **Poll**: read `GET /v1/agent/sessions/{session_id}` until `dial_status` is set. + +```bash +curl https://api.fish.audio/v1/agent/sessions/9c41f0d2e8a34b7f \ + --header "Authorization: Bearer $FISH_API_KEY" +``` + +Two session fields carry the outcome: + +| Field | Values | +| ------------- | ----------------------------------------------------------------------------------------------------------- | +| `dial_status` | `answered`, `busy`, `no_answer`, or `failed`. `null` while the call is still ringing, and on inbound calls. | +| `answered_by` | What answering-machine detection heard: `human`, `voicemail`, or `unknown`. `null` unless answered. | + +On outbound sessions the attribution fields are person-centric: `caller_number` is the human you dialed and `dialed_number` is your workspace number. Everything else about the session (transcript, recording, [post-call analysis](/agents/monitor/post-call-analysis), `call.ended` and `call.analyzed` webhooks, hang-up via `POST /v1/agent/sessions/{session_id}/end`) works exactly as for [inbound calls](/agents/telephony/inbound-calls). + +## Allowed destinations + +Calls from purchased numbers can reach US, Canada, and Japan numbers. Japanese destinations may keep the domestic trunk zero (`+81080...` is accepted and normalized to `+8180...`), and premium-rate segments (such as `0570` Navi Dial and `0990`) are always refused. Calls from [imported BYO numbers](/agents/telephony/byo-sip) dial out through your own trunk, so the country allowlist does not apply; the destination only has to be valid E.164. + +Numbers that live on the platform can never be dialed, so an agent cannot call another agent's number. + +## Limits + +| Limit | Default | +| ---------------- | -------------------------------------------------------------------------------- | +| Calls per day | 200 per workspace, on a fixed UTC day. Rejected attempts count toward the quota. | +| Concurrent calls | 10 per workspace, counting calls that are still ringing or in conversation. | + +Exceeding either returns `429` with a machine-readable reason (`daily_limit_exceeded`, `concurrency_limit_exceeded`). These are per-workspace defaults; contact support if you need more. + +## Errors + +Unlike most [Agents API errors](/api-reference/agent-errors), phone-call errors carry a machine-readable `reason` alongside the `message`: + +```json +{ + "status": 422, + "reason": "destination_not_allowed", + "message": "Outbound calls are limited to US, Canada and Japan numbers" +} +``` + +| Status | Reason | Cause | +| ------ | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `402` | `insufficient_credit` | Out of API credit; top up first. | +| `403` | `outbound_disabled` | Outbound calling is switched off for this workspace. | +| `404` | `number_not_found`, `agent_not_found` | The id doesn't exist, isn't yours, or the number was released. | +| `409` | `agent_not_published` | [Publish](/agents/deploy/versions-publishing) the agent first. | +| `409` | `idempotency_key_conflict` | A request with this key is still in flight; back off and retry the same request. | +| `422` | `number_provider_unsupported`, `number_termination_missing`, `number_inactive` | The from-number can't place calls; see [which numbers support outbound](/agents/telephony/byo-sip#outbound-calls-and-transfers). | +| `422` | `destination_invalid`, `destination_not_allowed`, `premium_destination_blocked`, `self_call_blocked` | The destination is refused; see [allowed destinations](#allowed-destinations). | +| `422` | `idempotency_key_reuse` | The key was already used with a different body; mint a fresh key per distinct call. | +| `429` | `daily_limit_exceeded`, `concurrency_limit_exceeded` | A workspace [limit](#limits) was hit. | + +`502` and `503` follow the [general guidance](/api-reference/agent-errors#5xx): retrying is safe, especially with an `Idempotency-Key`. + +## Going further + + + + The `phone_call.dial_finished` payload in full. + + + Hand an answered call to a human; consult legs dial from the same number. + + + Place calls through your own trunk with your number as caller ID. + + + Transcripts, recordings, and session listing filters. + + diff --git a/api-reference/agent-errors.mdx b/api-reference/agent-errors.mdx index 10756b6..149a000 100644 --- a/api-reference/agent-errors.mdx +++ b/api-reference/agent-errors.mdx @@ -25,6 +25,7 @@ The exceptions to that shape: ] ``` +- **Phone-call creation** ([`POST /v1/agent/phone-calls`](/api-reference/endpoint/agent/create-phone-call)) adds a machine-readable `reason` field to its errors; see [Outbound calls](/agents/telephony/outbound-calls#errors) for the full list. - A request body that isn't valid JSON returns `400` with `"Malformed JSON"`; a missing body or wrong `Content-Type` returns a bare `415`. - A missing or malformed `Authorization` header returns a bare `401` with a `WWW-Authenticate: Bearer` header; a present-but-bad credential returns the JSON shape (`"Invalid token"`, `"Token expired"`). diff --git a/api-reference/endpoint/agent/create-phone-call.mdx b/api-reference/endpoint/agent/create-phone-call.mdx new file mode 100644 index 0000000..4a55a76 --- /dev/null +++ b/api-reference/endpoint/agent/create-phone-call.mdx @@ -0,0 +1,7 @@ +--- +openapi: post /v1/agent/phone-calls +title: "Create Phone Call" +description: "Place an outbound call from one of your phone numbers; the agent speaks when\nthe callee answers." +icon: "phone-arrow-up-right" +iconType: "solid" +--- diff --git a/api-reference/openapi.json b/api-reference/openapi.json index d22e5ba..2a01be3 100644 --- a/api-reference/openapi.json +++ b/api-reference/openapi.json @@ -491,7 +491,7 @@ "/v1/agent/sessions": { "get": { "summary": "List Agent Sessions", - "description": "List your team's sessions, newest first. Filter by agent, status, caller\nnumber, or creation time. Paginate with `cursor` (recommended; follow\n`next_cursor` while `has_more` is true) or with `page` for offset pagination\nwith a `total` count; the two are mutually exclusive.", + "description": "List your team's sessions, newest first. Filter by agent, status, caller\nnumber, or creation time. Paginate with `cursor` (recommended; follow\n`next_cursor` while `has_more` is true) or with `page` for offset pagination\nwith a `total` count \u2014 the two are mutually exclusive.", "security": [ { "BearerAuth": [] @@ -2128,7 +2128,7 @@ "/v1/agent/agents": { "get": { "summary": "List Agents", - "description": "List your team's agents, newest first. Paginate with `cursor` (follow\n`next_cursor` while `has_more` is true) or with `page` for offset\npagination with a `total` count; the two are mutually exclusive.", + "description": "List your team's agents, newest first. Paginate with `cursor` (follow\n`next_cursor` while `has_more` is true) or with `page` for offset\npagination with a `total` count \u2014 the two are mutually exclusive.", "security": [ { "BearerAuth": [] @@ -2420,7 +2420,7 @@ }, "post": { "summary": "Create Agent", - "description": "Create an agent, optionally with its full initial configuration inline.\nThe agent starts as a draft: publish it before creating sessions with it.", + "description": "Create an agent, optionally with its full initial configuration inline \u2014\none call provisions a ready-to-publish agent. The agent starts as a draft:\npublish it before creating sessions with it.", "security": [ { "BearerAuth": [] @@ -2921,7 +2921,7 @@ }, "patch": { "summary": "Update Agent", - "description": "Update agent-level fields (name, description, status, public access and\nsession-override policy). Omitted fields keep their value. Conversation\nbehavior (voice, prompt, recording and the rest) is draft configuration:\nuse `PATCH /v1/agent/agents/{agent_id}/config`.", + "description": "Update agent-level fields (name, description, status, public access and\nsession-override policy). Omitted fields keep their value. Conversation\nbehavior \u2014 voice, prompt, recording and the rest \u2014 is draft configuration:\nuse `PATCH /v1/agent/agents/{agent_id}/config`.", "security": [ { "BearerAuth": [] @@ -3341,7 +3341,7 @@ "/v1/agent/agents/{agent_id}/widget": { "get": { "summary": "Get Widget Config", - "description": "Unauthenticated display configuration for the embeddable ``\nwidget. Only agents published as public are reachable, and the request\n`Origin` must match the agent's allowed origins, the same gate as\nanonymous session creation. Attributes set on the embed tag override\nevery field returned here.", + "description": "Unauthenticated display configuration for the embeddable ``\nwidget. Only agents published as public are reachable, and the request\n`Origin` must match the agent's allowed origins \u2014 the same gate as\nanonymous session creation. Attributes set on the embed tag override\nevery field returned here.", "parameters": [ { "in": "path", @@ -3381,7 +3381,7 @@ "content": { "application/json": { "schema": { - "description": "Display config for the embeddable `` widget.\n\nServed without authentication for public agents; HTML attributes on the\nembed tag override every field. Grows alongside the Builder widget tab\n(greeting, policy switches, styles): additions only, never renames.", + "description": "Display config for the embeddable `` widget.\n\nServed without authentication for public agents; HTML attributes on the\nembed tag override every field. Grows alongside the Builder widget tab\n(greeting, policy switches, styles) \u2014 additions only, never renames.", "properties": { "agent_name": { "title": "Agent Name", @@ -3479,7 +3479,7 @@ "/v1/agent/agents/{agent_id}/config": { "get": { "summary": "Get Draft Config", - "description": "Read the agent's current draft configuration, the state the next publish\nwill freeze. Sessions run the latest published version, not the draft; use\nthe versions endpoints to see what is live. Webhook signing secrets are\nwrite-only and reported as `has_secret`.", + "description": "Read the agent's current draft configuration \u2014 the state the next publish\nwill freeze. Sessions run the latest published version, not the draft; use\nthe versions endpoints to see what is live. Webhook signing secrets are\nwrite-only and reported as `has_secret`.", "security": [ { "BearerAuth": [] @@ -3539,6 +3539,9 @@ "guardrails": { "$ref": "#/components/schemas/AgentGuardrailsConfig" }, + "llm": { + "$ref": "#/components/schemas/AgentLLMConfigRedacted" + }, "updated_at": { "format": "date-time", "title": "Updated At", @@ -3556,6 +3559,7 @@ "knowledge_base", "analysis", "guardrails", + "llm", "updated_at" ], "type": "object" @@ -3681,7 +3685,7 @@ }, "patch": { "summary": "Update Draft Config", - "description": "Patch the draft configuration section by section; omitted sections keep\ntheir value. Changes only affect live sessions after the next publish.\n`prompt.system_prompt` is limited to 4000 tokens (422 beyond); keeping it\nunder 2000 tokens is recommended for latency and cost.\n`voice.voice_id` accepts any public voice model id.\n`voice.speaking_language` accepts `en`, `ja`, `zh`, `ko`, `es`, `fr`, `de`;\nanything else is 422. `voice.expressive` opts into richer expressive\ndelivery (emotion steering, laughter and sounds, pauses); off keeps the\nstandard delivery. `tool_ids` and\n`knowledge_source_ids` replace their attachment lists wholesale and every\nid must resolve, else 422.", + "description": "Patch the draft configuration section by section; omitted sections keep\ntheir value. Changes only affect live sessions after the next publish.\n`prompt.system_prompt` is limited to 4000 tokens (422 beyond); keeping it\nunder 2000 tokens is recommended for latency and cost.\n`voice.voice_id` accepts any public voice model id.\n`voice.speaking_language` accepts `en`, `ja`, `zh`, `ko`, `es`, `fr`, `de`;\nanything else is 422. `voice.expressive` opts into richer expressive\ndelivery (emotion steering, laughter and sounds, pauses); off keeps the\nstandard delivery. `tool_ids` and\n`knowledge_source_ids` replace their attachment lists wholesale and every\nid must resolve, else 422. `llm.custom` points the agent at your own\nOpenAI-compatible endpoint; mutually exclusive with `llm.tier`, cleared\nwith an explicit null.", "security": [ { "BearerAuth": [] @@ -3751,6 +3755,9 @@ "guardrails": { "$ref": "#/components/schemas/AgentGuardrailsConfig" }, + "llm": { + "$ref": "#/components/schemas/AgentLLMConfigRedacted" + }, "updated_at": { "format": "date-time", "title": "Updated At", @@ -3768,6 +3775,7 @@ "knowledge_base", "analysis", "guardrails", + "llm", "updated_at" ], "type": "object" @@ -3939,7 +3947,7 @@ "/v1/agent/agents/{agent_id}/publish": { "post": { "summary": "Publish Agent", - "description": "Freeze the current draft into an immutable version (version_number\nauto-increments) and make it the live configuration for new sessions. The\nbody is optional; the title and description label the version for audit\nand rollback.", + "description": "Freeze the current draft into an immutable version (version_number\nauto-increments) and make it the live configuration for new sessions. If\nthe draft already matches the live version, return that version unchanged.\nThe body is optional; the title and description label a newly created\nversion for audit and rollback.", "security": [ { "BearerAuth": [] @@ -4088,6 +4096,43 @@ } } }, + "409": { + "description": "Request conflict", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, "422": { "description": "", "headers": {}, @@ -4495,7 +4540,7 @@ "/v1/agent/agents/{agent_id}/versions/{version_number}": { "get": { "summary": "Get Agent Version", - "description": "One published version with its full frozen configuration snapshot,\nincluding the current live version. Secrets inside the snapshot are\nredacted the same way as the draft config.", + "description": "One published version with its full frozen configuration snapshot \u2014\nincluding the current live version. Secrets inside the snapshot are\nredacted the same way as the draft config.", "security": [ { "BearerAuth": [] @@ -4964,7 +5009,7 @@ "/v1/agent/knowledge-sources": { "get": { "summary": "List Knowledge Sources", - "description": "List your team's knowledge sources, newest first. Paginate with `cursor`\n(follow `next_cursor` while `has_more` is true) or with `page` for offset\npagination with a `total` count; the two are mutually exclusive.", + "description": "List your team's knowledge sources, newest first. Paginate with `cursor`\n(follow `next_cursor` while `has_more` is true) or with `page` for offset\npagination with a `total` count \u2014 the two are mutually exclusive.", "security": [ { "BearerAuth": [] @@ -5751,7 +5796,7 @@ }, "patch": { "summary": "Update Knowledge Source", - "description": "Rename the source and/or replace its content by uploading a new file in\n`source` (multipart). Replacing content increments `revision_number` while\nthe id stays stable, and every attached agent's draft picks it up\nimmediately; published versions pin the revision they were published with,\nso republish each affected agent to put the new content live.", + "description": "Rename the source and/or replace its content by uploading a new file in\n`source` (multipart). Replacing content increments `revision_number` while\nthe id stays stable, and every attached agent's draft picks it up\nimmediately; published versions pin the revision they were published with,\nso republish each affected agent to put the new content live \u2014 that\ntwo-step (sync content, republish) is the nightly content-sync recipe.", "security": [ { "BearerAuth": [] @@ -6086,7 +6131,7 @@ }, "delete": { "summary": "Delete Knowledge Source", - "description": "Delete a knowledge source. Returns 409 while any agent still references it,\nin its draft or in its currently published version (sessions resolve\nsources at call time, so deleting a published reference would change a\nrunning agent). Check `GET /v1/agent/knowledge-sources/{source_id}/agents`,\ndetach via the agent config, and republish if needed before deleting.", + "description": "Delete a knowledge source. Returns 409 while any agent still references it\n\u2014 in its draft or in its currently published version (sessions resolve\nsources at call time, so deleting a published reference would change a\nrunning agent). Check `GET /v1/agent/knowledge-sources/{source_id}/agents`,\ndetach via the agent config, and republish if needed before deleting.", "security": [ { "BearerAuth": [] @@ -6267,7 +6312,7 @@ "/v1/agent/knowledge-sources/{source_id}/agents": { "get": { "summary": "List Agents Using Knowledge Source", - "description": "Every agent that references this source in its draft or currently\npublished configuration: the pre-flight check before a delete.", + "description": "Every agent that references this source in its draft or currently\npublished configuration \u2014 the pre-flight check before a delete.", "security": [ { "BearerAuth": [] @@ -6436,7 +6481,7 @@ "/v1/agent/tools": { "get": { "summary": "List Tools", - "description": "List your team's tools, newest first. Filter with `agent_id` to see one\nagent's attached tools. Paginate with `cursor` (follow `next_cursor` while\n`has_more` is true) or with `page` for offset pagination with a `total`\ncount; the two are mutually exclusive.", + "description": "List your team's tools, newest first. Filter with `agent_id` to see one\nagent's attached tools. Paginate with `cursor` (follow `next_cursor` while\n`has_more` is true) or with `page` for offset pagination with a `total`\ncount \u2014 the two are mutually exclusive.", "security": [ { "BearerAuth": [] @@ -7038,7 +7083,7 @@ "/v1/agent/tools/{tool_id}": { "get": { "summary": "Get Tool", - "description": "Fetch one tool's full definition. Credential header values are never\nreturned; each credential header reports `has_secret` instead.", + "description": "Fetch one tool's full definition. Credential header values are never\nreturned \u2014 each credential header reports `has_secret` instead.", "security": [ { "BearerAuth": [] @@ -7315,7 +7360,7 @@ }, "patch": { "summary": "Update Tool", - "description": "Patch tool fields; omitted fields keep their value (null is rejected;\nsend an empty string to clear a text field). `headers` replaces the header\nlist wholesale. Include credential values again whenever you send it,\nsince reads never return them. Attached agents' drafts pick up the change\nimmediately; published versions stay frozen until re-published.", + "description": "Patch tool fields; omitted fields keep their value (null is rejected \u2014\nsend an empty string to clear a text field). `headers` replaces the header\nlist wholesale \u2014 include credential values again whenever you send it,\nsince reads never return them. Attached agents' drafts pick up the change\nimmediately; published versions stay frozen until re-published.", "security": [ { "BearerAuth": [] @@ -7676,7 +7721,7 @@ }, "delete": { "summary": "Delete Tool", - "description": "Delete a tool. Returns 409 while any agent's draft configuration still\nreferences it. Check `GET /v1/agent/tools/{tool_id}/agents` and detach it\nvia the agent config first, so a delete can never silently change agent\nbehavior.", + "description": "Delete a tool. Returns 409 while any agent's draft configuration still\nreferences it \u2014 check `GET /v1/agent/tools/{tool_id}/agents` and detach it\nvia the agent config first, so a delete can never silently change agent\nbehavior.", "security": [ { "BearerAuth": [] @@ -7857,7 +7902,7 @@ "/v1/agent/tools/{tool_id}/agents": { "get": { "summary": "List Agents Using Tool", - "description": "Every agent whose draft configuration references this tool: the\npre-flight check before a delete. Published versions keep executing their\nfrozen tool snapshot, so only draft references block deletion.", + "description": "Every agent whose draft configuration references this tool \u2014 the\npre-flight check before a delete. Published versions keep executing their\nfrozen tool snapshot, so only draft references block deletion.", "security": [ { "BearerAuth": [] @@ -8026,7 +8071,7 @@ "/v1/agent/phone-numbers": { "get": { "summary": "List Phone Numbers", - "description": "List your team's phone numbers, newest first. Released numbers are gone\nfor good and never appear. Look an id up by E.164 with `phone_number`, or\nfilter with `agent_id` to see one agent's numbers. Paginate with `cursor`\n(follow `next_cursor` while `has_more` is true) or with `page` for offset\npagination with a `total` count; the two are mutually exclusive.", + "description": "List your team's phone numbers, newest first. Released numbers are gone\nfor good and never appear. Look an id up by E.164 with `phone_number`, or\nfilter with `agent_id` to see one agent's numbers. Paginate with `cursor`\n(follow `next_cursor` while `has_more` is true) or with `page` for offset\npagination with a `total` count \u2014 the two are mutually exclusive.", "security": [ { "BearerAuth": [] @@ -8345,7 +8390,7 @@ }, "post": { "summary": "Purchase Phone Number", - "description": "Buy a number from the inventory. The number lands in your default\nworkspace, and any `agent_id` you bind must live there too. Billing is the\nmonthly price charged in daily slices: the first day is charged before\nanything is bought (402 costs you nothing), and the daily run advances it\nfrom there. 409 means the number is already on the platform; 502 means the\nprovider refused the purchase; the number stays visible with status\n`error` and is safe to release.", + "description": "Buy a number from the inventory. The number lands in your default\nworkspace, and any `agent_id` you bind must live there too. Billing is the\nmonthly price charged in daily slices: the first day is charged before\nanything is bought (402 costs you nothing), and the daily run advances it\nfrom there. 409 means the number is already on the platform; 502 means the\nprovider refused the purchase \u2014 the number stays visible with status\n`error` and is safe to release.", "security": [ { "BearerAuth": [] @@ -8979,7 +9024,7 @@ }, "patch": { "summary": "Update Phone Number", - "description": "Change the label and/or repoint the number at another agent: the\ndeployment-pipeline move (rebind from the staging agent to the production\none). Send `agent_id: null` to unbind; unbound numbers ring busy. The\nagent must live in the number's workspace. Rebinding is a routing-table\nupdate resolved on the next inbound call; nothing about the number itself\nis reprovisioned.", + "description": "Change the label and/or repoint the number at another agent \u2014 the\ndeployment-pipeline move (rebind from the staging agent to the production\none). Send `agent_id: null` to unbind; unbound numbers ring busy. The\nagent must live in the number's workspace. Rebinding is a routing-table\nupdate resolved on the next inbound call; nothing about the number itself\nis reprovisioned.", "security": [ { "BearerAuth": [] @@ -9251,7 +9296,7 @@ }, "delete": { "summary": "Release Phone Number", - "description": "Release a number back to the provider's inventory and stop its daily\nbilling. This is irreversible: anyone (including other platforms) can\nbuy the number afterwards, so callers who saved it may reach a stranger.\nThe number disappears from this API immediately.", + "description": "Release a number back to the provider's inventory and stop its daily\nbilling. This is irreversible: anyone \u2014 including other platforms \u2014 can\nbuy the number afterwards, so callers who saved it may reach a stranger.\nThe number disappears from this API immediately.", "security": [ { "BearerAuth": [] @@ -10155,7 +10200,7 @@ "audio_base64": "SUQzBAAAAAAA...", "chunk_audio_offset_sec": 0, "chunk_seq": 0, - "content": "I can’t believe it’s been this long. It feels like forever since we last really talked. I’ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I’ve thought about calling you so many times, but I never knew where to start." + "content": "I can\u2019t believe it\u2019s been this long. It feels like forever since we last really talked. I\u2019ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I\u2019ve thought about calling you so many times, but I never knew where to start." }, { "alignment": { @@ -10416,7 +10461,7 @@ "audio_base64": "//uSxOAAF...", "chunk_audio_offset_sec": 0, "chunk_seq": 0, - "content": "I can’t believe it’s been this long. It feels like forever since we last really talked. I’ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I’ve thought about calling you so many times, but I never knew where to start." + "content": "I can\u2019t believe it\u2019s been this long. It feels like forever since we last really talked. I\u2019ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I\u2019ve thought about calling you so many times, but I never knew where to start." }, { "alignment": { @@ -10607,7 +10652,7 @@ "audio_base64": "//uSxImAl...", "chunk_audio_offset_sec": 16.24, "chunk_seq": 1, - "content": "Seeing you again now makes me realize just how much I’ve missed you. We have so much to catch up on, and I don’t even know which part of my life to tell you about first." + "content": "Seeing you again now makes me realize just how much I\u2019ve missed you. We have so much to catch up on, and I don\u2019t even know which part of my life to tell you about first." } ], "properties": { @@ -10658,15 +10703,15 @@ "examples": { "first_event": { "summary": "First text chunk event with alignment", - "value": "data: {\"audio_base64\": \"SUQzBAAAAAAA...\", \"content\": \"I can’t believe it’s been this long. It feels like forever since we last really talked. I’ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I’ve thought about calling you so many times, but I never knew where to start.\", \"alignment\": {\"segments\": [{\"text\": \"I\", \"start\": 0.0, \"end\": 0.16}, {\"text\": \"can't\", \"start\": 0.16, \"end\": 0.48}, {\"text\": \"believe\", \"start\": 0.48, \"end\": 0.8}, {\"text\": \"its\", \"start\": 0.8, \"end\": 1.12}, {\"text\": \"been\", \"start\": 1.2, \"end\": 1.44}, {\"text\": \"this\", \"start\": 1.44, \"end\": 1.76}, {\"text\": \"long\", \"start\": 1.76, \"end\": 2.48}, {\"text\": \"It\", \"start\": 2.56, \"end\": 2.64}, {\"text\": \"feels\", \"start\": 2.72, \"end\": 3.04}, {\"text\": \"like\", \"start\": 3.12, \"end\": 3.28}, {\"text\": \"forever\", \"start\": 3.36, \"end\": 4.0}, {\"text\": \"since\", \"start\": 4.0, \"end\": 4.32}, {\"text\": \"we\", \"start\": 4.32, \"end\": 4.48}, {\"text\": \"last\", \"start\": 4.48, \"end\": 4.96}, {\"text\": \"really\", \"start\": 4.96, \"end\": 5.28}, {\"text\": \"talked\", \"start\": 5.28, \"end\": 5.84}, {\"text\": \"Ive\", \"start\": 6.0, \"end\": 6.24}, {\"text\": \"missed\", \"start\": 6.24, \"end\": 6.64}, {\"text\": \"hearing\", \"start\": 6.64, \"end\": 6.96}, {\"text\": \"your\", \"start\": 6.96, \"end\": 7.2}, {\"text\": \"voice\", \"start\": 7.2, \"end\": 7.76}, {\"text\": \"your\", \"start\": 7.76, \"end\": 7.92}, {\"text\": \"stories\", \"start\": 7.92, \"end\": 8.48}, {\"text\": \"even\", \"start\": 8.48, \"end\": 8.72}, {\"text\": \"the\", \"start\": 8.72, \"end\": 8.8}, {\"text\": \"little\", \"start\": 8.8, \"end\": 9.2}, {\"text\": \"things\", \"start\": 9.2, \"end\": 9.52}, {\"text\": \"you\", \"start\": 9.52, \"end\": 9.68}, {\"text\": \"used\", \"start\": 9.68, \"end\": 10.0}, {\"text\": \"to\", \"start\": 10.0, \"end\": 10.08}, {\"text\": \"say\", \"start\": 10.08, \"end\": 10.64}, {\"text\": \"How\", \"start\": 10.64, \"end\": 10.96}, {\"text\": \"have\", \"start\": 10.96, \"end\": 11.12}, {\"text\": \"you\", \"start\": 11.12, \"end\": 11.36}, {\"text\": \"been\", \"start\": 11.36, \"end\": 11.92}, {\"text\": \"Ive\", \"start\": 12.0, \"end\": 12.24}, {\"text\": \"thought\", \"start\": 12.24, \"end\": 12.48}, {\"text\": \"about\", \"start\": 12.48, \"end\": 12.8}, {\"text\": \"calling\", \"start\": 12.8, \"end\": 13.2}, {\"text\": \"you\", \"start\": 13.2, \"end\": 13.36}, {\"text\": \"so\", \"start\": 13.36, \"end\": 13.68}, {\"text\": \"many\", \"start\": 13.68, \"end\": 13.92}, {\"text\": \"times\", \"start\": 13.92, \"end\": 14.56}, {\"text\": \"but\", \"start\": 14.56, \"end\": 14.72}, {\"text\": \"I\", \"start\": 14.72, \"end\": 14.88}, {\"text\": \"never\", \"start\": 14.88, \"end\": 15.2}, {\"text\": \"knew\", \"start\": 15.2, \"end\": 15.36}, {\"text\": \"where\", \"start\": 15.36, \"end\": 15.6}, {\"text\": \"to\", \"start\": 15.6, \"end\": 15.6}, {\"text\": \"start\", \"start\": 15.68, \"end\": 16.24}], \"audio_duration\": 16.24}, \"chunk_seq\": 0, \"chunk_audio_offset_sec\": 0.0}\n\n" + "value": "data: {\"audio_base64\": \"SUQzBAAAAAAA...\", \"content\": \"I can\u2019t believe it\u2019s been this long. It feels like forever since we last really talked. I\u2019ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I\u2019ve thought about calling you so many times, but I never knew where to start.\", \"alignment\": {\"segments\": [{\"text\": \"I\", \"start\": 0.0, \"end\": 0.16}, {\"text\": \"can't\", \"start\": 0.16, \"end\": 0.48}, {\"text\": \"believe\", \"start\": 0.48, \"end\": 0.8}, {\"text\": \"its\", \"start\": 0.8, \"end\": 1.12}, {\"text\": \"been\", \"start\": 1.2, \"end\": 1.44}, {\"text\": \"this\", \"start\": 1.44, \"end\": 1.76}, {\"text\": \"long\", \"start\": 1.76, \"end\": 2.48}, {\"text\": \"It\", \"start\": 2.56, \"end\": 2.64}, {\"text\": \"feels\", \"start\": 2.72, \"end\": 3.04}, {\"text\": \"like\", \"start\": 3.12, \"end\": 3.28}, {\"text\": \"forever\", \"start\": 3.36, \"end\": 4.0}, {\"text\": \"since\", \"start\": 4.0, \"end\": 4.32}, {\"text\": \"we\", \"start\": 4.32, \"end\": 4.48}, {\"text\": \"last\", \"start\": 4.48, \"end\": 4.96}, {\"text\": \"really\", \"start\": 4.96, \"end\": 5.28}, {\"text\": \"talked\", \"start\": 5.28, \"end\": 5.84}, {\"text\": \"Ive\", \"start\": 6.0, \"end\": 6.24}, {\"text\": \"missed\", \"start\": 6.24, \"end\": 6.64}, {\"text\": \"hearing\", \"start\": 6.64, \"end\": 6.96}, {\"text\": \"your\", \"start\": 6.96, \"end\": 7.2}, {\"text\": \"voice\", \"start\": 7.2, \"end\": 7.76}, {\"text\": \"your\", \"start\": 7.76, \"end\": 7.92}, {\"text\": \"stories\", \"start\": 7.92, \"end\": 8.48}, {\"text\": \"even\", \"start\": 8.48, \"end\": 8.72}, {\"text\": \"the\", \"start\": 8.72, \"end\": 8.8}, {\"text\": \"little\", \"start\": 8.8, \"end\": 9.2}, {\"text\": \"things\", \"start\": 9.2, \"end\": 9.52}, {\"text\": \"you\", \"start\": 9.52, \"end\": 9.68}, {\"text\": \"used\", \"start\": 9.68, \"end\": 10.0}, {\"text\": \"to\", \"start\": 10.0, \"end\": 10.08}, {\"text\": \"say\", \"start\": 10.08, \"end\": 10.64}, {\"text\": \"How\", \"start\": 10.64, \"end\": 10.96}, {\"text\": \"have\", \"start\": 10.96, \"end\": 11.12}, {\"text\": \"you\", \"start\": 11.12, \"end\": 11.36}, {\"text\": \"been\", \"start\": 11.36, \"end\": 11.92}, {\"text\": \"Ive\", \"start\": 12.0, \"end\": 12.24}, {\"text\": \"thought\", \"start\": 12.24, \"end\": 12.48}, {\"text\": \"about\", \"start\": 12.48, \"end\": 12.8}, {\"text\": \"calling\", \"start\": 12.8, \"end\": 13.2}, {\"text\": \"you\", \"start\": 13.2, \"end\": 13.36}, {\"text\": \"so\", \"start\": 13.36, \"end\": 13.68}, {\"text\": \"many\", \"start\": 13.68, \"end\": 13.92}, {\"text\": \"times\", \"start\": 13.92, \"end\": 14.56}, {\"text\": \"but\", \"start\": 14.56, \"end\": 14.72}, {\"text\": \"I\", \"start\": 14.72, \"end\": 14.88}, {\"text\": \"never\", \"start\": 14.88, \"end\": 15.2}, {\"text\": \"knew\", \"start\": 15.2, \"end\": 15.36}, {\"text\": \"where\", \"start\": 15.36, \"end\": 15.6}, {\"text\": \"to\", \"start\": 15.6, \"end\": 15.6}, {\"text\": \"start\", \"start\": 15.68, \"end\": 16.24}], \"audio_duration\": 16.24}, \"chunk_seq\": 0, \"chunk_audio_offset_sec\": 0.0}\n\n" }, "following_event": { "summary": "Following audio event with latest alignment snapshot", - "value": "data: {\"audio_base64\": \"//uSxOAAF...\", \"content\": \"I can’t believe it’s been this long. It feels like forever since we last really talked. I’ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I’ve thought about calling you so many times, but I never knew where to start.\", \"alignment\": {\"segments\": [{\"text\": \"I\", \"start\": 0.0, \"end\": 0.16}, {\"text\": \"can't\", \"start\": 0.16, \"end\": 0.48}, {\"text\": \"believe\", \"start\": 0.48, \"end\": 0.8}, {\"text\": \"its\", \"start\": 0.8, \"end\": 1.12}, {\"text\": \"been\", \"start\": 1.2, \"end\": 1.44}, {\"text\": \"this\", \"start\": 1.44, \"end\": 1.76}, {\"text\": \"long\", \"start\": 1.76, \"end\": 2.48}, {\"text\": \"It\", \"start\": 2.56, \"end\": 2.64}, {\"text\": \"feels\", \"start\": 2.72, \"end\": 3.04}, {\"text\": \"like\", \"start\": 3.12, \"end\": 3.28}, {\"text\": \"forever\", \"start\": 3.36, \"end\": 4.0}, {\"text\": \"since\", \"start\": 4.0, \"end\": 4.32}, {\"text\": \"we\", \"start\": 4.32, \"end\": 4.48}, {\"text\": \"last\", \"start\": 4.48, \"end\": 4.96}, {\"text\": \"really\", \"start\": 4.96, \"end\": 5.28}, {\"text\": \"talked\", \"start\": 5.28, \"end\": 5.84}, {\"text\": \"Ive\", \"start\": 6.0, \"end\": 6.24}, {\"text\": \"missed\", \"start\": 6.24, \"end\": 6.64}, {\"text\": \"hearing\", \"start\": 6.64, \"end\": 6.96}, {\"text\": \"your\", \"start\": 6.96, \"end\": 7.2}, {\"text\": \"voice\", \"start\": 7.2, \"end\": 7.76}, {\"text\": \"your\", \"start\": 7.76, \"end\": 7.92}, {\"text\": \"stories\", \"start\": 7.92, \"end\": 8.48}, {\"text\": \"even\", \"start\": 8.48, \"end\": 8.72}, {\"text\": \"the\", \"start\": 8.72, \"end\": 8.8}, {\"text\": \"little\", \"start\": 8.8, \"end\": 9.2}, {\"text\": \"things\", \"start\": 9.2, \"end\": 9.52}, {\"text\": \"you\", \"start\": 9.52, \"end\": 9.68}, {\"text\": \"used\", \"start\": 9.68, \"end\": 10.0}, {\"text\": \"to\", \"start\": 10.0, \"end\": 10.08}, {\"text\": \"say\", \"start\": 10.08, \"end\": 10.64}, {\"text\": \"How\", \"start\": 10.64, \"end\": 10.96}, {\"text\": \"have\", \"start\": 10.96, \"end\": 11.12}, {\"text\": \"you\", \"start\": 11.12, \"end\": 11.36}, {\"text\": \"been\", \"start\": 11.36, \"end\": 11.92}, {\"text\": \"Ive\", \"start\": 12.0, \"end\": 12.24}, {\"text\": \"thought\", \"start\": 12.24, \"end\": 12.48}, {\"text\": \"about\", \"start\": 12.48, \"end\": 12.8}, {\"text\": \"calling\", \"start\": 12.8, \"end\": 13.2}, {\"text\": \"you\", \"start\": 13.2, \"end\": 13.36}, {\"text\": \"so\", \"start\": 13.36, \"end\": 13.68}, {\"text\": \"many\", \"start\": 13.68, \"end\": 13.92}, {\"text\": \"times\", \"start\": 13.92, \"end\": 14.56}, {\"text\": \"but\", \"start\": 14.56, \"end\": 14.72}, {\"text\": \"I\", \"start\": 14.72, \"end\": 14.88}, {\"text\": \"never\", \"start\": 14.88, \"end\": 15.2}, {\"text\": \"knew\", \"start\": 15.2, \"end\": 15.36}, {\"text\": \"where\", \"start\": 15.36, \"end\": 15.6}, {\"text\": \"to\", \"start\": 15.6, \"end\": 15.6}, {\"text\": \"start\", \"start\": 15.68, \"end\": 16.24}], \"audio_duration\": 16.24}, \"chunk_seq\": 0, \"chunk_audio_offset_sec\": 0.0}\n\n" + "value": "data: {\"audio_base64\": \"//uSxOAAF...\", \"content\": \"I can\u2019t believe it\u2019s been this long. It feels like forever since we last really talked. I\u2019ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I\u2019ve thought about calling you so many times, but I never knew where to start.\", \"alignment\": {\"segments\": [{\"text\": \"I\", \"start\": 0.0, \"end\": 0.16}, {\"text\": \"can't\", \"start\": 0.16, \"end\": 0.48}, {\"text\": \"believe\", \"start\": 0.48, \"end\": 0.8}, {\"text\": \"its\", \"start\": 0.8, \"end\": 1.12}, {\"text\": \"been\", \"start\": 1.2, \"end\": 1.44}, {\"text\": \"this\", \"start\": 1.44, \"end\": 1.76}, {\"text\": \"long\", \"start\": 1.76, \"end\": 2.48}, {\"text\": \"It\", \"start\": 2.56, \"end\": 2.64}, {\"text\": \"feels\", \"start\": 2.72, \"end\": 3.04}, {\"text\": \"like\", \"start\": 3.12, \"end\": 3.28}, {\"text\": \"forever\", \"start\": 3.36, \"end\": 4.0}, {\"text\": \"since\", \"start\": 4.0, \"end\": 4.32}, {\"text\": \"we\", \"start\": 4.32, \"end\": 4.48}, {\"text\": \"last\", \"start\": 4.48, \"end\": 4.96}, {\"text\": \"really\", \"start\": 4.96, \"end\": 5.28}, {\"text\": \"talked\", \"start\": 5.28, \"end\": 5.84}, {\"text\": \"Ive\", \"start\": 6.0, \"end\": 6.24}, {\"text\": \"missed\", \"start\": 6.24, \"end\": 6.64}, {\"text\": \"hearing\", \"start\": 6.64, \"end\": 6.96}, {\"text\": \"your\", \"start\": 6.96, \"end\": 7.2}, {\"text\": \"voice\", \"start\": 7.2, \"end\": 7.76}, {\"text\": \"your\", \"start\": 7.76, \"end\": 7.92}, {\"text\": \"stories\", \"start\": 7.92, \"end\": 8.48}, {\"text\": \"even\", \"start\": 8.48, \"end\": 8.72}, {\"text\": \"the\", \"start\": 8.72, \"end\": 8.8}, {\"text\": \"little\", \"start\": 8.8, \"end\": 9.2}, {\"text\": \"things\", \"start\": 9.2, \"end\": 9.52}, {\"text\": \"you\", \"start\": 9.52, \"end\": 9.68}, {\"text\": \"used\", \"start\": 9.68, \"end\": 10.0}, {\"text\": \"to\", \"start\": 10.0, \"end\": 10.08}, {\"text\": \"say\", \"start\": 10.08, \"end\": 10.64}, {\"text\": \"How\", \"start\": 10.64, \"end\": 10.96}, {\"text\": \"have\", \"start\": 10.96, \"end\": 11.12}, {\"text\": \"you\", \"start\": 11.12, \"end\": 11.36}, {\"text\": \"been\", \"start\": 11.36, \"end\": 11.92}, {\"text\": \"Ive\", \"start\": 12.0, \"end\": 12.24}, {\"text\": \"thought\", \"start\": 12.24, \"end\": 12.48}, {\"text\": \"about\", \"start\": 12.48, \"end\": 12.8}, {\"text\": \"calling\", \"start\": 12.8, \"end\": 13.2}, {\"text\": \"you\", \"start\": 13.2, \"end\": 13.36}, {\"text\": \"so\", \"start\": 13.36, \"end\": 13.68}, {\"text\": \"many\", \"start\": 13.68, \"end\": 13.92}, {\"text\": \"times\", \"start\": 13.92, \"end\": 14.56}, {\"text\": \"but\", \"start\": 14.56, \"end\": 14.72}, {\"text\": \"I\", \"start\": 14.72, \"end\": 14.88}, {\"text\": \"never\", \"start\": 14.88, \"end\": 15.2}, {\"text\": \"knew\", \"start\": 15.2, \"end\": 15.36}, {\"text\": \"where\", \"start\": 15.36, \"end\": 15.6}, {\"text\": \"to\", \"start\": 15.6, \"end\": 15.6}, {\"text\": \"start\", \"start\": 15.68, \"end\": 16.24}], \"audio_duration\": 16.24}, \"chunk_seq\": 0, \"chunk_audio_offset_sec\": 0.0}\n\n" }, "later_text_chunk_event": { "summary": "Later text chunk event with another alignment", - "value": "data: {\"audio_base64\": \"//uSxImAl...\", \"content\": \"Seeing you again now makes me realize just how much I’ve missed you. We have so much to catch up on, and I don’t even know which part of my life to tell you about first.\", \"alignment\": {\"segments\": [{\"text\": \"Seeing\", \"start\": 0.4, \"end\": 0.8}, {\"text\": \"you\", \"start\": 0.8, \"end\": 0.96}, {\"text\": \"again\", \"start\": 0.96, \"end\": 1.44}, {\"text\": \"now\", \"start\": 1.44, \"end\": 1.68}, {\"text\": \"makes\", \"start\": 1.68, \"end\": 2.08}, {\"text\": \"me\", \"start\": 2.08, \"end\": 2.24}, {\"text\": \"realize\", \"start\": 2.24, \"end\": 2.8}, {\"text\": \"just\", \"start\": 2.8, \"end\": 3.12}, {\"text\": \"how\", \"start\": 3.12, \"end\": 3.28}, {\"text\": \"much\", \"start\": 3.28, \"end\": 3.6}, {\"text\": \"Ive\", \"start\": 3.6, \"end\": 3.76}, {\"text\": \"missed\", \"start\": 3.84, \"end\": 4.24}, {\"text\": \"you\", \"start\": 4.24, \"end\": 4.56}, {\"text\": \"We\", \"start\": 4.64, \"end\": 4.8}, {\"text\": \"have\", \"start\": 4.8, \"end\": 5.04}, {\"text\": \"so\", \"start\": 5.04, \"end\": 5.36}, {\"text\": \"much\", \"start\": 5.36, \"end\": 5.76}, {\"text\": \"to\", \"start\": 5.76, \"end\": 5.76}, {\"text\": \"catch\", \"start\": 5.76, \"end\": 6.16}, {\"text\": \"up\", \"start\": 6.16, \"end\": 6.4}, {\"text\": \"on\", \"start\": 6.4, \"end\": 6.72}, {\"text\": \"and\", \"start\": 6.8, \"end\": 6.96}, {\"text\": \"I\", \"start\": 6.96, \"end\": 7.04}, {\"text\": \"dont\", \"start\": 7.04, \"end\": 7.36}, {\"text\": \"even\", \"start\": 7.36, \"end\": 7.6}, {\"text\": \"know\", \"start\": 7.6, \"end\": 7.84}, {\"text\": \"which\", \"start\": 7.84, \"end\": 8.08}, {\"text\": \"part\", \"start\": 8.08, \"end\": 8.4}, {\"text\": \"of\", \"start\": 8.4, \"end\": 8.48}, {\"text\": \"my\", \"start\": 8.56, \"end\": 8.72}, {\"text\": \"life\", \"start\": 8.72, \"end\": 8.96}, {\"text\": \"to\", \"start\": 9.12, \"end\": 9.12}, {\"text\": \"tell\", \"start\": 9.12, \"end\": 9.44}, {\"text\": \"you\", \"start\": 9.44, \"end\": 9.6}, {\"text\": \"about\", \"start\": 9.6, \"end\": 10.0}, {\"text\": \"first\", \"start\": 10.08, \"end\": 10.48}], \"audio_duration\": 10.48}, \"chunk_seq\": 1, \"chunk_audio_offset_sec\": 16.24}\n\n" + "value": "data: {\"audio_base64\": \"//uSxImAl...\", \"content\": \"Seeing you again now makes me realize just how much I\u2019ve missed you. We have so much to catch up on, and I don\u2019t even know which part of my life to tell you about first.\", \"alignment\": {\"segments\": [{\"text\": \"Seeing\", \"start\": 0.4, \"end\": 0.8}, {\"text\": \"you\", \"start\": 0.8, \"end\": 0.96}, {\"text\": \"again\", \"start\": 0.96, \"end\": 1.44}, {\"text\": \"now\", \"start\": 1.44, \"end\": 1.68}, {\"text\": \"makes\", \"start\": 1.68, \"end\": 2.08}, {\"text\": \"me\", \"start\": 2.08, \"end\": 2.24}, {\"text\": \"realize\", \"start\": 2.24, \"end\": 2.8}, {\"text\": \"just\", \"start\": 2.8, \"end\": 3.12}, {\"text\": \"how\", \"start\": 3.12, \"end\": 3.28}, {\"text\": \"much\", \"start\": 3.28, \"end\": 3.6}, {\"text\": \"Ive\", \"start\": 3.6, \"end\": 3.76}, {\"text\": \"missed\", \"start\": 3.84, \"end\": 4.24}, {\"text\": \"you\", \"start\": 4.24, \"end\": 4.56}, {\"text\": \"We\", \"start\": 4.64, \"end\": 4.8}, {\"text\": \"have\", \"start\": 4.8, \"end\": 5.04}, {\"text\": \"so\", \"start\": 5.04, \"end\": 5.36}, {\"text\": \"much\", \"start\": 5.36, \"end\": 5.76}, {\"text\": \"to\", \"start\": 5.76, \"end\": 5.76}, {\"text\": \"catch\", \"start\": 5.76, \"end\": 6.16}, {\"text\": \"up\", \"start\": 6.16, \"end\": 6.4}, {\"text\": \"on\", \"start\": 6.4, \"end\": 6.72}, {\"text\": \"and\", \"start\": 6.8, \"end\": 6.96}, {\"text\": \"I\", \"start\": 6.96, \"end\": 7.04}, {\"text\": \"dont\", \"start\": 7.04, \"end\": 7.36}, {\"text\": \"even\", \"start\": 7.36, \"end\": 7.6}, {\"text\": \"know\", \"start\": 7.6, \"end\": 7.84}, {\"text\": \"which\", \"start\": 7.84, \"end\": 8.08}, {\"text\": \"part\", \"start\": 8.08, \"end\": 8.4}, {\"text\": \"of\", \"start\": 8.4, \"end\": 8.48}, {\"text\": \"my\", \"start\": 8.56, \"end\": 8.72}, {\"text\": \"life\", \"start\": 8.72, \"end\": 8.96}, {\"text\": \"to\", \"start\": 9.12, \"end\": 9.12}, {\"text\": \"tell\", \"start\": 9.12, \"end\": 9.44}, {\"text\": \"you\", \"start\": 9.44, \"end\": 9.6}, {\"text\": \"about\", \"start\": 9.6, \"end\": 10.0}, {\"text\": \"first\", \"start\": 10.08, \"end\": 10.48}], \"audio_duration\": 10.48}, \"chunk_seq\": 1, \"chunk_audio_offset_sec\": 16.24}\n\n" } } } @@ -10791,7 +10836,7 @@ { "lang": "bash", "label": "Stream With Timestamps", - "source": "curl --no-buffer --request POST \\\n --url https://api.fish.audio/v1/tts/stream/with-timestamp \\\n --header 'Authorization: Bearer ' \\\n --header 'Content-Type: application/json' \\\n --header 'model: s2.1-pro-free' \\\n --data '{\n \"text\": \"[happy] I can’t believe it’s been this long. It feels like forever since we last really talked. I’ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I’ve thought about calling you so many times, but I never knew where to start. Seeing you again now makes me realize just how much I’ve missed you. We have so much to catch up on, and I don’t even know which part of my life to tell you about first.\",\n \"format\": \"opus\",\n \"normalize\": true,\n \"temperature\": 0.9,\n \"chunk_length\": 100,\n \"top_p\": 0.9,\n \"latency\": \"balanced\",\n \"sample_rate\": 48000,\n \"reference_id\": \"fbe02f8306fc4d3d915e9871722a39d5\"\n }'" + "source": "curl --no-buffer --request POST \\\n --url https://api.fish.audio/v1/tts/stream/with-timestamp \\\n --header 'Authorization: Bearer ' \\\n --header 'Content-Type: application/json' \\\n --header 'model: s2.1-pro-free' \\\n --data '{\n \"text\": \"[happy] I can\u2019t believe it\u2019s been this long. It feels like forever since we last really talked. I\u2019ve missed hearing your voice, your stories, even the little things you used to say. How have you been? I\u2019ve thought about calling you so many times, but I never knew where to start. Seeing you again now makes me realize just how much I\u2019ve missed you. We have so much to catch up on, and I don\u2019t even know which part of my life to tell you about first.\",\n \"format\": \"opus\",\n \"normalize\": true,\n \"temperature\": 0.9,\n \"chunk_length\": 100,\n \"top_p\": 0.9,\n \"latency\": \"balanced\",\n \"sample_rate\": 48000,\n \"reference_id\": \"fbe02f8306fc4d3d915e9871722a39d5\"\n }'" } ] } @@ -13014,141 +13059,554 @@ "Model" ] } - } - }, - "tags": [], - "components": { - "securitySchemes": { - "BearerAuth": { - "type": "http", - "scheme": "bearer" - } }, - "schemas": { - "AgentSessionSummary": { - "description": "One list row: lifecycle facts only; the conversation timeline lives on\nthe detail endpoint (Retell-style thin list).", - "properties": { - "session_id": { - "title": "Session Id", - "type": "string" - }, - "agent_id": { - "title": "Agent Id", - "type": "string" - }, - "agent_name": { - "title": "Agent Name", - "type": "string" - }, - "name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Name" - }, - "status": { - "enum": [ - "pending", - "active", - "completed", - "failed", - "unknown" - ], - "title": "Status", - "type": "string" - }, - "source": { - "enum": [ - "api_key", - "dashboard", - "public", - "phone" - ], - "title": "Source", - "type": "string" - }, - "direction": { - "default": "inbound", - "enum": [ - "inbound", - "outbound" - ], - "title": "Direction", - "type": "string" - }, - "dial_status": { - "anyOf": [ - { - "enum": [ - "answered", - "busy", - "no_answer", - "failed" - ], - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Dial Status" - }, - "answered_by": { - "anyOf": [ - { - "enum": [ - "human", - "voicemail", - "unknown" - ], - "type": "string" - }, - { - "type": "null" + "/v1/agent/phone-calls": { + "post": { + "summary": "Create Phone Call", + "description": "Place an outbound call from one of your Twilio phone numbers to a US,\nCanada or Japan destination. A domestic trunk 0 after +81 (e.g.\n+81080...) is accepted and normalized to E.164 (+8180...). Returns\nimmediately with the session queued for\ndialing; subscribe to the `phone_call.dial_finished` webhook or poll\n`GET /v1/agent/sessions/{session_id}` for the dial outcome. Ringing is\nnever billed \u2014 metering starts when the callee answers.\n\nErrors carry a machine-readable `reason` (e.g. `destination_not_allowed`,\n`insufficient_credit`, `daily_limit_exceeded`,\n`concurrency_limit_exceeded`).", + "security": [ + { + "BearerAuth": [] + } + ], + "parameters": [ + { + "in": "header", + "name": "idempotency-key", + "description": "Retry-safe replay key: the same key with the same body returns the call already placed instead of dialing again (24h window).", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Idempotency-Key" + }, + "deprecated": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PhoneCallCreatePayload" } - ], - "default": null, - "title": "Answered By" - }, - "caller_number": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + } + } + }, + "responses": { + "201": { + "description": "Document created, URL follows", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "session_id": { + "title": "Session Id", + "type": "string" + }, + "status": { + "const": "queued", + "default": "queued", + "title": "Status", + "type": "string" + } + }, + "required": [ + "session_id" + ], + "type": "object" + } } - ], - "default": null, - "title": "Caller Number" + } }, - "dialed_number": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + "401": { + "description": "No permission -- see authorization schemes", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } } - ], - "default": null, - "title": "Dialed Number" + } }, - "timezone": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + "402": { + "description": "No payment -- see charging schemes", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, + "403": { + "description": "Request forbidden -- authorization will not help", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, + "404": { + "description": "Nothing matches the given URI", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, + "409": { + "description": "Request conflict", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, + "422": { + "description": "", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, + "429": { + "description": "The user has sent too many requests in a given amount of time (\"rate limiting\")", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, + "502": { + "description": "Invalid responses from another server/proxy", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + }, + "503": { + "description": "The server cannot process the request due to a high load", + "headers": {}, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "title": "Status", + "type": "integer" + }, + "message": { + "title": "Message", + "type": "string" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reason" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + } + } + } + } + }, + "tags": [ + "Phone Calls" + ], + "x-codeSamples": [ + { + "lang": "bash", + "label": "Create Phone Call", + "source": "curl --request POST \\\n --url https://api.fish.audio/v1/agent/phone-calls \\\n --header 'Authorization: Bearer ' \\\n --header 'Content-Type: application/json' \\\n --header 'Idempotency-Key: ' \\\n --data '{\n \"agent_id\": \"\",\n \"phone_number_id\": \"\",\n \"to_number\": \"+14155550123\"\n }'" + } + ] + } + } + }, + "tags": [], + "components": { + "securitySchemes": { + "BearerAuth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "AgentSessionSummary": { + "description": "One list row: lifecycle facts only \u2014 the conversation timeline lives on\nthe detail endpoint (Retell-style thin list).", + "properties": { + "session_id": { + "title": "Session Id", + "type": "string" + }, + "agent_id": { + "title": "Agent Id", + "type": "string" + }, + "agent_name": { + "title": "Agent Name", + "type": "string" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "status": { + "enum": [ + "pending", + "active", + "completed", + "failed", + "unknown" + ], + "title": "Status", + "type": "string" + }, + "source": { + "enum": [ + "api_key", + "dashboard", + "public", + "phone" + ], + "title": "Source", + "type": "string" + }, + "direction": { + "default": "inbound", + "enum": [ + "inbound", + "outbound" + ], + "title": "Direction", + "type": "string" + }, + "dial_status": { + "anyOf": [ + { + "enum": [ + "answered", + "busy", + "no_answer", + "failed" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dial Status" + }, + "answered_by": { + "anyOf": [ + { + "enum": [ + "human", + "voicemail", + "unknown" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Answered By" + }, + "caller_number": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Caller Number" + }, + "dialed_number": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dialed Number" + }, + "timezone": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } ], "default": null, "title": "Timezone" @@ -14329,6 +14787,17 @@ } ], "default": null + }, + "llm": { + "anyOf": [ + { + "$ref": "#/components/schemas/PublicAgentLLMPatch" + }, + { + "type": "null" + } + ], + "default": null } }, "title": "PublicAgentConfigPatchPayload", @@ -14590,6 +15059,80 @@ "title": "PublicAgentKnowledgeBasePatch", "type": "object" }, + "PublicAgentLLMCustomConfig": { + "additionalProperties": false, + "properties": { + "base_url": { + "maxLength": 2000, + "minLength": 1, + "title": "Base Url", + "type": "string" + }, + "model": { + "maxLength": 256, + "minLength": 1, + "title": "Model", + "type": "string" + }, + "api_key": { + "anyOf": [ + { + "maxLength": 4096, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Sent to your endpoint as the Authorization bearer token; write-only, reads return null. Required when introducing `custom`; omit to keep the stored key when updating.", + "title": "Api Key" + } + }, + "required": [ + "base_url", + "model" + ], + "title": "PublicAgentLLMCustomConfig", + "type": "object" + }, + "PublicAgentLLMPatch": { + "additionalProperties": false, + "properties": { + "tier": { + "anyOf": [ + { + "enum": [ + "instant", + "medium", + "high" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Tier" + }, + "custom": { + "anyOf": [ + { + "$ref": "#/components/schemas/PublicAgentLLMCustomConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Your own OpenAI-compatible endpoint; mutually exclusive with `tier`, explicit null reverts to the tier." + } + }, + "title": "PublicAgentLLMPatch", + "type": "object" + }, "PublicAgentPromptPatch": { "additionalProperties": false, "properties": { @@ -14756,6 +15299,18 @@ "PublicAgentWebhooksPatch": { "additionalProperties": false, "properties": { + "conversation_init": { + "anyOf": [ + { + "$ref": "#/components/schemas/PublicConversationInitWebhookPayload" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Pre-call webhook for inbound phone calls: called while the call is being set up; the response's dynamic_variables render into the published prompt before the agent speaks. An explicit null removes it. Takes effect after the next publish." + }, "post_call": { "anyOf": [ { @@ -14777,6 +15332,44 @@ "title": "PublicAgentWebhooksPatch", "type": "object" }, + "PublicConversationInitWebhookPayload": { + "additionalProperties": false, + "properties": { + "url": { + "maxLength": 4000, + "minLength": 1, + "title": "Url", + "type": "string" + }, + "secret": { + "anyOf": [ + { + "maxLength": 256, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional HMAC-SHA256 signing secret (X-Fish-Webhook-Signature). Write-only: reads report `has_secret` instead of the value.", + "title": "Secret" + }, + "timeout_seconds": { + "default": 5, + "description": "How long the platform waits for the endpoint before connecting the call without variables.", + "maximum": 8, + "minimum": 1, + "title": "Timeout Seconds", + "type": "number" + } + }, + "required": [ + "url" + ], + "title": "PublicConversationInitWebhookPayload", + "type": "object" + }, "PublicPostCallWebhookPayload": { "additionalProperties": false, "properties": { @@ -15156,6 +15749,59 @@ "title": "AgentGuardrailsConfig", "type": "object" }, + "AgentLLMConfigRedacted": { + "properties": { + "tier": { + "default": "medium", + "enum": [ + "instant", + "medium", + "high" + ], + "title": "Tier", + "type": "string" + }, + "custom": { + "anyOf": [ + { + "$ref": "#/components/schemas/AgentLLMCustomConfigRedacted" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "AgentLLMConfigRedacted", + "type": "object" + }, + "AgentLLMCustomConfigRedacted": { + "description": "Read entity: the stored api_key never leaves the collection.", + "properties": { + "base_url": { + "minLength": 1, + "title": "Base Url", + "type": "string" + }, + "model": { + "minLength": 1, + "title": "Model", + "type": "string" + }, + "api_key": { + "default": null, + "title": "Api Key", + "type": "null" + } + }, + "required": [ + "base_url", + "model" + ], + "title": "AgentLLMCustomConfigRedacted", + "type": "object" + }, "AgentOutboundConfig": { "description": "Outbound-only behavior; mirror of core WorkflowOutbound.\nAbsent node = AMD on, hang up on voicemail.", "properties": { @@ -15219,7 +15865,7 @@ "type": "string" }, "first_message": { - "default": "Hi! Thanks for calling — how can I help you today?", + "default": "Hi! Thanks for calling \u2014 how can I help you today?", "title": "First Message", "type": "string" }, @@ -15356,6 +16002,17 @@ }, "PublicAgentWebhooksConfig": { "properties": { + "conversation_init": { + "anyOf": [ + { + "$ref": "#/components/schemas/PublicConversationInitWebhook" + }, + { + "type": "null" + } + ], + "default": null + }, "post_call": { "items": { "$ref": "#/components/schemas/PublicPostCallWebhook" @@ -15367,6 +16024,30 @@ "title": "PublicAgentWebhooksConfig", "type": "object" }, + "PublicConversationInitWebhook": { + "properties": { + "url": { + "title": "Url", + "type": "string" + }, + "has_secret": { + "default": false, + "description": "Whether a signing secret is configured; the value itself is never returned.", + "title": "Has Secret", + "type": "boolean" + }, + "timeout_seconds": { + "default": 5, + "title": "Timeout Seconds", + "type": "number" + } + }, + "required": [ + "url" + ], + "title": "PublicConversationInitWebhook", + "type": "object" + }, "PublicPostCallWebhook": { "properties": { "url": { @@ -15469,6 +16150,9 @@ "guardrails": { "$ref": "#/components/schemas/AgentGuardrailsConfig" }, + "llm": { + "$ref": "#/components/schemas/AgentLLMConfigRedacted" + }, "updated_at": { "format": "date-time", "title": "Updated At", @@ -15486,6 +16170,7 @@ "knowledge_base", "analysis", "guardrails", + "llm", "updated_at" ], "title": "PublicAgentConfigEntity", @@ -16303,7 +16988,7 @@ "type": "object" }, "TTSRequest": { - "description": "Request body for text-to-speech synthesis. Supports single-speaker synthesis on all compatible TTS models. Multi-speaker dialogue synthesis is only available with the S2 family (`s2-pro`, `s2.1-pro`, `s2.1-pro-free`), not `s1`.\n\n## Single Speaker\nProvide either `reference_id` (string) pointing to a voice model, or `references` (array of ReferenceAudio) for zero-shot cloning.\n\n## Multiple Speakers (Dialogue, S2 family only)\nFor multi-speaker synthesis, provide:\n- `reference_id`: array of voice model IDs, e.g., [\"speaker-0-id\", \"speaker-1-id\"]\n- `text`: use speaker tags `<|speaker:0|>`, `<|speaker:1|>`, etc. to indicate speaker changes, e.g., \"<|speaker:0|>Hello!<|speaker:1|>Hi there!\"\n\nAlternatively, for zero-shot multi-speaker:\n- `references`: 2D array where each inner array contains references for one speaker\n- `reference_id`: array of identifiers (can be arbitrary strings for zero-shot)\n\n## Example (Multi-Speaker with Model IDs)\n```json\n{\n \"text\": \"<|speaker:0|>Good morning!<|speaker:1|>Good morning! How are you?<|speaker:0|>I'm great, thanks!\",\n \"reference_id\": [\"model-id-alice\", \"model-id-bob\"]\n}\n```", + "description": "Request body for text-to-speech synthesis. Supports single-speaker synthesis on all compatible TTS models. Multi-speaker dialogue synthesis is only available with the S2 family (`s2-pro`, `s2.1-pro`, `s2.1-pro-free`), not `s1`.\n\n## Single Speaker\nProvide either `reference_id` (string) pointing to a voice model, or `references` (array of ReferenceAudio) for zero-shot cloning.\n\n## Multiple Speakers (Dialogue \u2014 S2 family only)\nFor multi-speaker synthesis, provide:\n- `reference_id`: array of voice model IDs, e.g., [\"speaker-0-id\", \"speaker-1-id\"]\n- `text`: use speaker tags `<|speaker:0|>`, `<|speaker:1|>`, etc. to indicate speaker changes, e.g., \"<|speaker:0|>Hello!<|speaker:1|>Hi there!\"\n\nAlternatively, for zero-shot multi-speaker:\n- `references`: 2D array where each inner array contains references for one speaker\n- `reference_id`: array of identifiers (can be arbitrary strings for zero-shot)\n\n## Example (Multi-Speaker with Model IDs)\n```json\n{\n \"text\": \"<|speaker:0|>Good morning!<|speaker:1|>Good morning! How are you?<|speaker:0|>I'm great, thanks!\",\n \"reference_id\": [\"model-id-alice\", \"model-id-bob\"]\n}\n```", "properties": { "text": { "description": "Text to convert to speech.", @@ -17325,6 +18010,88 @@ ], "title": "SampleEntity", "type": "object" + }, + "PhoneCallCreatePayload": { + "additionalProperties": false, + "description": "POST phone-calls body, shared by the public and console routes.\n\nto_number is deliberately not format-validated here: the contract orders\nthe E.164 check after the agent/published checks, so it runs in the\nservice with a machine-readable reason.", + "properties": { + "agent_id": { + "title": "Agent Id", + "type": "string" + }, + "phone_number_id": { + "description": "The team-owned number to dial from (twilio provider only).", + "title": "Phone Number Id", + "type": "string" + }, + "to_number": { + "description": "Destination in E.164, e.g. +14155550123.", + "title": "To Number", + "type": "string" + }, + "dynamic_variables": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + }, + "maxProperties": 50, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dynamic Variables" + }, + "overrides": { + "anyOf": [ + { + "$ref": "#/components/schemas/AgentSessionOverridesPayload" + }, + { + "type": "null" + } + ], + "default": null + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/JsonValue" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + } + }, + "required": [ + "agent_id", + "phone_number_id", + "to_number" + ], + "title": "PhoneCallCreatePayload", + "type": "object" } } }, diff --git a/docs.json b/docs.json index 1d5dd88..210715f 100644 --- a/docs.json +++ b/docs.json @@ -119,6 +119,7 @@ "agents/telephony/phone-numbers", "agents/telephony/byo-sip", "agents/telephony/inbound-calls", + "agents/telephony/outbound-calls", "agents/telephony/transfers" ] }, @@ -353,6 +354,13 @@ "api-reference/endpoint/agent/update-phone-number", "api-reference/endpoint/agent/release-phone-number" ] + }, + { + "group": "Phone Calls", + "icon": "phone-arrow-up-right", + "pages": [ + "api-reference/endpoint/agent/create-phone-call" + ] } ] },