{"openapi":"3.1.0","info":{"title":"API Reference","version":"1.0.0"},"paths":{"/v1/agents":{"get":{"operationId":"list","summary":"List Agents","description":"List voice agents owned by the caller. Cursor-paginated: omit\n`cursor` for the first page; walk pages while `has_more` is true\n(default page size 50, max 200).","tags":["subpackage_agent"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of voice agents.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create Agent","description":"Create a voice agent.","tags":["subpackage_agent"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentRequest"}}}}}},"/v1/agents/voices":{"get":{"operationId":"list-agent-voices","summary":"List Agent Voices","description":"List the curated voice catalogue available for voice agents.\nMatches the `ai-api-agents` VMS scope one-for-one, so the same\nslug set is accepted by POST/PATCH /v1/agents. Personal\n(cloned) voices are NOT included — they stay on\n`GET /v1/voices`. The JSON layout intentionally mirrors the\nTTS `/v1/voices` shape so a single voice picker can consume both\nendpoints. Returns the full set in a\nsingle response: bounded by the curated agent voice catalogue, so\nthis list is intentionally not paginated.\n","tags":["subpackage_agent"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The curated agent voice catalogue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentVoicesResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}":{"delete":{"operationId":"delete","summary":"Delete Agent","description":"Delete a voice agent. Conversations and attached tools remain. The agent's tests are deleted with it; their run history is retained.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get","summary":"Get Agent","description":"Retrieve a voice agent by ID.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update Agent","description":"Update a voice agent. Only fields present on the request body are changed.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentRequest"}}}}}},"/v1/agents/{agent_id}/widget-config":{"get":{"operationId":"get-widget-config","summary":"Get Agent Widget Config","description":"Return the embed-widget appearance config for an agent. Works\nunauthenticated for public agents; the body is cosmetic only.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The agent's widget configuration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WidgetConfig"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/flow/schema":{"get":{"operationId":"get-schema","summary":"Get Flow Graph Schema","description":"Return the JSON Schema describing the flow graph node taxonomy.\nUnauthenticated; flow editors fetch it to validate graphs client-side.\n","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A JSON Schema document for the flow graph.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent_flow_getSchema_Response_200"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/flow/templates":{"get":{"operationId":"list-templates","summary":"List Flow Templates","description":"List the reusable flow templates available to the workspace.\nCursor-paginated: omit `cursor` for the first page; walk pages\nwhile `has_more` is true (default page size 50, max 200).","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The available flow templates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListFlowTemplatesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create-template","summary":"Create Flow Template","description":"Create a reusable flow template from a graph.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created flow template.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplate"}}}},"400":{"description":"Flow validation failed (or the request body was undecodable). The\nstandard `Error` envelope plus an `issues` array locating each problem\nfor the editor. See the `FlowValidationError` schema.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowValidationError"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlowTemplateRequest"}}}}}},"/v1/agents/flow/templates/{flow_template_id}":{"delete":{"operationId":"delete-template","summary":"Delete Flow Template","description":"Delete a flow template.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"flow_template_id","in":"path","description":"Flow template id (prefixed external id, `tmpl_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Template deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get-template","summary":"Get Flow Template","description":"Retrieve a flow template by id.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"flow_template_id","in":"path","description":"Flow template id (prefixed external id, `tmpl_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested flow template.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplate"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"update-template","summary":"Update Flow Template","description":"Replace a flow template. The whole template is replaced, not patched field-by-field.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"flow_template_id","in":"path","description":"Flow template id (prefixed external id, `tmpl_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated flow template.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowTemplate"}}}},"400":{"description":"Flow validation failed (or the request body was undecodable). The\nstandard `Error` envelope plus an `issues` array locating each problem\nfor the editor. See the `FlowValidationError` schema.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowValidationError"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlowTemplateRequest"}}}}}},"/v1/agents/flow/templates/{flow_template_id}/clone":{"post":{"operationId":"clone-template","summary":"Clone Flow Template","description":"Clone a flow template onto an agent as a new draft graph.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"flow_template_id","in":"path","description":"Flow template id (prefixed external id, `tmpl_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The agent's new draft graph.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowGraph"}}}},"400":{"description":"Flow validation failed (or the request body was undecodable). The\nstandard `Error` envelope plus an `issues` array locating each problem\nfor the editor. See the `FlowValidationError` schema.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowValidationError"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneFlowTemplateRequest"}}}}}},"/v1/agents/{agent_id}/evaluation-config":{"get":{"operationId":"get-evaluation-config","summary":"Get Evaluation Config","description":"Retrieve the agent's post-call evaluation criteria + data-collection config.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The evaluation config for the agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluationConfig"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"update-evaluation-config","summary":"Update Evaluation Config","description":"Replace the agent's evaluation criteria + data-collection fields.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated evaluation config.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluationConfig"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEvaluationConfigRequest"}}}}}},"/v1/agents/{agent_id}/flow":{"get":{"operationId":"get-flow","summary":"Get Agent Flow","description":"Return the agent's flow graph: the current draft (if any), the\nactive published graph (if any), and the version history.\n","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The draft graph, active graph, and version history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetFlowResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"update-flow","summary":"Update Agent Flow Draft","description":"Replace the agent's draft flow graph. The graph is validated\nbefore it is stored; publish it separately to make it active.\n","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The stored draft graph.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowGraph"}}}},"400":{"description":"Flow validation failed (or the request body was undecodable). The\nstandard `Error` envelope plus an `issues` array locating each problem\nfor the editor. See the `FlowValidationError` schema.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowValidationError"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutFlowRequest"}}}}}},"/v1/agents/{agent_id}/flow/deactivate":{"post":{"operationId":"deactivate","summary":"Deactivate Agent Flow","description":"Deactivate the agent's published flow so the agent runs the synthesized default flow.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Flow deactivated.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/flow/draft":{"delete":{"operationId":"discard-draft","summary":"Discard Agent Flow Draft","description":"Discard the agent's unpublished draft flow graph.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Draft discarded.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/flow/publish":{"post":{"operationId":"publish","summary":"Publish Agent Flow","description":"Publish the agent's draft graph as a new active flow version.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The newly published flow version.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowVersion"}}}},"400":{"description":"Flow validation failed (or the request body was undecodable). The\nstandard `Error` envelope plus an `issues` array locating each problem\nfor the editor. See the `FlowValidationError` schema.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowValidationError"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishFlowRequest"}}}}}},"/v1/agents/{agent_id}/flow/rollback":{"post":{"operationId":"rollback","summary":"Roll Back Agent Flow","description":"Publish a prior flow version as the active graph.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The flow version that is now active.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowVersion"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RollbackFlowRequest"}}}}}},"/v1/agents/{agent_id}/flow/versions":{"get":{"operationId":"list-versions","summary":"List Agent Flow Versions","description":"List every published flow version for the agent, newest first.\nCursor-paginated: omit `cursor` for the first page; walk pages\nwhile `has_more` is true (default page size 50, max 200).","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The agent's flow version history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListFlowVersionsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/flow/versions/{version_id}":{"get":{"operationId":"get-version","summary":"Get Agent Flow Version","description":"Return the full flow graph for a specific published version.","tags":["subpackage_agent.subpackage_agent/flow"],"parameters":[{"name":"agent_id","in":"path","description":"Prefixed agent id.","required":true,"schema":{"type":"string"}},{"name":"version_id","in":"path","description":"Prefixed flow version id (`fver_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested flow version's graph.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowGraph"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/variables":{"get":{"operationId":"get-dynamic-variables","summary":"Get Dynamic Variables","description":"Retrieve the agent's customer-scope dynamic variables and the read-only\ncatalogue of reserved `system__*` keys. The system variables list is\nprovided so editor UIs can render the reference list without maintaining\na client-side copy of the catalogue.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The agent's variable catalogue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDynamicVariablesResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"update-dynamic-variables","summary":"Update Dynamic Variables","description":"Replace the agent's customer-scope dynamic variable definitions.\nThe supplied list overwrites the stored list wholesale (same\nsemantics as `updateEvaluationConfig`). Pass an empty array to\nclear all variables. Up to 20 variables per agent. Keys must\nmatch `[a-zA-Z0-9_]+` and must not start with the reserved\n`system__` prefix.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated variable catalogue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDynamicVariablesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDynamicVariablesRequest"}}}}}},"/v1/agents/conversations":{"get":{"operationId":"list","summary":"List Conversations","description":"List conversations owned by the caller, ordered by most recent.\nCursor-paginated: omit `cursor` to fetch the first page; pass the\nprevious response's `next_cursor` back to fetch the next page.\nWalk pages while `has_more` is true.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"agent_id","in":"query","description":"Filter to conversations for this agent.","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by conversation status.","required":false,"schema":{"$ref":"#/components/schemas/ConversationStatus"}},{"name":"transport","in":"query","description":"Filter by transport.","required":false,"schema":{"$ref":"#/components/schemas/ConversationTransport"}},{"name":"caller_identity","in":"query","description":"Filter by caller identity.","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Free-text search across conversation content.","required":false,"schema":{"type":"string"}},{"name":"started_after","in":"query","description":"Only conversations started at or after this RFC 3339 timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"started_before","in":"query","description":"Only conversations started at or before this RFC 3339 timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"duration_min_ms","in":"query","description":"Minimum conversation duration in milliseconds.","required":false,"schema":{"type":"integer"}},{"name":"duration_max_ms","in":"query","description":"Maximum conversation duration in milliseconds.","required":false,"schema":{"type":"integer"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of conversations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListConversationsResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/recent-callees":{"get":{"operationId":"recent-callees","summary":"List recent callees","description":"Distinct phone numbers the caller's workspace has dialled on\noutbound calls, ordered by most recent. Feeds the batch-calls\ncomposer's \"Suggested from history\" surface. Cursor-paginated:\nomit `cursor` to fetch the first page. Default page size is 50\nand max is 200. Walk pages while `has_more` is true.\n","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Recent callees for the caller's workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRecentCalleesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/stats":{"get":{"operationId":"stats","summary":"Conversation stats","description":"Aggregated counts and averages over the caller's conversations, scoped by the same filters as the list endpoint.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"agent_id","in":"query","description":"Filter to conversations for this agent.","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by conversation status.","required":false,"schema":{"$ref":"#/components/schemas/ConversationStatus"}},{"name":"transport","in":"query","description":"Filter by transport.","required":false,"schema":{"$ref":"#/components/schemas/ConversationTransport"}},{"name":"caller_identity","in":"query","description":"Filter by caller identity.","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Free-text search across conversation content.","required":false,"schema":{"type":"string"}},{"name":"started_after","in":"query","description":"Only conversations started at or after this RFC 3339 timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"started_before","in":"query","description":"Only conversations started at or before this RFC 3339 timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"duration_min_ms","in":"query","description":"Minimum conversation duration in milliseconds.","required":false,"schema":{"type":"integer"}},{"name":"duration_max_ms","in":"query","description":"Maximum conversation duration in milliseconds.","required":false,"schema":{"type":"integer"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stats for the matched conversations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationStats"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}":{"get":{"operationId":"get","summary":"Get Conversation","description":"Retrieve a conversation by ID.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/end":{"post":{"operationId":"force-end","summary":"Force-end conversation","description":"Force-terminate an ongoing conversation. Idempotent: a\nconversation that has already ended returns 204 the same as a\nsuccessful first-time termination. Requires an `owner` or `admin`\nof the workspace — the same gate as take-over.\n","tags":["subpackage_agent.subpackage_agent/admin"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Conversation ended.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/evaluations":{"get":{"operationId":"list-evaluations","summary":"List Evaluations","description":"Retrieve post-call evaluation results for a conversation.\nCursor-paginated: omit `cursor` for the first page; walk pages while\n`has_more` is true (default page size 50, max 200).","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The evaluations for the conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListEvaluationsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/memories":{"get":{"operationId":"list-memories","summary":"List Conversation Memories","description":"List memories extracted from a specific conversation.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Memories written during this conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMemoriesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/messages":{"get":{"operationId":"list-messages","summary":"List Messages","description":"Retrieve the transcript for a conversation in started_at order\n(oldest first). Cursor-paginated: omit `cursor` to fetch the\nfirst page. Default page size is 50 and max is 200. Walk pages\nwhile `has_more` is true.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The messages for the conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMessagesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/recording":{"get":{"operationId":"stream-recording","summary":"Stream Recording","description":"Proxy the GCS-stored audio recording for a conversation through\nthe Cloud Run service identity. Returns OGG/Opus bytes (LiveKit\nroom-composite egress default). The response is streamed so a\nlong recording does not buffer in memory; `<audio src>` consumers\ncan seek directly. Only present when the agent had\n`save_audio_recording` enabled at session start.\n","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The recorded audio.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/retrieval-log":{"get":{"operationId":"list-retrieval-log","summary":"List Retrieval Log","description":"Per-conversation retrieval log, newest first — one row per\n`search_knowledge` invocation made during the call. Each entry\nrecords the query, ranked chunks (denormalised so deletions\ndon't render history unreadable), `limit`, and hit count.\nPowers the Retrieval panel on the conversation detail view.\nCursor-paginated: omit `cursor` to fetch the first page.\nDefault page size is 50 and max is 200. Walk pages while\n`has_more` is true.\n","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The retrieval log entries for the conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRetrievalLogsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/shadow-token":{"post":{"operationId":"shadow-token","summary":"Mint shadow-call token","description":"Mint a listen-only realtime access token so an authorized observer\ncan join an ongoing voice-agent conversation as a hidden\nparticipant. Any `member`, `admin`, or `owner` of the workspace\nthe conversation belongs to may listen in — it is read-only\nobservation. The token cannot publish audio or data; the observer\nis invisible to the caller and the agent. Speechify support\nengineers reach this endpoint the same way as any other observer\n— by being granted a role on the customer's workspace (typically\nunder an NDA-backed support arrangement).\n","tags":["subpackage_agent.subpackage_agent/admin"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Shadow-call connection details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowConversationResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/webhook-deliveries":{"get":{"operationId":"list-webhook-deliveries","summary":"List Webhook Deliveries","description":"List post-call webhook delivery attempts for a conversation,\nnewest first. Rows appear once the call ends and the post-call\nwebhook has been dispatched to the agent's configured URL. One\nrow per\n`(conversation, webhook-url)`, updated in place across retries.\nEach row includes the exact request payload and signed headers\nSpeechify sent (`request_body`, `request_headers`) and the\nresponse your server returned (`last_status_code`,\n`last_response_body`, `last_response_headers`), so you can verify\nwhat was delivered and debug a failing endpoint.\nCursor-paginated: omit `cursor` to fetch the first page.\nDefault page size is 50 and max is 200. Walk pages while\n`has_more` is true.\n","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The post-call webhook deliveries for the conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookDeliveriesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/conversations":{"post":{"operationId":"create-conversation","summary":"Create Conversation","description":"Start a new voice conversation with the agent. Returns a realtime\nvoice session + short-lived client token so the caller can\nconnect the audio pipeline directly. The agent is dispatched\nserver-side; no additional client action required.\n\nPass `dynamic_variables` to supply per-session values that override\nthe agent's stored variable defaults for this one conversation.\nKeys in the `system__` namespace are rejected at this boundary.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created conversation with its realtime session token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}}}}},"/v1/agents/{agent_id}/sessions":{"post":{"operationId":"create-session","summary":"Create Session","description":"Mint a realtime voice session for the given agent. Widget-friendly\ncounterpart to `createConversation` — same response shape, dual\nauthentication:\n\n* **Authenticated (Bearer)**: works for any agent the caller\n  owns. Typical server-to-server flow where the embedding\n  site's backend mints a token and hands it to the browser so\n  the API key never reaches the client.\n* **Unauthenticated**: works only when `agent.is_public = true`\n  AND the request's `Origin` header matches `agent.allowed_origins`\n  (or that list is empty). When `agent.hostname_allowlist` is\n  non-empty, the `Origin` hostname must additionally be a\n  member of that list. Used directly by the\n  `<speechify-agent>` web component.\n\nResponds with the same `CreateConversationResponse` as\n`createConversation`.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created session with its realtime token + URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSessionRequest"}}}}}},"/v1/agents/knowledge-bases":{"get":{"operationId":"list","summary":"List Knowledge Bases","description":"List knowledge bases owned by the caller. Cursor-paginated:\nomit `cursor` to fetch the first page. The default page size is\n50 and the max is 200; values outside that range are clamped.\nWalk pages while `has_more` is true.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The knowledge bases for the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListKnowledgeBasesResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create Knowledge Base","description":"Create a new knowledge base.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created knowledge base.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBase"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKnowledgeBaseRequest"}}}}}},"/v1/agents/knowledge-bases/search":{"post":{"operationId":"search","summary":"Search Knowledge Bases","description":"Semantic search across a caller-owned list of knowledge bases.\nReturns ranked chunks with source filename and a cosine-similarity\nscore. Limited to 50 results per request.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Ranked search hits across the selected knowledge bases.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchKnowledgeBasesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchKnowledgeBasesRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}":{"delete":{"operationId":"delete","summary":"Delete Knowledge Base","description":"Soft-delete a knowledge base. Documents and chunks are cascaded.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Knowledge base deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get","summary":"Get Knowledge Base","description":"Retrieve a knowledge base by ID.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested knowledge base.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBase"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update Knowledge Base","description":"Update a knowledge base.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated knowledge base.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBase"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKnowledgeBaseRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents":{"get":{"operationId":"list-documents","summary":"List Knowledge Base Documents","description":"List documents ingested into a knowledge base. Cursor-paginated:\nomit `cursor` to fetch the first page. Default page size is 50\nand max is 200. Walk pages while `has_more` is true.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"folder_id","in":"query","description":"Folder filter: omit for root-level documents, pass `all` for\nevery document in the KB, or a folder id to scope to that\nfolder.\n","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Substring match on filename and source_url.","required":false,"schema":{"type":"string"}},{"name":"source_kind","in":"query","description":"Comma-separated source kinds (file|url|text).","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The documents in the knowledge base.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListKnowledgeBaseDocumentsResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"upload-document","summary":"Upload Knowledge Base Document","description":"Upload a document (PDF, plain text, markdown, or HTML) to a\nknowledge base. The document is extracted, chunked, embedded, and\nindexed synchronously; expect a few seconds per MB of input.\nMaximum 10 MB per upload.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The ingested document record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseDocument"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body exceeded a per-endpoint size limit (e.g. KB\ndocument upload cap, batch-call CSV cap, audio-asset WAV cap).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/batch":{"delete":{"operationId":"batch-delete-documents","summary":"Batch Delete Documents","description":"Delete multiple documents in a single transaction. All ids\nmust belong to the supplied knowledge base; mismatches fail\nthe request with 400 before any rows are touched. Capped at\n200 ids per call.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Documents deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDeleteDocumentsRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/batch/move":{"patch":{"operationId":"batch-move-documents","summary":"Batch Move Documents","description":"Move multiple documents into a folder in a single transaction.\nPass `folder_id: null` to move every doc to root. Capped at\n200 ids per call.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Documents moved.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchMoveDocumentsRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/crawl":{"post":{"operationId":"create-crawl-import","summary":"Create Crawl Import","description":"Kick off an async website crawl. Returns 202 with the import\njob row; client polls `GET /{kb_id}/imports` for progress.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"Import job queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJob"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCrawlImportRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/sitemap":{"post":{"operationId":"create-sitemap-import","summary":"Create Sitemap Import","description":"Kick off an async sitemap import. Returns 202 with the import\njob row; client polls `GET /{kb_id}/imports` for progress.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"Import job queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJob"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSitemapImportRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/text":{"post":{"operationId":"create-text-document","summary":"Create Text Document","description":"Create a document from inline pasted text. Content is chunked,\nembedded, and indexed synchronously.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created document.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseDocument"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTextDocumentRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/url":{"post":{"operationId":"create-url-document","summary":"Create URL Document","description":"Fetch a URL via Firecrawl and ingest the rendered content as a\ndocument. The fetch happens synchronously; expect a few\nseconds per page. Use the sitemap / crawl endpoints for\nmulti-page imports.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"The document was accepted and is being fetched + embedded\nasynchronously. The returned row is a placeholder with\n`status: fetching`; poll the document until it reaches\n`ready` or `failed`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseDocument"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateURLDocumentRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/urls":{"post":{"operationId":"create-url-batch-import","summary":"Create Multi-URL Import","description":"Kick off an async multi-URL import. Accepts 1..N URLs in a\nsingle job (capped per-deployment, default 50) and runs the\nsame per-URL pipeline as the sitemap importer. Returns 202 with\nthe import job row; client polls `GET /{kb_id}/imports` for\nprogress.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"Import job queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJob"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateURLBatchImportRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/{document_id}":{"delete":{"operationId":"delete-document","summary":"Delete Knowledge Base Document","description":"Delete a document and all its chunks.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"document_id","in":"path","description":"Knowledge-base document id (prefixed external id, `doc_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Document deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get-document","summary":"Get Knowledge Base Document","description":"Retrieve a document by ID.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"document_id","in":"path","description":"Knowledge-base document id (prefixed external id, `doc_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The document record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseDocumentDetail"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update-document","summary":"Update Knowledge Base Document","description":"Update a document. Currently supports moving the document\nbetween folders via `folder_id`.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"document_id","in":"path","description":"Knowledge-base document id (prefixed external id, `doc_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Document updated.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"folder_id":{"type":["string","null"],"description":"Destination folder. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null moves the\ndocument to the knowledge base root.\n"}}}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/{document_id}/chunks":{"get":{"operationId":"list-chunks","summary":"List Knowledge Base Chunks","description":"List the chunks for a document. Cursor-paginated: omit `cursor`\nto fetch the first page. Default page size is 50 and max is 200.\nWalk pages while `has_more` is true.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"document_id","in":"path","description":"Knowledge-base document id (prefixed external id, `doc_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The chunks for the document.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListKnowledgeBaseChunksResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/{document_id}/refresh-config":{"patch":{"operationId":"update-refresh-config","summary":"Update Refresh Config","description":"Update the per-document auto-refresh state. Only meaningful\nfor url-sourced documents; file and text rows reject the\nrequest.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"document_id","in":"path","description":"Knowledge-base document id (prefixed external id, `doc_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated refresh config.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshConfig"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRefreshConfigRequest"}}}}},"get":{"operationId":"get-refresh-config","summary":"Get Refresh Config","description":"Read the per-document auto-refresh state.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"document_id","in":"path","description":"Knowledge-base document id (prefixed external id, `doc_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The document's refresh config.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshConfig"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/knowledge-bases/{kb_id}/documents/{document_id}/refresh-history":{"get":{"operationId":"list-refresh-history","summary":"List Refresh History","description":"List auto-refresh attempts for a document, newest first.\nCursor-paginated: omit `cursor` to fetch the first page. Default\npage size is 50 and max is 200. Walk pages while `has_more` is\ntrue.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"document_id","in":"path","description":"Knowledge-base document id (prefixed external id, `doc_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Recent refresh attempts for the document.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRefreshHistoryResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/knowledge-bases/{kb_id}/folders":{"get":{"operationId":"list-folders","summary":"List Folders","description":"List folders inside a knowledge base. Root-level folders have\n`parent_folder_id: null`. Cursor-paginated: omit `cursor` to\nfetch the first page. Default page size is 50 and max is 200.\nBuild the folder tree from `parent_folder_id`, so consumers\nshould walk every page until `has_more` is `false` before\nrendering the tree.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Folders in the knowledge base.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListKnowledgeBaseFoldersResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create-folder","summary":"Create Folder","description":"Create a folder inside a knowledge base.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseFolder"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFolderRequest"}}}}}},"/v1/agents/knowledge-bases/{kb_id}/folders/{folder_id}":{"delete":{"operationId":"delete-folder","summary":"Delete Folder","description":"Delete a folder. By default a folder that still contains\ndocuments or sub-folders is refused with `409` - pass\n`?force=true` to delete it anyway, which recursively moves its\ndocuments to root and removes its sub-folders.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"folder_id","in":"path","description":"Knowledge-base folder id (prefixed external id, `kfolder_...`).","required":true,"schema":{"type":"string"}},{"name":"force","in":"query","description":"When true, delete the folder even if it still contains documents or sub-folders; documents are moved to root and sub-folders are removed.","required":false,"schema":{"type":"boolean"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Folder deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update-folder","summary":"Update Folder","description":"Update a folder. Pass `parent_folder_id: null` to move to\nroot; omit the field to leave it unchanged.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"folder_id","in":"path","description":"Knowledge-base folder id (prefixed external id, `kfolder_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseFolder"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFolderRequest"}}}}},"get":{"operationId":"get-folder","summary":"Get Folder","description":"Fetch a single knowledge-base folder by id.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"folder_id","in":"path","description":"Knowledge-base folder id (prefixed external id, `kfolder_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseFolder"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/knowledge-bases/{kb_id}/imports":{"get":{"operationId":"list-import-jobs","summary":"List Import Jobs","description":"List import jobs (sitemap / crawl / refresh) for a knowledge\nbase, newest first. Cursor-paginated: omit `cursor` to fetch the\nfirst page. Default page size is 50 and max is 200. Walk pages\nwhile `has_more` is true.","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The import jobs for the knowledge base.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListImportJobsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/knowledge-bases/{kb_id}/imports/{import_id}":{"get":{"operationId":"get-import-job","summary":"Get Import Job","description":"Retrieve a single import job by ID. Poll this endpoint until\n`status` reaches a terminal state (`completed` / `failed` /\n`cancelled`).\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"import_id","in":"path","description":"Knowledge-base import job id (prefixed external id, `import_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The import job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJob"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/knowledge-bases/{kb_id}/imports/{import_id}/cancel":{"post":{"operationId":"cancel-import-job","summary":"Cancel Import Job","description":"Cancel a non-terminal import job. Returns `200` with the\ncancelled job so callers see its new `status` without a follow-up\n`GET` — the same success shape as the other job-cancel verbs\n(`cancel` on batch calls, test runs, and suite runs). Returns 404\nwhen the job is already terminal (completed / failed / cancelled),\nunknown, or its kb_id does not match the `{kb_id}` path segment.\n","tags":["subpackage_agent.subpackage_agent/knowledgeBases"],"parameters":[{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"import_id","in":"path","description":"Knowledge-base import job id (prefixed external id, `import_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The cancelled import job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJob"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/knowledge-bases":{"get":{"operationId":"list-agent-knowledge-bases","summary":"List Agent Knowledge Bases","description":"List knowledge bases attached to an agent. Cursor-paginated: omit\n`cursor` for the first page; walk pages while `has_more` is true\n(default page size 50, max 200).\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The knowledge bases attached to the agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachedKnowledgeBasesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/knowledge-bases/{kb_id}":{"delete":{"operationId":"detach-knowledge-base","summary":"Detach Agent Knowledge Base","description":"Detach a knowledge base from an agent.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Knowledge base detached.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"attach-knowledge-base","summary":"Attach Agent Knowledge Base","description":"Attach a knowledge base to an agent. The `search_knowledge` tool\nis auto-registered on the next conversation and can only query the\nattached knowledge bases.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"kb_id","in":"path","description":"Knowledge base id (prefixed external id, `kb_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Knowledge base attached.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/tools":{"get":{"operationId":"list-tools","summary":"List Agent Tools","description":"List everything this agent can do: built-in capabilities and\nattached external tool definitions (webhook / client / MCP) in\none mixed-kind list. Each item carries its resolved config inline.\nCursor-paginated: omit `cursor` for the first page; walk pages while\n`has_more` is true (default page size 50, max 200).\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The agent's tools.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentToolsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create-tool","summary":"Create Agent Tool","description":"Add a tool to the agent. With `kind=builtin` this creates a\nper-agent built-in instance (e.g. `end_call`, `play_audio`); the\n`builtin` capability name comes from `config.builtin`. With\n`kind=webhook`, `client`, or `mcp` this atomically creates a\nworkspace tool definition AND attaches it to the agent in one\ncall. To attach a definition that already exists, use\n`PUT /v1/agents/{agent_id}/tools/{tool_id}` instead.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created tool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTool"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentToolRequest"}}}}}},"/v1/agents/{agent_id}/tools/{tool_id}":{"get":{"operationId":"get-tool","summary":"Get Agent Tool","description":"Fetch one of the agent's tools by its id (built-in or attached definition).","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"tool_id","in":"path","description":"Tool id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The tool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTool"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"attach-tool","summary":"Attach Tool","description":"Attach an existing workspace tool definition (webhook / client /\nMCP) to the agent by its definition id. Idempotent. To create and\nattach in one step, POST to `/v1/agents/{agent_id}/tools` instead.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"tool_id","in":"path","description":"Tool id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Tool attached.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update-tool","summary":"Update Agent Tool","description":"Update one of the agent's tools. For a built-in, every field\napplies. For an attached external tool, only `enabled` is\neditable here — its shared config/name is edited on the\ndefinition (`PATCH /v1/agents/tool-definitions/{tool_definition_id}`), since the\ndefinition is referenced live by every agent it is attached to;\nattempting a shared-config edit here returns `tool_config_shared`.\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"tool_id","in":"path","description":"Tool id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated tool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTool"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentToolRequest"}}}}},"delete":{"operationId":"delete-tool","summary":"Delete Agent Tool","description":"Remove a tool from the agent. A built-in instance is deleted; an\nattached external tool is detached (the workspace definition\nsurvives and stays attachable elsewhere).\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"tool_id","in":"path","description":"Tool id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Tool removed.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tool-capabilities":{"get":{"operationId":"list-tool-capabilities","summary":"List Tool Capabilities","description":"Read-only catalogue of every built-in tool capability the agent\nruntime supports (the names usable as `config.builtin` when adding a\n`kind=builtin` tool to an agent). Fetch this at runtime rather\nthan maintaining a parallel client-side list; the server is the\nsingle source of truth for the label and description text a\ncustomer sees in the capability picker. Returns\nthe full set in a single response: bounded by the platform's\nbuilt-in tool-capability registry, so this list is intentionally\nnot paginated.\n","tags":["subpackage_agent"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The catalogue of registered built-in capabilities.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSystemBuiltinsResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tool-definitions":{"get":{"operationId":"list","summary":"List Tools","description":"List tools in the caller's workspace, most recently updated\nfirst. Cursor-paginated: omit `cursor` to fetch the first page.\nDefault page size is 50 and max is 200. Walk pages while\n`has_more` is true.","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of tools.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListToolsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create Tool","description":"Create a tool. For webhook tools, the response includes the HMAC\n`webhook_secret` exactly once — store it immediately; subsequent\nreads return a masked placeholder.\n","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created tool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tool"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateToolRequest"}}}}}},"/v1/agents/tool-definitions/{tool_definition_id}":{"get":{"operationId":"get","summary":"Get Tool","description":"Retrieve a tool by ID. Webhook secrets are always masked here.","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"tool_definition_id","in":"path","description":"Tool definition id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested tool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tool"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update Tool","description":"Update a tool. Tool kind is immutable — create a new tool to change it.","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"tool_definition_id","in":"path","description":"Tool definition id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated tool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tool"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateToolRequest"}}}}},"delete":{"operationId":"delete","summary":"Delete Tool","description":"Delete a tool. Agents that had it attached get a soft-detach.","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"tool_definition_id","in":"path","description":"Tool definition id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Tool deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tool-definitions/{tool_definition_id}/attached-agents":{"get":{"operationId":"list-attached-agents","summary":"List Tool Attached Agents","description":"List the agents in the caller's workspace that currently have\nthis tool attached. Useful before deleting a tool, to surface\nwhich agents will lose access. Soft-deleted agents are filtered\nout. Cursor-paginated: omit `cursor` for the first page; walk\npages while `has_more` is true (default page size 50, max 200).","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"tool_definition_id","in":"path","description":"Tool definition id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agents in the caller's workspace attached to the tool.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListToolAttachedAgentsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tool-definitions/{tool_definition_id}/rotate-secret":{"post":{"operationId":"rotate-secret","summary":"Rotate Tool Webhook Secret","description":"Rotate the HMAC signing secret on a webhook tool. The tool id\nis preserved so attached agents keep working; only the secret\nrolls. The new plaintext is returned on `webhook_secret`\nexactly once — store it immediately, subsequent reads always\nreturn the masked placeholder. The previous secret is\ninvalidated immediately on success.\n","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"tool_definition_id","in":"path","description":"Tool definition id (prefixed external id, `tool_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The tool with its newly-rotated webhook_secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tool"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tool-definitions/test-mcp-connection":{"post":{"operationId":"test-mcp-connection","summary":"Test MCP Connection","description":"Probe a customer-supplied MCP server config without persisting\nanything. The server opens the configured transport, runs the\n`initialize` + `list_tools` handshake, and returns either the\ndiscovered tool catalogue or a structured error string. Pass\n`tool_id` from the edit-form flow when the auth payload carries\n`_set` markers but no plaintext, so the server can hydrate the\nstored secret from the encrypted column before probing.\n","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Probe result. The 200 envelope is used for both success and\nstructured failure — inspect `error` to disambiguate. Network\nand validation failures never bubble up as non-2xx so a\nclient can render them inline next to the form.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPProbeResult"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestMCPConnectionRequest"}}}}}},"/v1/agents/tool-definitions/test-webhook-connection":{"post":{"operationId":"test-webhook-connection","summary":"Test Webhook Connection","description":"Probe a customer-supplied webhook tool config without persisting\nanything. The server fires the exact request shape used on a real\ninvocation — same JSON body, same HMAC-SHA256\nsignature — with an empty argument set, and reports the\nendpoint's status code, latency, and a truncated response body,\nor a transport-level failure reason. The probe carries a\n`Speechify-Webhook-Test: true` header so a careful endpoint\ncan recognise the test and skip its real side effect. Pass\n`tool_id` from the edit-form flow so the server signs the probe\nwith the tool's stored HMAC secret.\n","tags":["subpackage_agent.subpackage_agent/toolDefinitions"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Probe result. The 200 envelope is used for both success and\nstructured failure — inspect `error` to disambiguate. A\nnon-2xx response from the endpoint is NOT an `error`: it\npopulates `status_code` / `response_body` with `ok=false`.\nTransport and validation failures never bubble up as non-2xx\nso a client can render them inline next to the form.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookProbeResult"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestWebhookConnectionRequest"}}}}}},"/v1/agents/tests":{"get":{"operationId":"list-all-tests","summary":"List Tests","description":"Workspace-wide list of tests across every agent the caller owns.\nSupports filters (agent, type, last-run status, folder), full-text\nsearch on name/description, and cursor pagination. Each row carries\nits newest run and attached agent IDs so the list renders without\nN+1 round-trips. Walk pages while `has_more` is true.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"agent_id","in":"query","description":"Comma-separated agent IDs to filter on.","required":false,"schema":{"type":"string"}},{"name":"type","in":"query","description":"Comma-separated test types (reply|tool|simulation).","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Comma-separated last-run lifecycle statuses to filter on\n(pending, running, completed, failed, cancelled).\n","required":false,"schema":{"type":"string"}},{"name":"verdict","in":"query","description":"Comma-separated last-run verdicts to filter on (passed, failed).\nANDed with the `status` filter when both are present.\n","required":false,"schema":{"type":"string"}},{"name":"folder_id","in":"query","description":"Folder ID to filter on, or \"root\" for unfiled tests.","required":false,"schema":{"type":"string"}},{"name":"updated_after","in":"query","description":"Only return tests updated after this RFC3339 timestamp.","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Substring match on name or description.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTestsResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/folders":{"get":{"operationId":"list-test-folders","summary":"List Test Folders","description":"List every test folder the caller owns. Flat list; build the tree\nclient-side. Cursor-paginated: omit `cursor` for the first page;\nwalk pages while `has_more` is true (default page size 50, max 200).","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Folder list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentTestFoldersResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create-test-folder","summary":"Create Test Folder","description":"Create a test folder. Max depth is 3.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"Created folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestFolder"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentTestFolderRequest"}}}}}},"/v1/agents/tests/folders/{test_folder_id}":{"delete":{"operationId":"delete-test-folder","summary":"Delete Test Folder","description":"Soft-delete a folder. Child tests drop back to root.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_folder_id","in":"path","description":"Agent test folder id (prefixed external id, `folder_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update-test-folder","summary":"Update Test Folder","description":"Rename or reparent a test folder. Cycles are rejected.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_folder_id","in":"path","description":"Agent test folder id (prefixed external id, `folder_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestFolder"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentTestFolderRequest"}}}}},"get":{"operationId":"get-test-folder","summary":"Get Test Folder","description":"Fetch a single agent-test folder by id.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_folder_id","in":"path","description":"Agent test folder id (prefixed external id, `folder_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The test folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestFolder"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/runs/batch":{"post":{"operationId":"run-tests-batch","summary":"Run Tests (Batch)","description":"Queue runs for every (test, agent) pair in the body. Entries\nwithout an `agent_id` fan out to every agent the test is\nattached to. Total expanded runs are capped at 100 per call.\nEach entry in the response is a queued run; poll\n`GET /v1/agents/tests/runs/{test_run_id}` for each.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"Runs queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunAgentTestsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBatchRequest"}}}}}},"/v1/agents/tests/runs/{test_run_id}":{"get":{"operationId":"get-test-run","summary":"Get Agent Test Run","description":"Retrieve a single test run by ID. Poll this endpoint until\n`status` reaches a terminal state (`completed`, `failed`, or\n`cancelled`). On `completed`, read `verdict` for the pass/fail\njudgment and `result` for the detail.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_run_id","in":"path","description":"Test run ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The test run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestRun"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/runs/{test_run_id}/cancel":{"post":{"operationId":"cancel-test-run","summary":"Cancel Agent Test Run","description":"Cancel a non-terminal test run. Idempotent on a terminal run\n(`completed` / `failed` / `cancelled`) - the call returns the\nunchanged run.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_run_id","in":"path","description":"Test run ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The (possibly already-terminal) test run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestRun"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/stats":{"get":{"operationId":"get-test-stats","summary":"Get Test Stats","description":"Aggregate pass-rate metrics over the last N days. Returns dense\ndaily buckets (one entry per day, zero-filled) plus totals and a\nper-type breakdown. Powers the header chart on the global tests\npage. Default window is 30 days, max 90.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"window_days","in":"query","description":"Trailing window in days (default 30, max 90).","required":false,"schema":{"type":"integer"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stats payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestStats"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/suite-runs":{"get":{"operationId":"list-suite-runs","summary":"List Suite Runs","description":"List one page of suite runs (test invocations), newest first.\nA suite run groups every test run dispatched by one Run All,\nbatch, or resubmit call. Paginate by passing `cursor` from the\nprevious response.\n","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"agent_id","in":"query","description":"Narrow the list to the suite runs of one agent.","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"One page of suite runs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSuiteRunsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/suite-runs/{suite_run_id}":{"get":{"operationId":"get-suite-run","summary":"Get Suite Run","description":"Retrieve a suite run by ID with its child runs and the derived\naggregate `status`, `verdict`, and progress counts.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"suite_run_id","in":"path","description":"Suite run ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The suite run with its child runs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestSuiteRunWithRuns"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/suite-runs/{suite_run_id}/resubmit":{"post":{"operationId":"resubmit-suite-run","summary":"Resubmit Suite Run","description":"Re-run the failed and errored tests of a suite run as a fresh\nsuite run, linked back to the original via\n`parent_suite_run_id`. Returns 400 when the suite run has no\nfailed or errored tests to re-run.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"suite_run_id","in":"path","description":"Suite run ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"The new suite run and its queued child runs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestSuiteRunWithRuns"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/suite-runs/{suite_run_id}/cancel":{"post":{"operationId":"cancel-suite-run","summary":"Cancel Suite Run","description":"Cancel a suite run: every child run still pending or running is\ncancelled, which makes the suite's derived `status` `cancelled`.\nChild runs that already produced a verdict or errored are left\nuntouched. Idempotent on a terminal suite - returns it unchanged.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"suite_run_id","in":"path","description":"Suite run ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The suite run with its child runs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestSuiteRunWithRuns"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/tests/{test_id}":{"delete":{"operationId":"delete-test","summary":"Delete Agent Test","description":"Delete a test and all its run history.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_id","in":"path","description":"Test ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Test deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get-test","summary":"Get Agent Test","description":"Retrieve a test by ID.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_id","in":"path","description":"Test ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested test.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTest"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update-test","summary":"Update Agent Test","description":"Update a test. Only fields present on the request body are changed.","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_id","in":"path","description":"Test ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated test.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTest"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentTestRequest"}}}}}},"/v1/agents/tests/{test_id}/runs":{"get":{"operationId":"list-test-runs","summary":"List Agent Test Runs","description":"List one page of run history for a test, newest first.\nPaginate by passing `cursor` from the previous response.\n","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_id","in":"path","description":"Test ID.","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Run history for the test.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentTestRunsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"run-test","summary":"Run Agent Test","description":"Enqueue a single run of the test. The returned run starts in\n`queued` status. Poll `GET /v1/agents/tests/runs/{test_run_id}` until the status\nreaches a terminal state (`passed`, `failed`, or `error`).","tags":["subpackage_agent.subpackage_agent/tests"],"parameters":[{"name":"test_id","in":"path","description":"Test ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"The queued run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestRun"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string","description":"Run the test against this agent instead of the test's default agent."}}}}}}}},"/v1/agents/{agent_id}/tests":{"get":{"operationId":"list-tests","summary":"List Agent Tests","description":"List all tests configured for the agent. Each entry includes the\nmost recent run so a client can render pass/fail badges without\nan extra round-trip. Cursor-paginated: omit `cursor` for the first\npage; walk pages while `has_more` is true (default page size 50,\nmax 200).","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent ID.","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tests for the agent with last-run summaries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTestsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create-test","summary":"Create Agent Test","description":"Create a new test for the agent.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created test.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTest"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentTestRequest"}}}}}},"/v1/agents/{agent_id}/tests/runs":{"post":{"operationId":"run-all-tests","summary":"Run All Agent Tests","description":"Enqueue runs for every test on the agent concurrently. Up to 50\ntests are dispatched in one call. Each returned run starts in\n`queued` status; poll `GET /v1/agents/tests/runs/{test_run_id}` for the terminal\nresult.\n\nAn optional request body runs the whole suite against\na proposed config: a `config_override` (prompt / model / tools)\napplied to every test without editing the tests, and/or a\n`flow_version_id` to target a specific flow version instead of\nthe agent's active flow. Omit the body to run against the\nagent's live config and active flow.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"Queued runs for all tests on the agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunAgentTestsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunAllTestsRequest"}}}}}},"/v1/agents/batch-calls":{"get":{"operationId":"list","summary":"List Batch Calls","description":"Returns one page of batch calls for the workspace, newest first.\nPaginate by passing `cursor` from the previous response.\n","tags":["subpackage_agent.subpackage_agent/batchCalls"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBatchCallsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create Batch Call","description":"Dial a list of phone numbers through one of your voice agents in a\nsingle request. Each recipient can receive personalised dynamic\nvariables that your agent prompt references via `{{key}}` placeholders.\nBatches can run immediately or be scheduled up to 30 days in advance.\n\nAccepts `application/json` or `multipart/form-data` (with a CSV file).\nMax 1000 recipients per batch.\n","tags":["subpackage_agent.subpackage_agent/batchCalls"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"A client-generated key (an opaque string, max 255 chars) that makes a\nside-effect POST safe to retry: the server runs the operation exactly\nonce and replays the first response (its status and body) for 24 hours.\nReusing a key with a different request body, or while the first request\nis still in flight, returns `409 idempotency_conflict`. A replayed\nresponse carries the `Idempotent-Replayed: true` header.\n","required":false,"schema":{"type":"string"}}],"responses":{"202":{"description":"Batch accepted for processing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCall"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBatchCallRequest"}}}}}},"/v1/agents/batch-calls/{batch_call_id}":{"get":{"operationId":"get","summary":"Get Batch Call","description":"Returns the batch row plus all recipients so the detail view renders\nwithout a second round-trip.\n","tags":["subpackage_agent.subpackage_agent/batchCalls"],"parameters":[{"name":"batch_call_id","in":"path","description":"Batch call ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetBatchCallResponse"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/batch-calls/{batch_call_id}/cancel":{"post":{"operationId":"cancel","summary":"Cancel Batch Call","description":"Cancels a pending batch before it starts dialing (including one\ndeferred to a future `scheduled_at`). Returns 409 if the batch is\nalready running or completed.\n","tags":["subpackage_agent.subpackage_agent/batchCalls"],"parameters":[{"name":"batch_call_id","in":"path","description":"Batch call ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCall"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/ivr-menus":{"get":{"operationId":"list","summary":"List IVR Menus","description":"List the active IVR menus the caller's workspace has learned.\nOne row per (fingerprint, tenant).\nInvalidated rows and the cross-tenant shared slot are excluded.\nSorted by `last_observed_at` DESC so the freshest IVRs land at\nthe top. Cursor-paginated: omit `cursor` to fetch the first\npage. Default page size is 50 and max is 200. Walk pages while\n`has_more` is true.\n","tags":["subpackage_agent.subpackage_agent/ivrMemory"],"parameters":[{"name":"fingerprint","in":"query","description":"Optional SHA-256 fingerprint hash to narrow the list to one menu.","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of cached IVR menus.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListIVRMenusResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/ivr-menus/{ivr_menu_id}":{"get":{"operationId":"get","summary":"Get IVR Menu","description":"Fetch one menu's full shape. Returns 404 for missing,\nsoft-deleted, or foreign-tenant menus — existence information\nis never leaked across tenants.\n","tags":["subpackage_agent.subpackage_agent/ivrMemory"],"parameters":[{"name":"ivr_menu_id","in":"path","description":"IVR menu ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The IVR menu detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IVRMenu"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update-label","summary":"Update IVR Menu Option Label","description":"Re-label one option in the stored menu_tree, matched on the\nsupplied DTMF value. The label is shown when reviewing the menu\nand is read back to the agent at navigate time to surface the\noption semantically. Unknown DTMF values\nare a no-op (the response echoes the unchanged menu).\n","tags":["subpackage_agent.subpackage_agent/ivrMemory"],"parameters":[{"name":"ivr_menu_id","in":"path","description":"IVR menu ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The refreshed menu shape.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IVRMenu"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIVRMenuLabelRequest"}}}}}},"/v1/agents/ivr-menus/{ivr_menu_id}/invalidate":{"post":{"operationId":"invalidate","summary":"Invalidate IVR Menu","description":"Soft-invalidate the named menu. Future lookups skip it; the\nnext discovery for the same fingerprint replaces it (clearing\nthe invalidation). Idempotent: re-invalidating\nan already-invalidated row returns 404.\n\nReason is optional and is captured in structured logs for\noperator triage. A future audit table may persist it.\n","tags":["subpackage_agent.subpackage_agent/ivrMemory"],"parameters":[{"name":"ivr_menu_id","in":"path","description":"IVR menu ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Menu invalidated.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvalidateIVRMenuRequest"}}}}}},"/v1/agents/outbound-calls":{"post":{"operationId":"create","summary":"Create Outbound Call","description":"Place an outbound call from an agent to a phone number. LiveKit\noriginates the SIP INVITE through the outbound trunk bound to the\nagent's workspace; the agent is dispatched into the call\nautomatically.\n\nThe response is returned as soon as LiveKit accepts the INVITE.\nPoll `GET /v1/agents/conversations/{conversation_id}` for status\ntransitions: `pending` → `active` (answered) → `completed`.\n\nRequires a Twilio or BYOC trunk. LiveKit-native numbers are\ninbound-only.\n","tags":["subpackage_agent.subpackage_agent/outboundCalls"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"A client-generated key (an opaque string, max 255 chars) that makes a\nside-effect POST safe to retry: the server runs the operation exactly\nonce and replays the first response (its status and body) for 24 hours.\nReusing a key with a different request body, or while the first request\nis still in flight, returns `409 idempotency_conflict`. A replayed\nresponse carries the `Idempotent-Replayed: true` header.\n","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The outbound call was accepted by LiveKit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOutboundCallResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"An upstream dependency (the TTS composer or voice-metadata\nservice) returned a 5xx. The raw upstream detail is not\nforwarded - the cause is in the server log; the response is a\nfixed `upstream_failure` envelope. Safe to retry.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOutboundCallRequest"}}}}}},"/v1/agents/phone-numbers":{"get":{"operationId":"list","summary":"List Phone Numbers","description":"List all phone numbers in the caller's workspace. Cursor-paginated:\nomit `cursor` for the first page; walk pages while `has_more` is true\n(default page size 50, max 200).","tags":["subpackage_agent.subpackage_agent/phoneNumbers"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The phone numbers for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPhoneNumbersResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"import","summary":"Import Phone Number","description":"Import a phone number into the workspace. The `provider` field\ndetermines the provisioning path:\n\n- `livekit` - LiveKit purchases the number on your behalf. US\n  inbound only. Quickest path for local testing.\n- `twilio` - Provide your Twilio Account SID, Auth Token, and\n  the E.164 number you already own. We provision an Elastic SIP\n  Trunk on your Twilio account automatically.\n- `byoc` - Provide an existing SIP trunk ID. The number is\n  registered against that trunk.\n\nReturns 402 when the workspace has reached the 100-number cap.\n","tags":["subpackage_agent.subpackage_agent/phoneNumbers"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The imported phone number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The request was well-formed but semantically rejected -\ntypically a referential integrity violation (e.g. flow node\nreferences an audio asset in another workspace) or a state\nmachine refusal.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportPhoneNumberRequest"}}}}}},"/v1/agents/phone-numbers/available":{"get":{"operationId":"search-available","summary":"Search Available Phone Numbers","description":"Search carrier inventory for phone numbers available to purchase.\nCurrently restricted to the US (`country=US`); pass `area_code`\nto narrow to a specific NPA. The returned numbers are not held;\na subsequent `POST /v1/agents/phone-numbers/purchase` against the same\nE.164 may fail with 4xx if the number has been taken in the\nmeantime.\n","tags":["subpackage_agent.subpackage_agent/phoneNumbers"],"parameters":[{"name":"country","in":"query","description":"ISO-3166 alpha-2 country code. Defaults to \"US\"; only \"US\" is supported in v1.","required":false,"schema":{"type":"string","default":"US"}},{"name":"area_code","in":"query","description":"Three-digit NPA to filter inventory to a region.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results to return. Capped at 50.","required":false,"schema":{"type":"integer","default":20}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Available numbers (may be empty if no inventory matches).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchAvailablePhoneNumbersResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"A downstream dependency is degraded or the endpoint is\nintentionally disabled (e.g. phone-number purchase before\nops setup).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/phone-numbers/purchase":{"post":{"operationId":"purchase","summary":"Purchase Phone Number","description":"Purchase a phone number on Speechify's master Twilio account.\nThe number is billed to Speechify until released. A plan that\nincludes no purchased numbers (e.g. Free) returns 402; a plan\nthat has used its full included quota returns 422. This is\nindependent of the overall 100-number cap.\n`e164` must come from a recent `SearchAvailablePhoneNumbers`\nresponse — carriers reject buys against numbers that are no\nlonger in inventory. The returned phone number is wired for\nboth inbound (when `agent_id` is set, or after binding the\nnumber to an agent via\n`POST /v1/agents/{agent_id}/phone-numbers/{phone_number_id}`) and\noutbound calls (via the workspace's shared outbound trunk).\n","tags":["subpackage_agent.subpackage_agent/phoneNumbers"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"A client-generated key (an opaque string, max 255 chars) that makes a\nside-effect POST safe to retry: the server runs the operation exactly\nonce and replays the first response (its status and body) for 24 hours.\nReusing a key with a different request body, or while the first request\nis still in flight, returns `409 idempotency_conflict`. A replayed\nresponse carries the `Idempotent-Replayed: true` header.\n","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The purchased phone number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace has insufficient credits, or the request needs a\nplan tier the workspace is not on (e.g. voice cloning). Distinct\nfrom `Forbidden` so SDK consumers can drive upgrade UX.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The request was well-formed but semantically rejected -\ntypically a referential integrity violation (e.g. flow node\nreferences an audio asset in another workspace) or a state\nmachine refusal.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"A downstream dependency is degraded or the endpoint is\nintentionally disabled (e.g. phone-number purchase before\nops setup).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchasePhoneNumberRequest"}}}}}},"/v1/agents/phone-numbers/{phone_number_id}":{"delete":{"operationId":"delete","summary":"Delete Phone Number","description":"Delete a phone number from the workspace. For Twilio and LiveKit\nnumbers this also deprovisions the backing SIP trunk and dispatch\nrule on LiveKit Cloud.\n","tags":["subpackage_agent.subpackage_agent/phoneNumbers"],"parameters":[{"name":"phone_number_id","in":"path","description":"Phone number id (prefixed external id, `phone_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Phone number deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get","summary":"Get Phone Number","description":"Retrieve a phone number by ID.","tags":["subpackage_agent.subpackage_agent/phoneNumbers"],"parameters":[{"name":"phone_number_id","in":"path","description":"Phone number id (prefixed external id, `phone_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested phone number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update Phone Number","description":"Update a phone number's own attributes (today: `label`).\n`source` and `e164` are immutable after import. To bind or\nunbind an agent, use the relationship endpoints\n`POST`/`DELETE /v1/agents/{agent_id}/phone-numbers/{phone_number_id}`.\n","tags":["subpackage_agent.subpackage_agent/phoneNumbers"],"parameters":[{"name":"phone_number_id","in":"path","description":"Phone number id (prefixed external id, `phone_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated phone number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePhoneNumberRequest"}}}}}},"/v1/agents/sip-trunks":{"get":{"operationId":"list","summary":"List SIP Trunks","description":"List all SIP trunks in the caller's workspace. Cursor-paginated\nfor uniformity with the other list endpoints: omit `cursor` for\nthe first page; walk pages while `has_more` is true (default page\nsize 50, max 200). In practice the workspace is capped at 20\ntrunks, so every response fits in a single page.","tags":["subpackage_agent.subpackage_agent/sipTrunks"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The SIP trunks for the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSIPTrunksResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create SIP Trunk","description":"Create a SIP trunk. For `provider=byoc` supply `sip_address` plus\noptional digest credentials and IP allowlist. For `provider=twilio`\nuse `ImportPhoneNumber` with a `twilio` spec instead - trunk\ncreation is handled automatically. Returns 422 when the workspace\nhas reached the 20-trunk cap.\n","tags":["subpackage_agent.subpackage_agent/sipTrunks"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created SIP trunk.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SIPTrunk"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The request was well-formed but semantically rejected -\ntypically a referential integrity violation (e.g. flow node\nreferences an audio asset in another workspace) or a state\nmachine refusal.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSIPTrunkRequest"}}}}}},"/v1/agents/sip-trunks/{sip_trunk_id}":{"delete":{"operationId":"delete","summary":"Delete SIP Trunk","description":"Delete a SIP trunk. This also removes the backing LiveKit inbound\ntrunk, outbound trunk, and dispatch rule if they were provisioned\nby us. Phone numbers attached to this trunk are left in place but\nbecome non-functional until rebound to a new trunk.\n","tags":["subpackage_agent.subpackage_agent/sipTrunks"],"parameters":[{"name":"sip_trunk_id","in":"path","description":"SIP trunk id (prefixed external id, `trunk_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"SIP trunk deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get","summary":"Get SIP Trunk","description":"Retrieve a SIP trunk by ID.","tags":["subpackage_agent.subpackage_agent/sipTrunks"],"parameters":[{"name":"sip_trunk_id","in":"path","description":"SIP trunk id (prefixed external id, `trunk_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The requested SIP trunk.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SIPTrunk"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/callers":{"get":{"operationId":"list","summary":"List Callers","description":"List the workspace's callers, ordered by most-recently-seen first.\nA caller is the per-(tenant, agent, identity) entity that owns\nlong-term memories and conversation history.\n","tags":["subpackage_agent.subpackage_agent/callers"],"parameters":[{"name":"agent_id","in":"query","description":"Narrow the list to callers attached to one agent.","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Identity-prefix search. Filters to rows where `identity LIKE q + '%'`\n(`%`/`_` characters in the input are escaped as literals).\n","required":false,"schema":{"type":"string"}},{"name":"last_seen_after","in":"query","description":"RFC 3339 timestamp. Narrows to callers active strictly AFTER the\nsupplied moment. Useful for \"active this week / month\" filters.\n","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCallersResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/callers/{caller_id}":{"delete":{"operationId":"delete","summary":"Delete Caller (GDPR purge)","description":"Soft-delete the caller AND cascade soft-delete every memory row\npointing at it. Conversations survive (forensic / billing records)\nbut their caller pointer surfaces as \"deleted\" through the API.\n\nIdempotent — re-deleting an already-purged caller returns\n`{caller_purged: 0, memories_purged: 0}`. Audit row counts\naccompany every response so a privacy operator has direct\nevidence of the purge without re-querying.\n\nReturns `200` with the row-count body rather than a bodiless\n`204`: the counts are GDPR-purge audit evidence. This is a\ndeliberate exception to the delete-returns-204 convention,\nshared with the bulk memory purge\n(`DELETE /v1/agents/{agent_id}/memories`).\n","tags":["subpackage_agent.subpackage_agent/callers"],"parameters":[{"name":"caller_id","in":"path","description":"Caller ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Soft-delete completed; row counts in the body (GDPR audit evidence).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCallerResponse"}}}}}},"get":{"operationId":"get","summary":"Get Caller","description":"Fetch a single caller by id. Returns 404 for soft-deleted or\nforeign-tenant rows — GDPR-purged callers appear as \"not found\"\nto the API.\n","tags":["subpackage_agent.subpackage_agent/callers"],"parameters":[{"name":"caller_id","in":"path","description":"Caller ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Caller"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update Caller","description":"Update the customer-editable fields on a caller. PATCH semantics:\nomitted fields are unchanged, present fields overwrite. To clear\na nullable field (`display_name`, `external_ref`) pass an empty\nstring. `metadata` REPLACES the existing JSONB blob when supplied.\n","tags":["subpackage_agent.subpackage_agent/callers"],"parameters":[{"name":"caller_id","in":"path","description":"Caller ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The refreshed caller row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Caller"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCallerRequest"}}}}}},"/v1/agents/callers/{caller_id}/conversations":{"get":{"operationId":"list-conversations","summary":"List Conversations For Caller","description":"List one page of conversations belonging to the caller, newest\nstarted first. Same wire envelope as the workspace-wide\n`GET /v1/agents/conversations`, narrowed to one caller.\n","tags":["subpackage_agent.subpackage_agent/callers"],"parameters":[{"name":"caller_id","in":"path","description":"Caller ID.","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCallerConversationsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/callers/{caller_id}/memories":{"get":{"operationId":"list-memories","summary":"List Memories For Caller","description":"List one page of memories belonging to the caller, newest first.\nSoft-deleted memories AND memories whose parent caller is\nsoft-deleted are hidden — the GDPR purge semantics require the\nAPI to behave as if those rows do not exist.\n","tags":["subpackage_agent.subpackage_agent/callers"],"parameters":[{"name":"caller_id","in":"path","description":"Caller ID.","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCallerMemoriesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/memories/{memory_id}":{"delete":{"operationId":"delete","summary":"Delete Memory","description":"Soft-delete one memory row.","tags":["subpackage_agent.subpackage_agent/memories"],"parameters":[{"name":"memory_id","in":"path","description":"User memory id (prefixed external id, `memory_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Memory deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get","summary":"Get Memory","description":"Fetch a single memory row by id.","tags":["subpackage_agent.subpackage_agent/memories"],"parameters":[{"name":"memory_id","in":"path","description":"User memory id (prefixed external id, `memory_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The memory.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Memory"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/memories":{"get":{"operationId":"list-memories","summary":"List Agent Memories","description":"List per-caller memories extracted for an agent. Memories are\nwritten post-call by the built-in extractor when `memory_enabled`\nis true on the agent; the list is sorted newest-first.\nCursor-paginated: omit `cursor` for the first page; walk pages\nwhile `has_more` is true (default page size 50, max 200).","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Memories for the agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMemoriesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"delete-memories-by-caller","summary":"Delete Memories by Caller","description":"Delete every memory ever extracted for a specific caller on\nthis agent, addressed by `caller_identity`. Privacy / GDPR\nsurface. Rows become permanently unreachable immediately and are\nhard-deleted by the retention job after the tenant's configured\nretention window.\n\nReturns `200` with the soft-deleted row count rather than a\nbodiless `204`: the count is GDPR-purge audit evidence, so a\nprivacy operator has direct proof of the purge without\nre-querying. This is a deliberate exception to the\ndelete-returns-204 convention, shared with the caller-purge\ncascade (`DELETE /v1/agents/callers/{caller_id}`).","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"caller_identity","in":"query","description":"Stable caller identity whose memories on this agent are purged.\n","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deletion summary (GDPR audit evidence).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteMemoriesByCallerResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/audio-assets":{"get":{"operationId":"list","summary":"List Audio Assets","description":"List every non-deleted audio asset in the caller's workspace.\nAudio assets are pre-recorded WAV clips (intro jingles, legal\ndisclaimers, hold cues) referenced from `play_audio` flow nodes\nand the corresponding system builtin. Cursor-paginated: omit\n`cursor` for the first page; walk pages while `has_more` is true\n(default page size 50, max 200).","tags":["subpackage_agent.subpackage_agent/audioAssets"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of audio assets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAudioAssetsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"upload","summary":"Upload Audio Asset","description":"Upload a new audio asset. The body is a multipart/form-data\nrequest with a single `file` field carrying the WAV bytes.\n\nThe WAV is validated server-side against a strict format\ncontract — PCM 16-bit signed, mono, 48000 Hz, ≤30s, ≤4 MiB —\nbefore any bytes hit storage. The format matches what voice\nagents play back natively, so clips stream with no transcoding;\nconvert MP3 sources with `ffmpeg -i in.mp3 -ar 48000 -ac 1\n-sample_fmt s16 out.wav`.\n","tags":["subpackage_agent.subpackage_agent/audioAssets"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The uploaded asset's metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioAsset"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The WAV file bytes. Must be PCM 16-bit signed, mono,\n48000 Hz, ≤30s duration, ≤4 MiB total.\n"}},"required":["file"]}}}}}},"/v1/agents/audio-assets/{audio_asset_id}":{"delete":{"operationId":"delete","summary":"Delete Audio Asset","description":"Soft-delete an audio asset. The underlying GCS object is\nretained so any flow node or tool still referencing the asset\nkeeps working until the config is updated; the agent runtime logs\nand skips on a missing row at session start (fail-soft).\n","tags":["subpackage_agent.subpackage_agent/audioAssets"],"parameters":[{"name":"audio_asset_id","in":"path","description":"Audio asset ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Audio asset soft-deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get","summary":"Get Audio Asset","description":"Fetch one audio asset's metadata. Returns 404 for missing,\nsoft-deleted, or foreign-tenant assets — existence information\nis never leaked across tenants.\n","tags":["subpackage_agent.subpackage_agent/audioAssets"],"parameters":[{"name":"audio_asset_id","in":"path","description":"Audio asset ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The audio asset's metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioAsset"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/audio-assets/{audio_asset_id}/bytes":{"get":{"operationId":"get-bytes","summary":"Get Audio Asset Bytes","description":"Stream the raw WAV bytes for an audio asset. Byte-stream\nsibling of the metadata endpoint at /v1/agents/audio-assets/{audio_asset_id}.\nThe agent runtime fetches through here for the play_audio\nbuiltin; SDK consumers can also download originals. Returns 404\nfor missing / soft-deleted / foreign-tenant assets.\n","tags":["subpackage_agent.subpackage_agent/audioAssets"],"parameters":[{"name":"audio_asset_id","in":"path","description":"Audio asset ID.","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The raw audio bytes (PCM 16-bit signed, mono, 48 kHz, WAV-wrapped).","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}}}},"/v1/chat/completions":{"post":{"operationId":"create","summary":"Create Chat Completion","description":"OpenAI-compatible chat completions. The gateway runs a mixture of\nfrontier models and returns a single answer, so the request and\nresponse follow the OpenAI chat-completions shape: point the OpenAI SDK\nat this base URL and set `model` to one of the `waymark-*` routes. Any\nstandard OpenAI parameter (`temperature`, `max_tokens`, `tools`, …) is\nforwarded.\n\nSet `stream: true` to receive the answer as a `text/event-stream` of\nserver-sent events. The response adds a `waymark` object reporting which\nupstream models ran and their per-model token counts, and the\n`Speechify-Route` response header names the route that served the\nrequest.","tags":["subpackage_chat"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The chat completion. A single JSON object by default; when the\nrequest set `stream: true`, a `text/event-stream` of server-sent\nevents whose final data chunk before `[DONE]` carries the `waymark`\nusage object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace has insufficient credits, or the request needs a\nplan tier the workspace is not on (e.g. voice cloning). Distinct\nfrom `Forbidden` so SDK consumers can drive upgrade UX.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or concurrency limit exceeded. `error.code` distinguishes\nrequest-rate limiting (`rate_limited`) from concurrency exhaustion\n(`concurrency_limit_reached`). Carries `Retry-After` and the\nrequest-rate budget headers; a concurrency-exhaustion 429 also carries\n`RateLimit-Remaining-Calls: 0`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"An upstream dependency (the TTS composer or voice-metadata\nservice) returned a 5xx. The raw upstream detail is not\nforwarded - the cause is in the server log; the response is a\nfixed `upstream_failure` envelope. Safe to retry.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"A downstream dependency is degraded or the endpoint is\nintentionally disabled (e.g. phone-number purchase before\nops setup).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}}}}},"/v1/messages":{"post":{"operationId":"create-message","summary":"Create Message","description":"Anthropic-compatible Messages endpoint. The gateway runs a mixture of\nfrontier models and returns a single answer in Anthropic's Messages\nshape: point the Anthropic SDK (or Claude Code via `ANTHROPIC_BASE_URL`)\nat this base URL and set `model` to one of the `waymark-*` routes. Any\nstandard Anthropic parameter (`system`, `temperature`, `top_p`,\n`stop_sequences`, `tools`, …) is forwarded.\n\nSet `stream: true` to receive the answer as a `text/event-stream` of\nAnthropic server-sent events. The response adds a `waymark` object\nreporting which upstream models ran and their per-model token counts, and\nthe `Speechify-Route` response header names the route that served the\nrequest.","tags":["subpackage_chat"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The message. A single JSON object by default; when the request set\n`stream: true`, a `text/event-stream` of Anthropic server-sent\nevents whose `message_delta` frame carries the `waymark` usage\nobject.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicMessage"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace has insufficient credits, or the request needs a\nplan tier the workspace is not on (e.g. voice cloning). Distinct\nfrom `Forbidden` so SDK consumers can drive upgrade UX.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit or concurrency limit exceeded. `error.code` distinguishes\nrequest-rate limiting (`rate_limited`) from concurrency exhaustion\n(`concurrency_limit_reached`). Carries `Retry-After` and the\nrequest-rate budget headers; a concurrency-exhaustion 429 also carries\n`RateLimit-Remaining-Calls: 0`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"An unexpected server-side error occurred. Safe to retry with\nexponential backoff for idempotent requests.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"An upstream dependency (the TTS composer or voice-metadata\nservice) returned a 5xx. The raw upstream detail is not\nforwarded - the cause is in the server log; the response is a\nfixed `upstream_failure` envelope. Safe to retry.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"A downstream dependency is degraded or the endpoint is\nintentionally disabled (e.g. phone-number purchase before\nops setup).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicMessageRequest"}}}}}},"/v1/agents/llm-models":{"get":{"operationId":"list-llm-models","summary":"List LLM Models","description":"List the LLM models selectable for voice agents on the caller's\nworkspace plan. Premium flagship models and the bring-your-own\ncustom endpoint are available only on higher plans; lower plans\nreceive the managed and standard models. Drive a model picker from\nthis response so it only offers models that POST/PATCH /v1/agents\nwill accept. Returns the full set in a single\nresponse: bounded by the platform's curated model catalogue, so this\nlist is intentionally not paginated.\n","tags":["subpackage_agent"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The LLM models available on the caller's plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LLMModelsResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/phone-numbers":{"get":{"operationId":"list-agent-phone-numbers","summary":"List Agent Phone Numbers","description":"List the phone numbers bound to an agent. Cursor-paginated: omit\n`cursor` for the first page; walk pages while `has_more` is true\n(default page size 50, max 200).\n","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The phone numbers bound to the agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPhoneNumbersResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/{agent_id}/phone-numbers/{phone_number_id}":{"post":{"operationId":"bind-phone-number","summary":"Bind Agent Phone Number","description":"Bind a workspace phone number to this agent so inbound calls to\nthe number reach it. Idempotent and last-write-wins: binding a\nnumber already bound to another agent reassigns it. Verified\ncaller IDs are outbound-only and cannot be bound (400).","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"phone_number_id","in":"path","description":"Phone number id (prefixed external id, `phone_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Phone number bound to the agent.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"unbind-phone-number","summary":"Unbind Agent Phone Number","description":"Unbind a phone number from this agent. Returns 404 when the\nnumber is not currently bound to this agent.","tags":["subpackage_agent"],"parameters":[{"name":"agent_id","in":"path","description":"Agent id (prefixed external id, `agent_...`).","required":true,"schema":{"type":"string"}},{"name":"phone_number_id","in":"path","description":"Phone number id (prefixed external id, `phone_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Phone number unbound from the agent.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/livekit-room":{"get":{"operationId":"get-livekit-room","summary":"Get Conversation LiveKit Room","description":"Operator-only: return a conversation's internal LiveKit room\nhandles (the room name and `RM_` room SID). These are deliberately\nabsent from the conversation read responses so they never freeze\ninto the public contract, and are available only to Speechify\noperators for support and debugging.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The conversation's internal LiveKit room handles (operator-only).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationLiveKitRoom"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/traces":{"get":{"operationId":"get-traces","summary":"Get Conversation Traces","description":"Retrieve the per-call trace timeline for a conversation: the agent\npipeline spans (STT, end-of-turn, LLM, TTS, tool calls, DTMF) in call\norder, each with its start offset from the beginning of the call and\nits duration, for rendering a latency waterfall. Returns an empty\ntimeline for a call that never connected.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The per-call trace timeline.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationTrace"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"A downstream dependency is degraded or the endpoint is\nintentionally disabled (e.g. phone-number purchase before\nops setup).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/conversations/{conversation_id}/live":{"get":{"operationId":"stream-live","summary":"Stream Live Conversation","description":"Server-Sent Events stream of an in-progress conversation's\ntranscript and status, for live-monitoring surfaces.\nHolds the connection open and tails the transcript: emits a\n`message` event per turn (its `data` is a Message object), a\n`status` event when the conversation status changes, and a\nterminal `end` event when the call completes. Resumes after a\ndropped connection via the standard `Last-Event-ID` header. Same\nread access as List Messages.","tags":["subpackage_agent.subpackage_agent/conversations"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"An event stream (text/event-stream) of transcript and status deltas.","content":{"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/analytics/dimensions":{"get":{"operationId":"dimensions","summary":"List analytics dimensions","description":"The typed dimension catalog the analytics dashboards filter and\nbreak down by. Returns the always-available call-level dimensions;\npass `agent_id` to additionally include that agent's evaluation\ncriteria and typed data-collection fields. Each dimension declares\nits value `type` and whether it can be used to filter, to group by,\nor both. Free-text fields are never returned as dimensions. Returns\nthe full set in a single response: bounded by the typed dimension\ncatalogue plus (with agent_id) one agent's evaluation config, so\nthis list is intentionally not paginated.\n","tags":["subpackage_agent.subpackage_agent/analytics"],"parameters":[{"name":"agent_id","in":"query","description":"Include this agent's per-agent evaluation and data-collection dimensions.","required":false,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The analytics dimension catalog.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsDimensionsResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/analytics/query":{"post":{"operationId":"query","summary":"Run an analytics query","description":"Run one tenant-scoped aggregation over the workspace's conversations\nand post-call evaluations — the query that powers a single dashboard\nwidget. Every chart type is a different shape of this request: a\nnumber card omits `group_by` and `time.bucket`; a line chart sets a\n`time.bucket`; bar / column / donut set `group_by`; a table sets\nseveral `group_by` dimensions.\n\n`metric` is the value each group/bucket reduces to (`count`, or an\n`avg` / `sum` / `min` / `max` over a numeric field, or a `rate` whose\nnumerator is `rate_predicate`). `group_by` and `filters` reference\ndimension keys from `GET /v1/agents/analytics/dimensions`; an unknown\ndimension, metric, or operator is rejected. `compare_to_previous`\nreturns the same query for the immediately preceding period. The\nnumber of breakdown groups is capped by `breakdown_limit`; `meta.truncated`\nreports when groups were dropped.\n","tags":["subpackage_agent.subpackage_agent/analytics"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The aggregation result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsQueryResult"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsQueryRequest"}}}}}},"/v1/agents/dashboards":{"get":{"operationId":"list","summary":"List dashboards","description":"The caller's workspace's saved analytics dashboards. Dashboards are\nshared across the workspace. Cursor-paginated: omit `cursor` for the\nfirst page; walk pages while `has_more` is true (default page size 50,\nmax 200).","tags":["subpackage_agent.subpackage_agent/dashboards"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The workspace's dashboards.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDashboardsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create dashboard","description":"Create a saved dashboard. Each widget carries a chart type, a grid\nposition, and an analytics query spec validated against the\ndimension registry. Limited to 10 dashboards per workspace.\n","tags":["subpackage_agent.subpackage_agent/dashboards"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created dashboard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dashboard"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The request was well-formed but semantically rejected -\ntypically a referential integrity violation (e.g. flow node\nreferences an audio asset in another workspace) or a state\nmachine refusal.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}}}}},"/v1/agents/dashboards/{dashboard_id}":{"get":{"operationId":"get","summary":"Get dashboard","description":"Fetch a saved analytics dashboard by id.","tags":["subpackage_agent.subpackage_agent/dashboards"],"parameters":[{"name":"dashboard_id","in":"path","description":"Dashboard id (prefixed `dash_…`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The dashboard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dashboard"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"delete","summary":"Delete dashboard","description":"Delete a saved analytics dashboard. Returns 204 on success.","tags":["subpackage_agent.subpackage_agent/dashboards"],"parameters":[{"name":"dashboard_id","in":"path","description":"Dashboard id (prefixed `dash_…`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Dashboard deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update dashboard","description":"Partial update; omitted fields are left unchanged.","tags":["subpackage_agent.subpackage_agent/dashboards"],"parameters":[{"name":"dashboard_id","in":"path","description":"Dashboard id (prefixed `dash_…`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated dashboard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dashboard"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}}}}},"/v1/agents/conversations/{conversation_id}/takeover":{"post":{"operationId":"take-over","summary":"Take over conversation","description":"Take over an active voice-agent call. Returns short-lived\ncredentials a real-time client uses to connect an authorized\noperator into the live call. The operator speaks to the caller\ndirectly while the AI agent stands down and stays silent, then\nresumes once the operator hands the call back. The requester must\nbe an `owner` or `admin` of the workspace the call belongs to.\nOnly an active call can be taken over; a pending or completed call\nreturns 409.\n","tags":["subpackage_agent.subpackage_agent/admin"],"parameters":[{"name":"conversation_id","in":"path","description":"Conversation id (prefixed external id, `conv_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Take-over connection details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TakeOverConversationResponse"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/credentials":{"get":{"operationId":"list","summary":"List Credentials","description":"List every active credential in the caller's workspace, newest\nfirst. The vault is write-only: each `config` is the masked\n`CredentialConfigView` (non-secret fields plus `*_set` markers) —\nsecret values are never returned. Soft-deleted credentials are\nomitted. Cursor-paginated: omit `cursor` for the first page; walk\npages while `has_more` is true (default page size 50, max 200).\n","tags":["subpackage_credentials"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"All active credentials in the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCredentialsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create Credential","description":"Create a credential in the caller's workspace. `config` must\ncarry exactly the one kind-specific block named by `kind` (e.g.\n`kind=bearer` requires `config.bearer`). Names are unique per\nworkspace among active credentials.\n","tags":["subpackage_credentials"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credential"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCredentialRequest"}}}}}},"/v1/credentials/{credential_id}":{"get":{"operationId":"get","summary":"Get Credential","description":"Fetch one credential by id, scoped to the caller's workspace.\n`config` is the masked `CredentialConfigView` — secret values are\nnever returned. Returns 404 for missing, soft-deleted, or\nforeign-workspace credentials — credential existence is never\nleaked across workspaces.\n","tags":["subpackage_credentials"],"parameters":[{"name":"credential_id","in":"path","description":"Credential id (prefixed external id, `cred_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credential"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"delete","summary":"Delete Credential","description":"Soft-delete a credential. Tool rows that still reference it via\n`credential_id` keep working until their next update resolves\nthe FK; a future GC job hard-deletes orphaned rows.\n","tags":["subpackage_credentials"],"parameters":[{"name":"credential_id","in":"path","description":"Credential id (prefixed external id, `cred_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Credential soft-deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update Credential","description":"Rotate a credential's secret and/or rename it, in place, keeping the\nsame id so every referencing config picks up the change with no\nre-wiring. Because the vault is write-only, rotation is the only way\nto change a stored secret. The kind is immutable: a rotated `config`\nmust populate the same block as the credential's existing kind.\n","tags":["subpackage_credentials"],"parameters":[{"name":"credential_id","in":"path","description":"Credential id (prefixed external id, `cred_...`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credential"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The request conflicts with the current resource state - e.g.\nduplicate, optimistic-concurrency mismatch, or last-owner\nguard.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCredentialRequest"}}}}}},"/v1/webhooks/endpoints":{"get":{"operationId":"list","summary":"List webhook endpoints","description":"The caller's workspace's registered webhook endpoints. Cursor-paginated:\nomit `cursor` for the first page; walk pages while `has_more` is true\n(default page size 50, max 200). The signing `secret` is never returned\nhere — it is shown only when an endpoint is created or its secret is\nrotated.","tags":["subpackage_webhooks.subpackage_webhooks/endpoints"],"parameters":[{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The workspace's webhook endpoints.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookEndpointsResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"create","summary":"Create webhook endpoint","description":"Register a webhook endpoint. Speechify mints an HMAC signing secret\nand returns it in the response `secret` field — exactly once. Store it\nthen; subsequent reads omit it (rotate it with the rotate-secret action\nif lost). Select events via `enabled_events`: a list of catalog event\nnames or `[\"*\"]` for every event. Limited to 50 endpoints per workspace.\n","tags":["subpackage_webhooks.subpackage_webhooks/endpoints"],"parameters":[{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"201":{"description":"The created endpoint, including its one-time signing secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The request was well-formed but semantically rejected -\ntypically a referential integrity violation (e.g. flow node\nreferences an audio asset in another workspace) or a state\nmachine refusal.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookEndpointRequest"}}}}}},"/v1/webhooks/endpoints/{webhook_endpoint_id}":{"get":{"operationId":"get","summary":"Get webhook endpoint","description":"Fetch a webhook endpoint by id. The signing secret is never returned.","tags":["subpackage_webhooks.subpackage_webhooks/endpoints"],"parameters":[{"name":"webhook_endpoint_id","in":"path","description":"Webhook endpoint id (prefixed `whe_…`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The webhook endpoint (without the signing secret).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"delete","summary":"Delete webhook endpoint","description":"Delete a webhook endpoint. In-flight deliveries stop; returns 204 on success.","tags":["subpackage_webhooks.subpackage_webhooks/endpoints"],"parameters":[{"name":"webhook_endpoint_id","in":"path","description":"Webhook endpoint id (prefixed `whe_…`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"Endpoint deleted.","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"update","summary":"Update webhook endpoint","description":"Partial update; omitted fields are left unchanged. Set `disabled` to pause delivery without deleting the endpoint.","tags":["subpackage_webhooks.subpackage_webhooks/endpoints"],"parameters":[{"name":"webhook_endpoint_id","in":"path","description":"Webhook endpoint id (prefixed `whe_…`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated endpoint (without the signing secret).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookEndpointRequest"}}}}}},"/v1/webhooks/endpoints/{webhook_endpoint_id}/rotate-secret":{"post":{"operationId":"rotate-secret","summary":"Rotate webhook endpoint secret","description":"Mint a new HMAC signing secret for the endpoint and return it in the\nresponse `secret` field (shown exactly once). The previous secret stops\nsigning immediately, so accept both during your cutover window.\n","tags":["subpackage_webhooks.subpackage_webhooks/endpoints"],"parameters":[{"name":"webhook_endpoint_id","in":"path","description":"Webhook endpoint id (prefixed `whe_…`).","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The endpoint, including its new one-time signing secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential authenticated, but is not authorised for this\nresource - typically a workspace-role gate (owner / admin\nrequired) or a cross-tenant access attempt.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/endpoints/{webhook_endpoint_id}/deliveries":{"get":{"operationId":"list-deliveries","summary":"List webhook endpoint deliveries","description":"Delivery attempts for one webhook endpoint, newest first. One row per\n(endpoint, event, resource), updated in place across retries. Each row\nincludes the exact request payload and signed headers Speechify sent\n(`request_body`, `request_headers`) and the response your server returned\n(`last_status_code`, `last_response_body`, `last_response_headers`), so\nyou can verify the signature and debug failures. Cursor-paginated: omit\n`cursor` for the first page; walk pages while `has_more` is true (default\npage size 50, max 200).","tags":["subpackage_webhooks.subpackage_webhooks/endpoints"],"parameters":[{"name":"webhook_endpoint_id","in":"path","description":"Webhook endpoint id (prefixed `whe_…`).","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Opaque pagination cursor from a previous response.","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max items per page (default 50, max 200).","required":false,"schema":{"type":"integer","default":50}},{"name":"Authorization","in":"header","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.","required":true,"schema":{"type":"string"}},{"name":"Speechify-Version","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The endpoint's delivery attempts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhookEndpointDeliveriesResponse"}}}},"400":{"description":"The request was malformed or failed validation. The response\nbody is the standard `Error` envelope; for validation\nfailures `error.fields` enumerates the offending fields as\na `path -> message` map (code = `validation_failed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication is missing or invalid. The request did not\ncarry a recognised credential (Firebase ID token, API key, or\nworker JWT).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The referenced resource does not exist or is not visible to\nthe caller's workspace.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"servers":[{"url":"https://api.speechify.ai","description":"https://api.speechify.ai"}],"components":{"schemas":{"AgentLlmConfigProvider":{"type":"string","enum":["openai","speechify","custom"],"description":"LLM backend. Null (or omit) uses the platform default,\nresolved server-side at dispatch. `openai` and `speechify`\npair with a `model` from the allowed table. `custom` points\nthe worker at any OpenAI / vLLM-compatible endpoint - see\n`base_url`, `credential_id`, `extra_body`. Must be paired with\na non-null `model`; setting one without the other is rejected.\n","title":"AgentLlmConfigProvider"},"AgentLLMConfig":{"type":"object","properties":{"provider":{"$ref":"#/components/schemas/AgentLlmConfigProvider","description":"LLM backend. Null (or omit) uses the platform default,\nresolved server-side at dispatch. `openai` and `speechify`\npair with a `model` from the allowed table. `custom` points\nthe worker at any OpenAI / vLLM-compatible endpoint - see\n`base_url`, `credential_id`, `extra_body`. Must be paired with\na non-null `model`; setting one without the other is rejected.\n"},"model":{"type":["string","null"],"description":"Chat model slug. Null (or omit) uses the platform default.\nFor `openai` / `speechify` it must be a slug from the allowed\ntable; for `custom` it is free-form.\n"},"base_url":{"type":["string","null"],"description":"Custom OpenAI/vLLM-compatible endpoint base URL. Required\nwhen `provider` is `custom`, rejected otherwise.\n"},"credential_id":{"type":["string","null"],"description":"`cred_<crockford>` id of a `bearer` credential in the\nworkspace vault holding the custom endpoint's API key. The\nsecret lives in the vault and is resolved server-side at\ndispatch, never inlined on the agent. On write, send a value\nto point at a credential, an empty string to clear it, or omit\nit to keep the stored reference unchanged. On read, the\nreferenced `cred_` id, or null when none is referenced. Create\nthe credential first via `POST /v1/credentials`. Valid only\nwhen `provider` is `custom`.\n"},"extra_body":{"type":["object","null"],"additionalProperties":{"description":"Any type"},"description":"JSON object forwarded verbatim to the custom endpoint as the\nchat.completions `extra_body` (reasoning / sampling knobs).\nValid only when `provider` is `custom`.\n"},"temperature":{"type":"number","format":"double","description":"Sampling temperature in the range 0.0-1.0. Defaults to 0.5."}},"description":"Language-model configuration. Omit the whole block on create to\nrun on the platform default model. On update (merge-patch) send\nonly the sub-fields you want to change: an explicit null clears a\nnullable field to its default, a value sets it, and anything\nomitted is left unchanged. `provider`/`model` are validated as a\npair, inheriting the omitted half from the stored value.\n","title":"AgentLLMConfig"},"AgentTTSConfig":{"type":"object","properties":{"voice_id":{"type":"string","description":"Voice slug from the catalog (see GET /v1/agents/voices). The server rejects an unknown or empty slug."},"speed":{"type":["number","null"],"format":"double","description":"Post-process, pitch-preserving time-stretch applied to the\nsynthesized audio before playback (0.5 = half speed, 2.0 =\ndouble, 1.0 = unchanged). Null means no time-stretch.\n"}},"required":["voice_id"],"description":"Text-to-speech voice and delivery configuration.","title":"AgentTTSConfig"},"AgentSttConfigOverride":{"type":"string","enum":["whisper-v3","gpt-realtime-whisper"],"description":"Pins the streaming speech-to-text stack this agent\ndispatches with. Null uses the platform default (Whisper\nLarge V3).\n","title":"AgentSttConfigOverride"},"AgentSTTConfig":{"type":"object","properties":{"override":{"$ref":"#/components/schemas/AgentSttConfigOverride","description":"Pins the streaming speech-to-text stack this agent\ndispatches with. Null uses the platform default (Whisper\nLarge V3).\n"}},"description":"Speech-to-text configuration.","title":"AgentSTTConfig"},"AgentTurnHandlingConfig":{"type":"object","properties":{"response_delay_seconds":{"type":["number","null"],"format":"double","description":"How long the agent waits after the caller stops talking\nbefore replying. Null uses the platform default. Applies only\nto speech-to-text stacks that use voice-activity endpointing;\nstacks that use semantic turn detection ignore it.\n"},"inactivity_timeout_seconds":{"type":["integer","null"],"description":"How long the agent tolerates silence before ending the call,\nin seconds. Null uses the platform default.\n"}},"description":"Turn-handling and silence-timeout configuration.","title":"AgentTurnHandlingConfig"},"AgentMemoryConfig":{"type":"object","properties":{"enabled":{"type":"boolean","description":"When true, the post-call extractor writes durable facts about\neach caller and the retriever injects the top matches into the\nsystem prompt via the `{{memory}}` variable. Defaults to false.\n"},"retention_days":{"type":"integer","description":"Maximum age (in days) of memories kept and surfaced. 0\ndisables the cap. Defaults to 90.\n"}},"description":"Per-caller long-term memory configuration.","title":"AgentMemoryConfig"},"AgentNavigatorConfig":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Tunes worker turn handling for autonomous outbound IVR\nnavigation - longer endpointing and no barge-in. The\nnavigation goal itself lives in the agent's prompt; this flag\nis the behaviour switch only. Defaults to false.\n"},"ivr_cache_enabled":{"type":"boolean","description":"Controls the IVR-menu cache consulted during navigation.\nDefaults to true so a navigator agent reuses learned menu\nlayouts across calls. Set to false to force every outbound\ndial on this agent to navigate from scratch.\n"}},"description":"Autonomous IVR-navigation configuration for outbound calls.","title":"AgentNavigatorConfig"},"AgentBackgroundNoiseConfigPreset":{"type":"string","enum":["office","city","forest","crowded_room","keyboard_typing","hold_music"],"description":"Pre-mixed ambient bed. Null disables background noise.","title":"AgentBackgroundNoiseConfigPreset"},"AgentBackgroundNoiseConfig":{"type":"object","properties":{"preset":{"$ref":"#/components/schemas/AgentBackgroundNoiseConfigPreset","description":"Pre-mixed ambient bed. Null disables background noise."},"volume":{"type":["number","null"],"format":"double","description":"Volume of the background-noise bed (0.0-1.0). Null disables."}},"description":"Optional ambient background-noise bed mixed into the call.","title":"AgentBackgroundNoiseConfig"},"WidgetConfigStyle":{"type":"string","enum":["pill","fab"],"title":"WidgetConfigStyle"},"WidgetConfigTheme":{"type":"string","enum":["dark","light","auto"],"title":"WidgetConfigTheme"},"WidgetConfigAvatarType":{"type":"string","enum":["orb","image"],"title":"WidgetConfigAvatarType"},"WidgetConfigAvatar":{"type":"object","properties":{"type":{"$ref":"#/components/schemas/WidgetConfigAvatarType"},"image_url":{"type":"string"},"orb_color_1":{"type":"string"},"orb_color_2":{"type":"string"}},"title":"WidgetConfigAvatar"},"WidgetConfigText":{"type":"object","properties":{"start_call":{"type":"string"},"end_call":{"type":"string"},"listening":{"type":"string"},"thinking":{"type":"string"},"speaking":{"type":"string"}},"title":"WidgetConfigText"},"WidgetConfigTerms":{"type":"object","properties":{"enabled":{"type":"boolean"},"content":{"type":"string"}},"title":"WidgetConfigTerms"},"WidgetConfigTranscript":{"type":"object","properties":{"enabled":{"type":"boolean"}},"title":"WidgetConfigTranscript"},"WidgetConfig":{"type":"object","properties":{"version":{"type":"integer"},"style":{"$ref":"#/components/schemas/WidgetConfigStyle"},"theme":{"$ref":"#/components/schemas/WidgetConfigTheme"},"avatar":{"$ref":"#/components/schemas/WidgetConfigAvatar"},"text":{"$ref":"#/components/schemas/WidgetConfigText"},"terms":{"$ref":"#/components/schemas/WidgetConfigTerms"},"transcript":{"$ref":"#/components/schemas/WidgetConfigTranscript"}},"description":"Customer-editable appearance + behaviour payload for the\nembedded `<speechify-agent>` pill: button text, avatar style,\norb colours, terms-and-conditions markdown, transcript display.\nEvery field is optional - empty fields fall back to the\nwidget's compile-time defaults.\n","title":"WidgetConfig"},"AmdConfigOnVoicemailAction":{"type":"string","enum":["hangup","leave_message"],"title":"AmdConfigOnVoicemailAction"},"AmdConfigOnVoicemail":{"type":"object","properties":{"action":{"$ref":"#/components/schemas/AmdConfigOnVoicemailAction"},"message":{"type":"string","description":"Spoken before terminating when action=leave_message.\nSupports {{variable}} substitution. Required (non-empty)\nwhen action=leave_message; rejected by the validator\notherwise.\n"}},"required":["action"],"description":"Action when AMD returns category=machine-vm.","title":"AmdConfigOnVoicemail"},"AmdConfigOnIvrAction":{"type":"string","enum":["proceed","hangup","navigate"],"description":"proceed: hand control to the agent's flow as if the\ncalled party were human. hangup: terminate immediately.\nnavigate: hand control to the IVR Navigator subagent\nwith menu-memoization-aware session config (cache hit\nseeds the agent context; cache miss triggers cold\ndiscovery and the post-call pipeline extracts the\nmenu for future calls).\n","title":"AmdConfigOnIvrAction"},"AmdConfigOnIvr":{"type":"object","properties":{"action":{"$ref":"#/components/schemas/AmdConfigOnIvrAction","description":"proceed: hand control to the agent's flow as if the\ncalled party were human. hangup: terminate immediately.\nnavigate: hand control to the IVR Navigator subagent\nwith menu-memoization-aware session config (cache hit\nseeds the agent context; cache miss triggers cold\ndiscovery and the post-call pipeline extracts the\nmenu for future calls).\n"}},"required":["action"],"description":"Action when AMD returns category=machine-ivr.","title":"AmdConfigOnIvr"},"AmdConfigOnUnavailableAction":{"type":"string","enum":["hangup"],"title":"AmdConfigOnUnavailableAction"},"AmdConfigOnUnavailable":{"type":"object","properties":{"action":{"$ref":"#/components/schemas/AmdConfigOnUnavailableAction"}},"required":["action"],"description":"Action when AMD returns category=machine-unavailable (mailbox full or disconnected).","title":"AmdConfigOnUnavailable"},"AmdConfigTuning":{"type":"object","properties":{"human_speech_threshold_seconds":{"type":"number","format":"double"},"no_speech_threshold_seconds":{"type":"number","format":"double"},"timeout_seconds":{"type":"number","format":"double"},"classification_prompt":{"type":"string"}},"description":"Optional overrides for LiveKit's detection thresholds and\ntimeouts. Cross-field rule (enforced at the application\nvalidator): `timeout_seconds` must be greater than or equal\nto `no_speech_threshold_seconds` when both are set.\n","title":"AmdConfigTuning"},"AMDConfig":{"type":"object","properties":{"enabled":{"type":"boolean","description":"When false, the worker skips AMD entirely. When true, the\nworker runs AMD on the called party's greeting before\ndelivering the agent's first message and dispatches per\nresult.category. The per-route fields below are still\nrequired by the schema regardless of `enabled` state so a\ncustomer flipping `enabled: false → true` ships coherent\nroute configuration immediately.\n"},"on_voicemail":{"$ref":"#/components/schemas/AmdConfigOnVoicemail","description":"Action when AMD returns category=machine-vm."},"on_ivr":{"$ref":"#/components/schemas/AmdConfigOnIvr","description":"Action when AMD returns category=machine-ivr."},"on_unavailable":{"$ref":"#/components/schemas/AmdConfigOnUnavailable","description":"Action when AMD returns category=machine-unavailable (mailbox full or disconnected)."},"tuning":{"$ref":"#/components/schemas/AmdConfigTuning","description":"Optional overrides for LiveKit's detection thresholds and\ntimeouts. Cross-field rule (enforced at the application\nvalidator): `timeout_seconds` must be greater than or equal\nto `no_speech_threshold_seconds` when both are set.\n"}},"required":["enabled","on_voicemail","on_ivr","on_unavailable"],"description":"Answering Machine Detection routing config for outbound voice\nagents. AMD classifies the called party's first ~3-15 seconds of\naudio into one of LiveKit's categories (human, uncertain,\nmachine-vm, machine-ivr, machine-unavailable) and dispatches per\ncategory to the configured action. Stored on the agent row;\nflowed onto outbound dispatch metadata under the `amd` key.\n","title":"AMDConfig"},"Agent":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`).\nThis is the sole customer-facing\nidentifier. URL paths accept only this prefixed form; legacy\nUUID path parameters are rejected with 404.\n"},"name":{"type":"string"},"slug":{"type":"string"},"prompt":{"type":"string"},"first_message":{"type":"string","description":"Spoken verbatim at session start when present in the customer's flow graph."},"language":{"type":"string","description":"ISO 639-1 code, e.g. 'en'."},"llm":{"$ref":"#/components/schemas/AgentLLMConfig"},"tts":{"$ref":"#/components/schemas/AgentTTSConfig"},"stt":{"$ref":"#/components/schemas/AgentSTTConfig"},"turn_handling":{"$ref":"#/components/schemas/AgentTurnHandlingConfig"},"memory":{"$ref":"#/components/schemas/AgentMemoryConfig"},"navigator":{"$ref":"#/components/schemas/AgentNavigatorConfig"},"background_noise":{"$ref":"#/components/schemas/AgentBackgroundNoiseConfig"},"widget_config":{"$ref":"#/components/schemas/WidgetConfig"},"is_public":{"type":"boolean","description":"When true, the `<speechify-agent>` web component can start a\nsession against this agent without an API key, subject to\nthe `allowed_origins` allowlist. When false (default), only\nauthenticated callers can start sessions.\n"},"allowed_origins":{"type":"array","items":{"type":"string"},"description":"Exact `Origin` header values (e.g. `https://example.com`)\nthat are allowed to start public sessions. Empty array\nwith `is_public = true` means any origin is accepted —\nintended for open demos. No subdomain wildcards.\n"},"hostname_allowlist":{"type":["array","null"],"items":{"type":"string"},"description":"Optional per-agent hostname allowlist enforced at\nsession-creation time. When set and non-empty, the\n`Origin` header's hostname must be an exact member.\nBare hostnames only — no scheme, port, or path. Up to\n10 entries. Omit (null) or leave empty for no\nenforcement (public agents accept any hostname).\n"},"webhook_url":{"type":"string","description":"Per-agent override of the workspace webhook endpoints for this\nagent's post-call event. When non-empty, the control plane POSTs a\nsigned payload (transcript + evals + extractors + recording URL) here\nonce the conversation completes, and the workspace endpoints'\n`conversation.completed` is suppressed for this agent (the override\nwins, so the two planes no longer both fire). Empty routes\n`conversation.completed` to your workspace webhook endpoints instead.\n`conversation.started` / `conversation.failed` always ride the\nworkspace endpoints regardless of this field.\n"},"webhook_secret_set":{"type":"boolean","description":"True when an HMAC-SHA256 webhook secret is configured. The\nsecret itself is write-only — supplied on PATCH and never\nechoed back on reads.\n"},"amd":{"$ref":"#/components/schemas/AMDConfig"},"save_audio_recording":{"type":"boolean","description":"When true, every conversation produces a room-composite\nOGG egress uploaded to the recordings bucket. Defaults\nFALSE for new agents (privacy by default).\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","slug","prompt","first_message","language","llm","tts","stt","turn_handling","memory","navigator","background_noise","is_public","allowed_origins","amd","save_audio_recording","created_at","updated_at"],"title":"Agent"},"ListAgentsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"agents":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}}},"required":["next_cursor","has_more","agents"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListAgentsResponse"},"ErrorCode":{"type":"string","enum":["bad_request","validation_failed","unauthorized","payment_required","forbidden","not_found","method_not_allowed","conflict","idempotency_conflict","payload_too_large","unsupported_media_type","rate_limited","concurrency_limit_reached","invalid_api_version","internal_error","upstream_failure","service_unavailable","caller_not_found","credential_not_found","credential_in_use","agent_not_found","kb_not_found","kb_document_not_found","kb_folder_not_found","tool_not_found","conversation_not_found","phone_number_not_found","sip_trunk_not_found","voice_not_found","audio_asset_not_found","builtin_not_found","batch_not_found","agent_test_not_found","workspace_not_found","invite_not_found","insufficient_scope","purchased_numbers_not_included","phone_number_quota_reached","batch_calls_not_included","voice_cloning_not_included","workspace_last_owner","workspace_last_workspace","invite_email_mismatch","invite_already_pending","tool_config_shared"],"description":"Stable machine-readable error code. Additive only: codes are\nnever renamed, only deprecated. SDKs may map each code to a\ntyped exception class. Status-code semantics:\n4xx codes describe caller-fixable issues; 5xx codes describe\nserver-side failures and are safe to retry with backoff for\nidempotent requests.\n","title":"ErrorCode"},"ErrorDetail":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string","description":"Human-readable explanation of this specific occurrence.\nSafe to surface in UI banners or pass to support. The\nwording can change between releases; clients should\nmatch on `code`, not on the message string.\n"},"fields":{"type":"object","additionalProperties":{"type":"string"},"description":"Per-field validation errors as `path -> message`. Only\npresent on 400 responses caused by request validation\n(typically code=`validation_failed`). Keys are field\npaths in dotted/bracket notation; values are short\nhuman explanations safe to inline-surface next to the\noffending form field.\n"}},"required":["code","message"],"title":"ErrorDetail"},"Error":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorDetail"},"request_id":{"type":"string","description":"Server-side request identifier. Echoes the\n`X-Request-ID` response header. Stable across the\nrequest's lifetime, written to structured logs, and\nuseful when reporting issues.\n"}},"required":["error"],"description":"Standard error envelope returned on every non-2xx response.\nContent-Type is `application/json`. The shape mirrors OpenAI /\nAnthropic / Stripe style: a machine-readable `error.code` for\nSDK consumers to switch on, a human `error.message` for UI,\nand an optional `error.fields` map for per-field validation\nerrors. `request_id` matches the `X-Request-ID` response\nheader and is what customers quote when filing support\ntickets.\n","title":"Error"},"CreateAgentRequest":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Optional. Server derives slug from name with a random suffix when omitted; if you supply your own, a collision returns 400 'slug already taken'."},"prompt":{"type":"string"},"first_message":{"type":"string","description":"Greeting spoken verbatim at session start when included in the agent's flow graph."},"language":{"type":"string","description":"ISO 639-1 code. Defaults to 'en' when omitted."},"llm":{"$ref":"#/components/schemas/AgentLLMConfig"},"tts":{"$ref":"#/components/schemas/AgentTTSConfig"},"stt":{"$ref":"#/components/schemas/AgentSTTConfig"},"turn_handling":{"$ref":"#/components/schemas/AgentTurnHandlingConfig"},"memory":{"$ref":"#/components/schemas/AgentMemoryConfig"},"navigator":{"$ref":"#/components/schemas/AgentNavigatorConfig"},"background_noise":{"$ref":"#/components/schemas/AgentBackgroundNoiseConfig"},"widget_config":{"$ref":"#/components/schemas/WidgetConfig"},"is_public":{"type":"boolean","description":"Defaults to false when omitted."},"allowed_origins":{"type":"array","items":{"type":"string"}},"hostname_allowlist":{"type":"array","items":{"type":"string"},"description":"Optional per-agent hostname allowlist (see Agent schema)."},"webhook_url":{"type":"string","description":"Customer-facing post-call webhook URL."},"webhook_secret":{"type":"string","description":"HMAC-SHA256 secret seed. Write-only — never echoed back on\nreads; clients see `webhook_secret_set: true` instead.\n"},"amd":{"$ref":"#/components/schemas/AMDConfig","description":"AMD routing config. Optional on create; omitted means AMD off. See AMDConfig schema."},"save_audio_recording":{"type":"boolean","description":"When set, opts the agent into per-conversation audio recording. Defaults to false when omitted."}},"required":["name","prompt","first_message","tts"],"title":"CreateAgentRequest"},"AgentVoiceType":{"type":"string","enum":["shared"],"description":"Voice provenance. Always `shared` on this endpoint — personal\n/ cloned voices are not exposed here; they stay on\n`GET /v1/voices`.\n","title":"AgentVoiceType"},"AgentVoiceModelName":{"type":"string","enum":["simba-english","simba-multilingual"],"title":"AgentVoiceModelName"},"AgentVoiceLanguage":{"type":"object","properties":{"locale":{"type":"string","description":"BCP-47-ish locale tag (e.g. `en-US`, `de-DE`)."},"preview_audio":{"type":["string","null"],"description":"URL to a short audio preview for this locale, or null if\nno preview is available.\n"}},"required":["locale","preview_audio"],"title":"AgentVoiceLanguage"},"AgentVoiceModel":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/AgentVoiceModelName"},"languages":{"type":"array","items":{"$ref":"#/components/schemas/AgentVoiceLanguage"}}},"required":["name","languages"],"description":"One TTS engine the voice can be synthesised through. Each\nagent voice exposes a multilingual model, plus an\nenglish-specific model for voices whose locale starts with\n`en`.\n","title":"AgentVoiceModel"},"AgentVoiceGender":{"type":"string","enum":["male","female","not_specified"],"description":"Speaker gender classification for the voice. `not_specified` is\nused when the source dataset didn't carry the metadata; treat it\nas a neutral display label rather than a filter gap.\n","title":"AgentVoiceGender"},"AgentVoice":{"type":"object","properties":{"id":{"type":"string","description":"Voice slug. Passed verbatim as `voice_id` on agent writes."},"type":{"$ref":"#/components/schemas/AgentVoiceType"},"display_name":{"type":"string"},"models":{"type":"array","items":{"$ref":"#/components/schemas/AgentVoiceModel"}},"gender":{"$ref":"#/components/schemas/AgentVoiceGender"},"locale":{"type":"string","description":"Default locale for the voice (BCP-47-ish, e.g. `en-US`)."},"preview_audio":{"type":["string","null"],"description":"Preferred preview clip URL, locale-matched when possible."},"avatar_image":{"type":["string","null"],"description":"Avatar URL for the picker UI. Null when no avatar is\nconfigured; the wire is intentionally `null` rather than\n`\"\"` so the picker doesn't render a broken `<img src=\"\">`.\n"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"VMS-defined tags (e.g. `narrator`, `young`)."}},"required":["id","type","display_name","models","gender","locale","preview_audio","avatar_image"],"description":"One row in the curated voice catalogue returned by\n`GET /v1/agents/voices`. Matches the slug set accepted by\nagent create/update.\n","title":"AgentVoice"},"ListAgentVoicesResponse":{"type":"object","properties":{"voices":{"type":"array","items":{"$ref":"#/components/schemas/AgentVoice"}}},"required":["voices"],"description":"Payload for `GET /v1/agents/voices`. The curated agent voice\ncatalogue is bounded (the `ai-api-agents` VMS scope plus a\nhandful of builtins), so it is returned in full with no\npagination metadata.\n","title":"ListAgentVoicesResponse"},"UpdateAgentRequest":{"type":"object","properties":{"name":{"type":"string"},"prompt":{"type":"string"},"first_message":{"type":"string"},"language":{"type":"string"},"llm":{"$ref":"#/components/schemas/AgentLLMConfig"},"tts":{"$ref":"#/components/schemas/AgentTTSConfig"},"stt":{"$ref":"#/components/schemas/AgentSTTConfig"},"turn_handling":{"$ref":"#/components/schemas/AgentTurnHandlingConfig"},"memory":{"$ref":"#/components/schemas/AgentMemoryConfig"},"navigator":{"$ref":"#/components/schemas/AgentNavigatorConfig"},"background_noise":{"$ref":"#/components/schemas/AgentBackgroundNoiseConfig"},"widget_config":{"$ref":"#/components/schemas/WidgetConfig"},"is_public":{"type":"boolean"},"allowed_origins":{"type":"array","items":{"type":"string"}},"hostname_allowlist":{"type":"array","items":{"type":"string"},"description":"When supplied, replaces the stored list. Pass an empty\narray to clear enforcement (public agent is open again).\nOmit the field to leave the existing value unchanged.\n"},"webhook_url":{"type":"string"},"webhook_secret":{"type":"string","description":"Rotate the HMAC secret. Write-only."},"amd":{"$ref":"#/components/schemas/AMDConfig","description":"AMD routing config (PATCH-replace, wholesale). Omit to leave the stored config unchanged."},"save_audio_recording":{"type":"boolean"}},"description":"Body for PATCH /v1/agents/{agent_id}. JSON merge-patch semantics: every\nfield is optional and omitting it leaves the stored value\nunchanged. Inside a nested config block (llm, tts, stt,\nturn_handling, memory, navigator, background_noise, amd) send only\nthe sub-fields you want to change - an explicit null clears a\nnullable sub-field to its default, a value sets it, and omitted\nsub-fields are left as-is. `slug` is intentionally not patchable\n(changing it would break embed URLs).\n","title":"UpdateAgentRequest"},"agent_flow_getSchema_Response_200":{"type":"object","properties":{},"title":"agent_flow_getSchema_Response_200"},"FlowVersion":{"type":"object","properties":{"id":{"type":"string","description":"Flow version id (prefixed external id, `fver_...`)."},"agent_id":{"type":"string"},"version":{"type":"integer","description":"Monotonic revision number within the agent."},"parent_version_id":{"type":["string","null"],"description":"Parent flow version id (prefixed external id, `fver_...`); null for the first version."},"is_active":{"type":"boolean"},"is_draft":{"type":"boolean"},"name":{"type":"string"},"notes":{"type":"string"},"published_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","agent_id","version","is_active","is_draft"],"description":"One published or draft revision of an agent's flow graph.","title":"FlowVersion"},"FlowGraphNodesItems":{"type":"object","properties":{},"title":"FlowGraphNodesItems"},"FlowGraphEdgesItems":{"type":"object","properties":{},"title":"FlowGraphEdgesItems"},"FlowGraphVariablesItems":{"type":"object","properties":{},"title":"FlowGraphVariablesItems"},"FlowGraph":{"type":"object","properties":{"version":{"$ref":"#/components/schemas/FlowVersion"},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/FlowGraphNodesItems"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/FlowGraphEdgesItems"}},"variables":{"type":"array","items":{"$ref":"#/components/schemas/FlowGraphVariablesItems"}}},"required":["version","nodes","edges"],"description":"A flow graph: an ordered set of typed nodes connected by edges,\nplus flow variables. The node, edge, and variable shapes are\ngoverned by the live JSON Schema at GET /v1/agents/flow/schema\nand are intentionally opaque here so this spec cannot drift\nfrom that authoritative definition.\n","title":"FlowGraph"},"FlowTemplate":{"type":"object","properties":{"id":{"type":"string","description":"Flow template id (prefixed external id, `tmpl_...`)."},"key":{"type":"string","description":"Stable unique key for the template."},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"graph":{"$ref":"#/components/schemas/FlowGraph"},"is_seed":{"type":"boolean","description":"True for platform-provided templates."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","key","name","category","graph","is_seed","created_at","updated_at"],"description":"A reusable flow graph that can be cloned onto an agent as a new draft.","title":"FlowTemplate"},"ListFlowTemplatesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"templates":{"type":"array","items":{"$ref":"#/components/schemas/FlowTemplate"}}},"required":["next_cursor","has_more","templates"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListFlowTemplatesResponse"},"FlowGraphInputNodesItems":{"type":"object","properties":{},"title":"FlowGraphInputNodesItems"},"FlowGraphInputEdgesItems":{"type":"object","properties":{},"title":"FlowGraphInputEdgesItems"},"FlowGraphInputVariablesItems":{"type":"object","properties":{},"title":"FlowGraphInputVariablesItems"},"FlowGraphInput":{"type":"object","properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/FlowGraphInputNodesItems"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/FlowGraphInputEdgesItems"}},"variables":{"type":"array","items":{"$ref":"#/components/schemas/FlowGraphInputVariablesItems"}}},"required":["nodes","edges"],"description":"Request-side flow graph: nodes, edges, and variables only.\nUnlike the response-side FlowGraph it carries no `version`\nblock - the server owns version metadata.\n","title":"FlowGraphInput"},"CreateFlowTemplateRequest":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string","description":"Defaults to \"custom\" when omitted."},"graph":{"$ref":"#/components/schemas/FlowGraphInput"}},"required":["key","name","graph"],"description":"Request body for creating (POST) or replacing (PATCH) a flow\ntemplate. PATCH replaces the whole template, it is not a\nfield-by-field patch.\n","title":"CreateFlowTemplateRequest"},"FlowValidationIssue":{"type":"object","properties":{"path":{"type":"string","description":"Node / edge / field path the issue applies to; drives editor highlighting."},"code":{"type":"string","description":"Stable per-issue code, e.g. `tool_call.tool_id.invalid`."},"message":{"type":"string"}},"required":["path","code","message"],"description":"One flow-graph validation problem, located by node/edge/field path.","title":"FlowValidationIssue"},"FlowValidationError":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorDetail"},"request_id":{"type":"string"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/FlowValidationIssue"}}},"required":["error"],"description":"400 body for flow save / publish / template operations. The standard\n`Error` envelope (so clients read `error.code` = `validation_failed`\nand `request_id`) plus the per-issue `issues` array the flow editor\nuses for node highlighting and the Validator-tab list. `issues` is\nabsent on a plain bad request (e.g. an undecodable body, code\n`bad_request`).\n","title":"FlowValidationError"},"CloneFlowTemplateRequest":{"type":"object","properties":{"agent_id":{"type":"string","description":"The agent that receives the cloned graph as a new draft."}},"required":["agent_id"],"title":"CloneFlowTemplateRequest"},"EvaluationCriterion":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"}},"required":["id","name","description"],"description":"One LLM-scored assertion about the call (\"Did the agent confirm the customer's name?\").","title":"EvaluationCriterion"},"DataCollectionFieldType":{"type":"string","enum":["string","int","number","boolean"],"title":"DataCollectionFieldType"},"DataCollectionField":{"type":"object","properties":{"key":{"type":"string"},"description":{"type":"string"},"type":{"$ref":"#/components/schemas/DataCollectionFieldType"}},"required":["key","description","type"],"description":"A structured value the post-call evaluator should extract from the\ntranscript. `int` is distinct from `number` so downstream consumers\nreceive whole integers without a synthetic decimal.\n","title":"DataCollectionField"},"EvaluationConfig":{"type":"object","properties":{"criteria":{"type":"array","items":{"$ref":"#/components/schemas/EvaluationCriterion"}},"data_collection":{"type":"array","items":{"$ref":"#/components/schemas/DataCollectionField"}}},"required":["criteria","data_collection"],"title":"EvaluationConfig"},"UpdateEvaluationConfigRequest":{"type":"object","properties":{"criteria":{"type":"array","items":{"$ref":"#/components/schemas/EvaluationCriterion"}},"data_collection":{"type":"array","items":{"$ref":"#/components/schemas/DataCollectionField"}}},"required":["criteria","data_collection"],"title":"UpdateEvaluationConfigRequest"},"GetFlowResponse":{"type":"object","properties":{"draft":{"$ref":"#/components/schemas/FlowGraph"},"active":{"$ref":"#/components/schemas/FlowGraph"}},"description":"Response for GET /v1/agents/{agent_id}/flow.","title":"GetFlowResponse"},"PutFlowRequestNodesItems":{"type":"object","properties":{},"title":"PutFlowRequestNodesItems"},"PutFlowRequestEdgesItems":{"type":"object","properties":{},"title":"PutFlowRequestEdgesItems"},"PutFlowRequestVariablesItems":{"type":"object","properties":{},"title":"PutFlowRequestVariablesItems"},"PutFlowRequest":{"type":"object","properties":{"name":{"type":"string"},"notes":{"type":"string"},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/PutFlowRequestNodesItems"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/PutFlowRequestEdgesItems"}},"variables":{"type":"array","items":{"$ref":"#/components/schemas/PutFlowRequestVariablesItems"}}},"required":["nodes","edges"],"description":"Request body for PUT /v1/agents/{agent_id}/flow. Replaces the draft graph.","title":"PutFlowRequest"},"PublishFlowRequest":{"type":"object","properties":{"notes":{"type":"string","description":"Optional changelog note recorded on the published version."}},"description":"Optional body for POST /v1/agents/{agent_id}/flow/publish.","title":"PublishFlowRequest"},"RollbackFlowRequest":{"type":"object","properties":{"version_id":{"type":"string","description":"The flow version to roll back to (prefixed external id, `fver_...`)."}},"required":["version_id"],"title":"RollbackFlowRequest"},"ListFlowVersionsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"versions":{"type":"array","items":{"$ref":"#/components/schemas/FlowVersion"}}},"required":["next_cursor","has_more","versions"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListFlowVersionsResponse"},"DynamicVariableType":{"type":"string","enum":["string","number","boolean","json"],"description":"Declared type of a customer-scope variable. Enforced at save time\nand again at session-start when an override value is supplied.\n- `string`  - plain text value; interpolated verbatim with `{{name}}`\n- `number`  - numeric value; rendered as its decimal representation\n- `boolean` - `true` or `false`\n- `json`    - any valid JSON value; use `{{name|json}}` to inject\n              safely inside JSON tool bodies\n","title":"DynamicVariableType"},"DynamicVariable":{"type":"object","properties":{"key":{"type":"string","description":"Variable name. Must match `[a-zA-Z0-9_]+`. The `system__` prefix\nis reserved for platform-populated variables and will be rejected.\n"},"type":{"$ref":"#/components/schemas/DynamicVariableType"},"default":{"description":"Optional default value used when no per-session override is\nsupplied. Must conform to the declared `type`.\n"},"description":{"type":"string","description":"Human-readable note describing the variable."}},"required":["key","type"],"description":"One customer-scope variable definition on an agent. Referenced in\nprompts, first messages, and webhook tool configs via `{{key}}` or\n`{{key|json}}`. Missing variables render as empty string at dispatch\ntime - a typo never breaks a session.\n","title":"DynamicVariable"},"SystemVariableDoc":{"type":"object","properties":{"key":{"type":"string","description":"The reserved variable key (always starts with `system__`)."},"description":{"type":"string","description":"What the variable contains and when it is populated."}},"required":["key","description"],"description":"Documents one reserved `system__*` variable that the platform\nauto-populates at session start. Customers cannot define or\noverride these keys.\n","title":"SystemVariableDoc"},"ListDynamicVariablesResponse":{"type":"object","properties":{"variables":{"type":"array","items":{"$ref":"#/components/schemas/DynamicVariable"},"description":"Customer-defined variables for this agent."},"system_variables":{"type":"array","items":{"$ref":"#/components/schemas/SystemVariableDoc"},"description":"Platform-populated `system__*` variables, provided for\nreference. This list is the same for every agent.\n"}},"required":["variables","system_variables"],"description":"Response for `GET /v1/agents/{agent_id}/variables`. Returns both the\ncustomer-scope variable catalogue and the read-only `system__*`\ncatalogue so a single source of truth is available client-side.\n","title":"ListDynamicVariablesResponse"},"UpdateDynamicVariablesRequest":{"type":"object","properties":{"variables":{"type":"array","items":{"$ref":"#/components/schemas/DynamicVariable"},"description":"The new variable list. Replaces the existing list entirely."}},"required":["variables"],"description":"PATCH body for `PATCH /v1/agents/{agent_id}/variables`. Replaces the\nstored variable list wholesale. Pass an empty array to clear all\nvariables. Up to 20 variables per agent.\n","title":"UpdateDynamicVariablesRequest"},"ConversationStatus":{"type":"string","enum":["pending","active","completed","failed"],"title":"ConversationStatus"},"ConversationTransport":{"type":"string","enum":["web","phone","whatsapp","sip_inbound","sip_outbound"],"description":"How the caller reached the agent. `web` is the browser /\nSDK realtime path; the `sip_*` and `phone` variants come\nfrom the telephony stack.\n","title":"ConversationTransport"},"ConversationEndReason":{"type":"string","enum":["voicemail_message_left","voicemail_hangup","ivr_hangup","unavailable_hangup","agent_ended","caller_hangup","inactivity_timeout","loop_detected","max_duration_reached","over_capacity","dial_no_answer","dial_busy","dial_rejected","dial_failed"],"description":"Coarse termination category. Most reasons are assigned by the\nagent runtime as the call ends; `caller_hangup` may also be\napplied server-side as a post-call catch-all. The `dial_*`\nreasons are assigned server-side on a `failed` conversation\nfor an outbound call that never connected.\n* `voicemail_message_left` — AMD machine-vm + we spoke the configured drop-message.\n* `voicemail_hangup` — AMD machine-vm + we terminated silently (action=hangup or empty-message bypass).\n* `ivr_hangup` — AMD machine-ivr + action=hangup.\n* `unavailable_hangup` — AMD machine-unavailable (mailbox full / disconnected).\n* `agent_ended` — LLM-driven end_call builtin.\n* `inactivity_timeout` — the call ended after the configured silence window elapsed with no activity.\n* `loop_detected` — a loop guard force-ended the call after several consecutive near-identical user turns (typically an IVR replaying its menu while the agent kept reacting instead of ending the call).\n* `max_duration_reached` - the max-call-duration limit force-ended the call at the platform ceiling (a safety bound on runaway calls).\n* `over_capacity` — inbound call refused because the workspace was over its active-call concurrency cap; the busy message played and the call hung up. Stamped server-side and excluded from billing.\n* `caller_hangup` — the caller's leg went away. Stamped immediately when a SIP disconnect is observed; otherwise applied server-side shortly after the call ends as a catch-all (web tab close, network blip, etc.).\n* `dial_no_answer` — outbound dial: callee did not pick up (SIP 408/480/487, the ringing timeout expired).\n* `dial_busy` — outbound dial: the line was busy (SIP 486/600).\n* `dial_rejected` — outbound dial: the call was actively refused (SIP 401/403/407 carrier auth/permission, or 603/607/608 callee decline).\n* `dial_failed` — outbound dial: any other failure to connect (invalid number, carrier 5xx, malformed trunk address, TLS requirement, transport error). On a `failed` conversation with NULL `duration_ms`.\n* `null` — the termination category was not recorded. Legacy calls only; current calls always carry a reason.\n","title":"ConversationEndReason"},"AgentSnapshotBackgroundNoisePreset":{"type":"string","enum":["office","city","forest","crowded_room","keyboard_typing","hold_music"],"description":"Ambient-bed preset at call time; null = no background noise.","title":"AgentSnapshotBackgroundNoisePreset"},"AgentSnapshot":{"type":"object","properties":{"schema_version":{"type":"integer"},"captured_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"prompt":{"type":"string"},"first_message":{"type":"string"},"language":{"type":"string"},"llm_provider":{"type":"string","description":"Resolved provider that actually ran (a \"Platform default\"\nagent freezes the concrete platform pair at call time).\n"},"llm_model":{"type":"string"},"llm_base_url":{"type":["string","null"],"description":"Custom-provider endpoint base URL; null for managed providers. The bearer key is never captured."},"llm_extra_body":{"type":["object","null"],"additionalProperties":{"description":"Any type"},"description":"Extra chat.completions body forwarded verbatim for custom-provider agents; null otherwise."},"voice_id":{"type":"string"},"temperature":{"type":"number","format":"double"},"memory_enabled":{"type":"boolean"},"memory_retention_days":{"type":"integer"},"tts_playback_rate":{"type":["number","null"],"format":"double","description":"Post-process time-stretch at call time; null = no time-stretch (1x)."},"response_delay_seconds":{"type":["number","null"],"format":"double","description":"Silence-wait override at call time; null = stack default endpointing."},"stt_override":{"type":["string","null"],"description":"Streaming-STT stack the call dispatched with; null = the worker's platform default."},"amd":{"$ref":"#/components/schemas/AMDConfig"},"save_audio_recording":{"type":"boolean"},"navigator_mode":{"type":"boolean"},"ivr_memory_enabled":{"type":"boolean"},"inactivity_timeout_seconds":{"type":["integer","null"],"description":"Silence-tolerance override at call time; null = platform default."},"background_noise_preset":{"$ref":"#/components/schemas/AgentSnapshotBackgroundNoisePreset","description":"Ambient-bed preset at call time; null = no background noise."},"background_noise_volume":{"type":["number","null"],"format":"double"}},"description":"Frozen copy of the agent's behavioral configuration captured at\nconversation-create time so the detail view can\nrender historical calls accurately even after the live agent\nhas been edited. Carries its own `schema_version` because the\nsnapshot shape evolves independently of the live Agent shape.\n\nField-presence contract: new snapshots emit every field\n(explicit null when unset). A key that is ABSENT from a stored\nsnapshot means the snapshot pre-dates that field's capture;\nreaders hide the value instead of guessing a default.\n","title":"AgentSnapshot"},"ConversationIvrSurrenderReason":{"type":"string","enum":["no_goal","no_cached_menu","below_threshold","fingerprint_mismatch","goal_ambiguous","child_cache_miss","dtmf_send_failure","matched_option_missing_dtmf","disabled","repeated_prompt_max_retries"],"description":"Canonical code the worker emits when the IVR\nnavigator gave up. NULL when the navigator completed\ncleanly OR never started a plan.\n* `no_goal` - the goal extractor returned empty.\n* `no_cached_menu` - AMD-time cache miss for the root fingerprint.\n* `below_threshold` - cached menu loaded but confidence < threshold.\n* `fingerprint_mismatch` - in-call prompt diverged from the cached menu fingerprint.\n* `goal_ambiguous` - cached options matched the goal more than once or not at all.\n* `child_cache_miss` - sub-menu fingerprint had no cached row.\n* `dtmf_send_failure` - DTMF press could not be delivered.\n* `matched_option_missing_dtmf` - defensive shape guard.\n* `disabled` - per-agent toggle off OR operator kill switch on.\n* `repeated_prompt_max_retries` - bounded press-retry on the same fingerprint hit its cap of 1.\n","title":"ConversationIvrSurrenderReason"},"Conversation":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`conv_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nfor the agent that answers this conversation.\n"},"status":{"$ref":"#/components/schemas/ConversationStatus"},"transport":{"$ref":"#/components/schemas/ConversationTransport"},"created_at":{"type":"string","format":"date-time","description":"When the conversation row was created (the call was\ninitiated). Always present, including for conversations\nthat never started — unlike `started_at` — so it is the\ntimestamp to display and sort pending calls by.\n"},"started_at":{"type":["string","null"],"format":"date-time","description":"Set when the first user participant joins the realtime\nvoice session. Null between CreateConversation and the\nparticipant-joined event, and stays null if no user ever\njoins.\n"},"ended_at":{"type":["string","null"],"format":"date-time"},"duration_ms":{"type":["integer","null"]},"cost_cents":{"type":["integer","null"]},"recording_url":{"type":["string","null"]},"recording_started_at":{"type":["string","null"],"format":"date-time","description":"When the recording file actually began capturing audio\n(LiveKit egress file started_at). Anchor transcript message\noffsets on this — not `started_at` — when seeking the\nrecording: the file's first frame trails the participant\njoin by the egress recorder's spin-up (~1-2s). Null when\nthere is no recording or the row pre-dates the field.\n"},"end_reason":{"$ref":"#/components/schemas/ConversationEndReason","description":"Coarse termination category. Most reasons are assigned by the\nagent runtime as the call ends; `caller_hangup` may also be\napplied server-side as a post-call catch-all. The `dial_*`\nreasons are assigned server-side on a `failed` conversation\nfor an outbound call that never connected.\n* `voicemail_message_left` — AMD machine-vm + we spoke the configured drop-message.\n* `voicemail_hangup` — AMD machine-vm + we terminated silently (action=hangup or empty-message bypass).\n* `ivr_hangup` — AMD machine-ivr + action=hangup.\n* `unavailable_hangup` — AMD machine-unavailable (mailbox full / disconnected).\n* `agent_ended` — LLM-driven end_call builtin.\n* `inactivity_timeout` — the call ended after the configured silence window elapsed with no activity.\n* `loop_detected` — a loop guard force-ended the call after several consecutive near-identical user turns (typically an IVR replaying its menu while the agent kept reacting instead of ending the call).\n* `max_duration_reached` - the max-call-duration limit force-ended the call at the platform ceiling (a safety bound on runaway calls).\n* `over_capacity` — inbound call refused because the workspace was over its active-call concurrency cap; the busy message played and the call hung up. Stamped server-side and excluded from billing.\n* `caller_hangup` — the caller's leg went away. Stamped immediately when a SIP disconnect is observed; otherwise applied server-side shortly after the call ends as a catch-all (web tab close, network blip, etc.).\n* `dial_no_answer` — outbound dial: callee did not pick up (SIP 408/480/487, the ringing timeout expired).\n* `dial_busy` — outbound dial: the line was busy (SIP 486/600).\n* `dial_rejected` — outbound dial: the call was actively refused (SIP 401/403/407 carrier auth/permission, or 603/607/608 callee decline).\n* `dial_failed` — outbound dial: any other failure to connect (invalid number, carrier 5xx, malformed trunk address, TLS requirement, transport error). On a `failed` conversation with NULL `duration_ms`.\n* `null` — the termination category was not recorded. Legacy calls only; current calls always carry a reason.\n"},"metadata":{"type":"object","additionalProperties":{"description":"Any type"}},"caller_identity":{"type":"string","description":"Stable caller key (LiveKit participant identity) persisted\nat session start so the post-call memory extractor can\npivot memories by `(agent_id, caller_identity)`. Empty\nstring for anonymous widget sessions.\n"},"from_number":{"type":["string","null"],"description":"E.164 of the phone number that placed the call. For\n`sip_outbound` this is the workspace number used as the\ncaller ID; for `sip_inbound` it is the external caller's\nnumber. Null for `web` conversations and for older\noutbound rows, where the dialing caller id was not recorded\nbefore this field existed.\n"},"to_number":{"type":["string","null"],"description":"E.164 of the phone number that received the call. For\n`sip_outbound` this is the external callee; for\n`sip_inbound` it is the workspace number the caller\ndialed. Null for `web` conversations and for legacy\ninbound rows whose room name did not embed the dialed\nnumber.\n"},"agent_snapshot":{"$ref":"#/components/schemas/AgentSnapshot","description":"Frozen snapshot of the agent's configuration at create\ntime. Populated only on detail responses; list responses\nintentionally skip the column to keep the row small.\n"},"dynamic_variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Customer-facing dynamic variables this call ran with: the\nagent's stored variable defaults overlaid with the\nper-session `dynamic_variables` overrides, resolved to\ntheir values. Reserved `system__*` keys are excluded —\nthey are runtime-derived and not part of the audit\nsnapshot. Omitted for SIP inbound calls (which take no\nper-session variables) and for legacy conversations\nrecorded before this field existed. Populated only on\ndetail responses; the\nlist endpoint skips it, mirroring `agent_snapshot`.\n"},"message_count":{"type":"integer","description":"Populated only on the list endpoint via a correlated\nsubquery. Zero on single-row reads where the join cost\nisn't paid.\n"},"ivr_menu_id":{"type":["string","null"],"description":"Audit pointer at the cached IVR menu the\nnavigator consulted on this call. NULL when the navigator\nnever engaged OR after the referenced menu was\ninvalidated (FK is ON DELETE SET NULL).\n"},"ivr_path_taken":{"type":["array","null"],"items":{"type":"object","additionalProperties":{"description":"Any type"}},"description":"Ordered log of the navigator's per-call presses:\n`[{fingerprint, dtmf, label}, ...]`. Empty array means\n\"navigator engaged but pressed nothing\" (distinct from\nNULL = \"navigator never engaged\").\n"},"ivr_surrender_reason":{"$ref":"#/components/schemas/ConversationIvrSurrenderReason","description":"Canonical code the worker emits when the IVR\nnavigator gave up. NULL when the navigator completed\ncleanly OR never started a plan.\n* `no_goal` - the goal extractor returned empty.\n* `no_cached_menu` - AMD-time cache miss for the root fingerprint.\n* `below_threshold` - cached menu loaded but confidence < threshold.\n* `fingerprint_mismatch` - in-call prompt diverged from the cached menu fingerprint.\n* `goal_ambiguous` - cached options matched the goal more than once or not at all.\n* `child_cache_miss` - sub-menu fingerprint had no cached row.\n* `dtmf_send_failure` - DTMF press could not be delivered.\n* `matched_option_missing_dtmf` - defensive shape guard.\n* `disabled` - per-agent toggle off OR operator kill switch on.\n* `repeated_prompt_max_retries` - bounded press-retry on the same fingerprint hit its cap of 1.\n"}},"required":["id","agent_id","status","transport","created_at","metadata","message_count"],"title":"Conversation"},"ListConversationsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"conversations":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}}},"required":["next_cursor","has_more","conversations"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListConversationsResponse"},"RecentCallee":{"type":"object","properties":{"phone":{"type":"string","description":"E.164 phone number that was dialled."},"last_called_at":{"type":"string","format":"date-time","description":"Timestamp of the most recent outbound call to this number."}},"required":["phone","last_called_at"],"description":"One distinct phone number this workspace has dialled, with the timestamp of the most recent outbound call to it.","title":"RecentCallee"},"ListRecentCalleesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"callees":{"type":"array","items":{"$ref":"#/components/schemas/RecentCallee"}}},"required":["next_cursor","has_more","callees"],"description":"Payload for GET /v1/agents/conversations/recent-callees.","title":"ListRecentCalleesResponse"},"ConversationStats":{"type":"object","properties":{"total":{"type":"integer","format":"int64"},"completed":{"type":"integer","format":"int64"},"failed":{"type":"integer","format":"int64"},"active":{"type":"integer","format":"int64"},"pending":{"type":"integer","format":"int64"},"avg_duration_ms":{"type":["number","null"],"format":"double"},"avg_cost_cents":{"type":["number","null"],"format":"double"}},"required":["total","completed","failed","active","pending","avg_duration_ms","avg_cost_cents"],"description":"Counts + averages over the caller's conversations matching the supplied filters. AVG fields are null when no rows match the FILTER predicate.","title":"ConversationStats"},"EvaluationKind":{"type":"string","enum":["criterion","summary","data"],"title":"EvaluationKind"},"EvaluationStatus":{"type":"string","enum":["success","failure","unknown"],"description":"Three-state criterion result. `unknown` means the criterion did not apply to this call.","title":"EvaluationStatus"},"Evaluation":{"type":"object","properties":{"id":{"type":"string"},"conversation_id":{"type":"string","description":"Prefixed wire identifier (`conv_<26 char Crockford base32>`)\nof the conversation this evaluation is attached to.\n"},"kind":{"$ref":"#/components/schemas/EvaluationKind"},"criterion_id":{"type":["string","null"]},"name":{"type":"string"},"status":{"oneOf":[{"$ref":"#/components/schemas/EvaluationStatus"},{"type":"null"}],"description":"Three-state criterion result. `unknown` means the criterion did not apply to this call."},"passed":{"type":["boolean","null"]},"score":{"type":["number","null"],"format":"double"},"rationale":{"type":"string"},"data":{"description":"Structured data-collection payload (present only on `kind=data` rows)."},"created_at":{"type":"string","format":"date-time"}},"required":["id","conversation_id","kind","name","rationale","created_at"],"description":"Three flavours coexist, discriminated by `kind`:\n- `criterion` rows carry `status` + `passed` + `score` + `rationale` for one criterion\n- `summary` row carries overall sentiment + rationale in `rationale`\n- `data` row carries the structured data-collection payload in `data`\n\n`status` is the canonical three-state result. `passed` is a\nderived boolean kept for backwards compatibility with earlier\nwebhook consumers: success→true, failure→false, unknown→null.\n","title":"Evaluation"},"ListEvaluationsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"evaluations":{"type":"array","items":{"$ref":"#/components/schemas/Evaluation"}}},"required":["next_cursor","has_more","evaluations"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListEvaluationsResponse"},"Memory":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`memory_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the owning agent.\n"},"caller_identity":{"type":"string","description":"Stable caller key (LiveKit participant identity) the memory is scoped to."},"fact":{"type":"string","description":"Short third-person statement about the caller."},"source_conversation_id":{"type":["string","null"],"description":"When set, the prefixed wire identifier\n(`conv_<26 char Crockford base32>`) of the conversation this\nmemory was extracted from. May be null if the source was\ndeleted.\n"},"confidence":{"type":"number","format":"double","description":"LLM self-reported 0-1 confidence in the fact's durability and relevance."},"score":{"type":"number","format":"double","description":"Populated only on retrieval hits — recency-weighted cosine similarity."},"created_at":{"type":"string","format":"date-time"}},"required":["id","agent_id","caller_identity","fact","confidence","created_at"],"description":"One salient fact extracted post-call about a specific caller on\na specific agent. Retrieved at the next conversation-start for\nthe same caller and injected into the agent's system prompt via\nthe `{{memory}}` template variable.","title":"Memory"},"ListMemoriesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"memories":{"type":"array","items":{"$ref":"#/components/schemas/Memory"}}},"required":["next_cursor","has_more","memories"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListMemoriesResponse"},"MessageRole":{"type":"string","enum":["user","assistant","system","tool","operator"],"description":"Who produced the turn: `user` is the caller, `assistant` the AI\nagent, `tool` a tool call, `system` a transcript annotation (such\nas the take-over window markers), and `operator` a human\noperator's speech while they have taken the call over.\n","title":"MessageRole"},"Message":{"type":"object","properties":{"id":{"type":"string"},"conversation_id":{"type":"string","description":"Prefixed wire identifier (`conv_<26 char Crockford base32>`)\nof the parent conversation.\n"},"role":{"$ref":"#/components/schemas/MessageRole","description":"Who produced the turn: `user` is the caller, `assistant` the AI\nagent, `tool` a tool call, `system` a transcript annotation (such\nas the take-over window markers), and `operator` a human\noperator's speech while they have taken the call over.\n"},"content":{"type":"string"},"tool_name":{"type":["string","null"]},"tool_args":{"type":["object","null"],"additionalProperties":{"description":"Any type"}},"tool_result":{"description":"Arbitrary JSON value returned by the tool (object, array, string, or primitive)."},"started_at":{"type":"string","format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"}},"required":["id","conversation_id","role","content","started_at"],"title":"Message"},"ListMessagesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"messages":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}},"required":["next_cursor","has_more","messages"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListMessagesResponse"},"RetrievalLogResult":{"type":"object","properties":{"chunk_id":{"type":"string"},"document_id":{"type":"string"},"kb_id":{"type":"string","description":"Prefixed wire identifier (`kb_<26 char Crockford base32>`)\nof the knowledge base the matched chunk lives in.\n"},"filename":{"type":"string"},"chunk_index":{"type":"integer"},"content":{"type":"string"},"score":{"type":"number","format":"double"}},"required":["chunk_id","document_id","kb_id","filename","chunk_index","content","score"],"description":"One ranked chunk inside a retrieval log row. Denormalised so\ndeleting a chunk or document after the call doesn't render\nhistorical logs unreadable.\n","title":"RetrievalLogResult"},"RetrievalLogEntry":{"type":"object","properties":{"id":{"type":"string"},"conversation_id":{"type":"string","description":"Prefixed wire identifier (`conv_<26 char Crockford base32>`)\nof the conversation.\n"},"query":{"type":"string"},"results":{"type":"array","items":{"$ref":"#/components/schemas/RetrievalLogResult"}},"limit":{"type":"integer"},"hit_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}},"required":["id","conversation_id","query","results","limit","hit_count","created_at"],"description":"One `search_knowledge` invocation recorded against a\nconversation. Powers the Retrieval panel on the conversation\ndetail view.\n","title":"RetrievalLogEntry"},"ListRetrievalLogsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"entries":{"type":"array","items":{"$ref":"#/components/schemas/RetrievalLogEntry"}}},"required":["next_cursor","has_more","entries"],"description":"Payload for `GET /v1/agents/conversations/{conversation_id}/retrieval-log`.","title":"ListRetrievalLogsResponse"},"ShadowConversationResponse":{"type":"object","properties":{"conversation_id":{"type":"string"},"signaling_url":{"type":"string","description":"wss://… signaling URL the realtime client connects to."},"token":{"type":"string","description":"Short-lived realtime access token. The grant is listen-only\n(cannot publish audio or data) and hidden, so the observer can\nhear the call but cannot speak and is invisible to the caller\nand the agent.\n"},"identity":{"type":"string","description":"Opaque participant identity tag (e.g. shadow_<hex>). Visible only to admin tooling."},"expires_at":{"type":"string","format":"date-time","description":"When the token stops being accepted by the realtime provider. Re-mint past this point."}},"required":["conversation_id","signaling_url","token","identity","expires_at"],"description":"Connection details for an authorized observer (workspace owner or\nadmin) joining an active conversation as a hidden, listen-only\nparticipant. A realtime client consumes `signaling_url` + `token`\nto attach to the live room and play the agent + caller audio\ntracks.\n","title":"ShadowConversationResponse"},"WebhookDeliveryStatus":{"type":"string","enum":["pending","delivered","failed"],"description":"Lifecycle of a post-call webhook delivery row. The sender\nupdates the same row across retries so the UI always sees the\nlatest outcome.\n","title":"WebhookDeliveryStatus"},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string"},"conversation_id":{"type":"string","description":"Prefixed wire identifier (`conv_<26 char Crockford base32>`)\nof the conversation that triggered this delivery.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the agent.\n"},"url":{"type":"string"},"event":{"type":"string"},"status":{"$ref":"#/components/schemas/WebhookDeliveryStatus"},"attempt_count":{"type":"integer"},"last_attempt_at":{"type":"string","format":"date-time"},"last_status_code":{"type":"integer"},"last_error":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"request_body":{"type":"string","description":"The exact JSON body Speechify POSTed to your webhook URL. This\nis the verbatim payload the `Speechify-Signature` HMAC was\ncomputed over (as `<t>.<raw_body>`), so you can re-verify the\nsignature against it. Absent on deliveries that pre-date this\ncapture.\n"},"request_headers":{"type":"object","additionalProperties":{"type":"string"},"description":"The HTTP headers Speechify sent with the delivery, including\n`Speechify-Signature` (`t=<unix>,v0=<hmac-sha256-hex>`),\n`Speechify-Event`, and `Speechify-Delivery-Id`. Reflects the\nmost recent attempt.\n"},"last_response_body":{"type":"string","description":"The response body your server returned on the most recent\nattempt, truncated to 8 KiB. Useful for debugging a non-2xx\nresponse. Absent when no response was received (transport\nerror) or on pre-capture deliveries.\n"},"last_response_headers":{"type":"object","additionalProperties":{"type":"string"},"description":"The response headers your server returned on the most recent\nattempt.\n"}},"required":["id","conversation_id","agent_id","url","event","status","attempt_count","created_at"],"description":"Post-call webhook delivery log row. One row per\n`(conversation, webhook-url)`; updated in place across retry\nattempts.\n","title":"WebhookDelivery"},"ListWebhookDeliveriesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}},"required":["next_cursor","has_more","deliveries"],"description":"Payload for `GET /v1/agents/conversations/{conversation_id}/webhook-deliveries`.","title":"ListWebhookDeliveriesResponse"},"CreateConversationRequest":{"type":"object","properties":{"transport":{"type":["string","null"],"description":"Transport hint. Omit to use the agent's default."},"dynamic_variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-session variable overrides that merge on top of the agent's\nstored variable defaults for this one conversation. Keys in the\nreserved `system__` namespace are rejected. Values must match the\ndeclared type of the corresponding variable definition on the agent.\n"}},"description":"Optional body for `POST /v1/agents/{agent_id}/conversations`.","title":"CreateConversationRequest"},"CreateConversationResponse":{"type":"object","properties":{"conversation":{"$ref":"#/components/schemas/Conversation"},"token":{"type":"string","description":"Short-lived realtime session access token (JWT)."},"url":{"type":"string","description":"Realtime session wss:// URL to connect to."}},"required":["conversation","token","url"],"description":"Returned when a conversation is created. The `token` + `url`\nlet the caller connect its browser/SDK directly to the\nrealtime voice session — the agent that answers is dispatched\nserver-side.\n","title":"CreateConversationResponse"},"CreateSessionRequest":{"type":"object","properties":{"user_identity":{"type":"string","description":"Opaque identifier for the end-user (e.g. your app's user ID). Stamped onto the conversation. Optional - defaults to an anonymous per-session ID."},"dynamic_variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-session variable overrides that merge on top of the agent's\nstored variable defaults for this one session. Keys in the\nreserved `system__` namespace are rejected at this boundary.\nValues must match the declared type of the corresponding variable\ndefinition on the agent (a `string` type expects a JSON string,\n`number` expects a JSON number, etc.).\n"}},"description":"Optional body for `POST /v1/agents/{agent_id}/sessions`. Widget embeds usually pass nothing.","title":"CreateSessionRequest"},"KnowledgeBase":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`kb_<26 char Crockford base32>`).\n"},"name":{"type":"string","description":"Human-readable label for the knowledge base."},"description":{"type":"string","description":"Optional description."},"document_count":{"type":"integer","description":"Number of ingested documents."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","description","document_count","created_at","updated_at"],"description":"A bundle of documents that can be attached to one or more voice\nagents. Chunks across every document in the knowledge base are\nembedded and searched together.","title":"KnowledgeBase"},"ListKnowledgeBasesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"knowledge_bases":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeBase"}}},"required":["next_cursor","has_more","knowledge_bases"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListKnowledgeBasesResponse"},"CreateKnowledgeBaseRequest":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable label."},"description":{"type":"string","description":"Optional description."}},"required":["name"],"title":"CreateKnowledgeBaseRequest"},"SearchKnowledgeBasesRequest":{"type":"object","properties":{"query":{"type":"string","description":"Natural-language search query."},"kb_ids":{"type":"array","items":{"type":"string"},"description":"Knowledge bases to search across. Results scoped to caller-owned entries; unknown IDs are silently ignored."},"limit":{"type":"integer","default":5,"description":"Max hits to return (default 5, capped at 50)."}},"required":["query","kb_ids"],"title":"SearchKnowledgeBasesRequest"},"KnowledgeBaseSearchHit":{"type":"object","properties":{"chunk_id":{"type":"string"},"document_id":{"type":"string"},"kb_id":{"type":"string"},"filename":{"type":"string"},"chunk_index":{"type":"integer"},"content":{"type":"string"},"score":{"type":"number","format":"double","description":"Cosine similarity (higher = more relevant)."}},"required":["chunk_id","document_id","kb_id","filename","chunk_index","content","score"],"title":"KnowledgeBaseSearchHit"},"SearchKnowledgeBasesResponse":{"type":"object","properties":{"hits":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeBaseSearchHit"}}},"required":["hits"],"title":"SearchKnowledgeBasesResponse"},"UpdateKnowledgeBaseRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}},"title":"UpdateKnowledgeBaseRequest"},"KnowledgeBaseDocumentSourceKind":{"type":"string","enum":["file","url","text"],"description":"How the document entered the KB. `file` is the upload path,\n`text` is inline pasted content, `url` is fetched via\nFirecrawl. Sitemap and crawl imports also produce `url` rows.\n","title":"KnowledgeBaseDocumentSourceKind"},"KnowledgeBaseDocumentStatus":{"type":"string","enum":["fetching","embedding","ready","failed"],"description":"Document lifecycle. `fetching` is the pre-scrape state used\nonly by url-sourced rows; file and text docs skip straight\nto `embedding` because their content is available\nsynchronously. Terminal states are `ready` and `failed`.\n","title":"KnowledgeBaseDocumentStatus"},"KnowledgeBaseDocument":{"type":"object","properties":{"id":{"type":"string"},"kb_id":{"type":"string","description":"Prefixed wire identifier (`kb_<26 char Crockford base32>`) of\nthe knowledge base the document belongs to.\n"},"source_kind":{"$ref":"#/components/schemas/KnowledgeBaseDocumentSourceKind"},"source_url":{"type":"string","description":"Source URL for url-sourced documents (and the sitemap /\ncrawl imports that produce them). Empty string for file\nand text rows.\n"},"folder_id":{"type":["string","null"],"description":"Folder this document lives in. Null for root-level\n(unfiled) documents. Mutated via the move endpoint.\n"},"filename":{"type":"string"},"content_type":{"type":"string"},"byte_size":{"type":"integer","format":"int64"},"char_count":{"type":"integer"},"chunk_count":{"type":"integer"},"status":{"$ref":"#/components/schemas/KnowledgeBaseDocumentStatus"},"error":{"type":"string","description":"Populated when status is failed."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","kb_id","source_kind","folder_id","filename","content_type","byte_size","char_count","chunk_count","status","created_at","updated_at"],"title":"KnowledgeBaseDocument"},"ListKnowledgeBaseDocumentsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"documents":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeBaseDocument"}}},"required":["next_cursor","has_more","documents"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListKnowledgeBaseDocumentsResponse"},"BatchDeleteDocumentsRequest":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"}}},"required":["ids"],"description":"Body for DELETE /v1/agents/knowledge-bases/{kb_id}/documents/batch. All\nids must belong to the supplied KB; capped at 200 ids per\ncall.\n","title":"BatchDeleteDocumentsRequest"},"BatchMoveDocumentsRequest":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"}},"folder_id":{"type":["string","null"],"description":"Destination folder. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null moves every\ndocument to the knowledge base root.\n"}},"required":["ids","folder_id"],"description":"Body for PATCH /v1/agents/knowledge-bases/{kb_id}/documents/batch/move.\nCapped at 200 ids per call. Pass `folder_id: null` to move to\nroot.\n","title":"BatchMoveDocumentsRequest"},"CreateCrawlImportRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"max_pages":{"type":"integer"},"max_depth":{"type":"integer"},"folder_id":{"type":["string","null"],"description":"Folder to import the documents into. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null/omitted = root.\n"}},"required":["url"],"title":"CreateCrawlImportRequest"},"ImportJobKind":{"type":"string","enum":["sitemap","crawl","refresh","urls"],"title":"ImportJobKind"},"JobStatus":{"type":"string","enum":["pending","running","completed","failed","cancelled"],"description":"The one lifecycle vocabulary shared by every async job (batch\ncalls, knowledge-base imports, agent-test runs, suite runs):\n`pending` → `running` → a terminal state.\n\n- `pending` - accepted but not yet executing (queued for a worker,\n  or deferred to a future scheduled time).\n- `running` - actively executing.\n- `completed` - ran to conclusion. The single terminal-success\n  verb. For a job that produces a pass/fail judgment (an agent-test\n  run), this means it produced a verdict - read the separate\n  `verdict` field for the judgment, not this status.\n- `failed` - could not complete (an infrastructure or input\n  failure), distinct from a `completed` job whose `verdict` is\n  `failed`.\n- `cancelled` - cancelled before reaching a natural terminal state.\n","title":"JobStatus"},"ImportJob":{"type":"object","properties":{"id":{"type":"string"},"kb_id":{"type":"string"},"kind":{"$ref":"#/components/schemas/ImportJobKind"},"status":{"$ref":"#/components/schemas/JobStatus"},"total":{"type":"integer","description":"Total URLs to process (the progress denominator)."},"completed":{"type":"integer","description":"URLs imported successfully."},"failed":{"type":"integer","description":"URLs that failed to import."},"params":{"type":"object","additionalProperties":{"description":"Any type"},"description":"JSON blob whose shape depends on `kind` — typically `url`,\n`max_pages`, `max_depth`. Read it for display\nonly.\n"},"error":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"}},"required":["id","kb_id","kind","status","total","completed","failed","params","created_at","updated_at","started_at","ended_at"],"description":"Async URL import job (sitemap, crawl, plus\nthe auto-refresh path). Poll\n`GET /v1/agents/knowledge-bases/{kb_id}/imports` while the job is\nnon-terminal.\n","title":"ImportJob"},"CreateSitemapImportRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"folder_id":{"type":["string","null"],"description":"Folder to import the documents into. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null/omitted = root.\n"}},"required":["url"],"title":"CreateSitemapImportRequest"},"CreateTextDocumentRequest":{"type":"object","properties":{"name":{"type":"string"},"content":{"type":"string"},"folder_id":{"type":["string","null"],"description":"Folder to drop the document into. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null/omitted = root.\n"}},"required":["name","content"],"description":"Body for POST /v1/agents/knowledge-bases/{kb_id}/documents/text.","title":"CreateTextDocumentRequest"},"CreateURLDocumentRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"folder_id":{"type":["string","null"],"description":"Folder to drop the document into. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null/omitted = root.\n"}},"required":["url"],"description":"Body for POST /v1/agents/knowledge-bases/{kb_id}/documents/url.","title":"CreateURLDocumentRequest"},"CreateURLBatchImportRequest":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string","format":"uri"}},"folder_id":{"type":["string","null"],"description":"Folder to import the documents into. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null/omitted = root.\n"}},"required":["urls"],"description":"Body for POST /v1/agents/knowledge-bases/{kb_id}/documents/urls. Submit\n1..N URLs in a single async import. The server dedupes and\nvalidates each entry before queueing. The per-import cap is\noperator-tunable (default 250) via kbUrlBatchMaxUrls; the\nserver returns 400 when the resolved list exceeds the cap, so\nno maxItems is encoded in the schema to avoid SDK-side false\nrejections when an operator raises the limit.\n","title":"CreateURLBatchImportRequest"},"DependentAgent":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"description":"Minimal agent pointer (id + name) used by the document\ndetail view to render a clickable link to each agent that\nhas the document's KB attached.\n","title":"DependentAgent"},"RefreshConfig":{"type":"object","properties":{"enabled":{"type":"boolean"},"interval_days":{"type":"integer"},"auto_remove_enabled":{"type":"boolean"},"last_refreshed_at":{"type":["string","null"],"format":"date-time"},"consecutive_fetch_failures":{"type":"integer"}},"required":["enabled","interval_days","auto_remove_enabled","last_refreshed_at","consecutive_fetch_failures"],"description":"Per-document auto-refresh state. Only populated\nfor url-sourced documents; file and text rows omit this and\nclients hide auto-refresh affordances accordingly.\n","title":"RefreshConfig"},"KnowledgeBaseDocumentDetail":{"type":"object","properties":{"id":{"type":"string"},"kb_id":{"type":"string","description":"Prefixed wire identifier (`kb_<26 char Crockford base32>`) of\nthe knowledge base the document belongs to.\n"},"source_kind":{"$ref":"#/components/schemas/KnowledgeBaseDocumentSourceKind"},"source_url":{"type":"string","description":"Source URL for url-sourced documents (and the sitemap /\ncrawl imports that produce them). Empty string for file\nand text rows.\n"},"folder_id":{"type":["string","null"],"description":"Folder this document lives in. Null for root-level\n(unfiled) documents. Mutated via the move endpoint.\n"},"filename":{"type":"string"},"content_type":{"type":"string"},"byte_size":{"type":"integer","format":"int64"},"char_count":{"type":"integer"},"chunk_count":{"type":"integer"},"status":{"$ref":"#/components/schemas/KnowledgeBaseDocumentStatus"},"error":{"type":"string","description":"Populated when status is failed."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"content_preview":{"type":"string"},"preview_truncated":{"type":"boolean"},"dependent_agents":{"type":"array","items":{"$ref":"#/components/schemas/DependentAgent"}},"refresh":{"$ref":"#/components/schemas/RefreshConfig"}},"required":["id","kb_id","source_kind","folder_id","filename","content_type","byte_size","char_count","chunk_count","status","created_at","updated_at","content_preview","preview_truncated","dependent_agents"],"description":"Payload of GET /v1/agents/knowledge-bases/documents/{document_id}. Extends\nthe list-view document with a bounded content preview, the\nlist of dependent agents, and (for url-sourced docs) the\nauto-refresh state.\n","title":"KnowledgeBaseDocumentDetail"},"KnowledgeBaseChunk":{"type":"object","properties":{"id":{"type":"string"},"document_id":{"type":"string"},"kb_id":{"type":"string","description":"Prefixed wire identifier (`kb_<26 char Crockford base32>`) of\nthe knowledge base the chunk belongs to.\n"},"chunk_index":{"type":"integer"},"content":{"type":"string"}},"required":["id","document_id","kb_id","chunk_index","content"],"title":"KnowledgeBaseChunk"},"ListKnowledgeBaseChunksResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"chunks":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeBaseChunk"}}},"required":["next_cursor","has_more","chunks"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListKnowledgeBaseChunksResponse"},"UpdateRefreshConfigRequest":{"type":"object","properties":{"enabled":{"type":"boolean"},"interval_days":{"type":"integer"},"auto_remove_enabled":{"type":"boolean"}},"description":"PATCH body — every field optional.","title":"UpdateRefreshConfigRequest"},"RefreshHistoryEntryStatus":{"type":"string","enum":["running","changed","unchanged","failed","removed"],"title":"RefreshHistoryEntryStatus"},"RefreshHistoryEntry":{"type":"object","properties":{"id":{"type":"string"},"document_id":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"status":{"$ref":"#/components/schemas/RefreshHistoryEntryStatus"},"error":{"type":"string"},"previous_hash":{"type":"string"},"new_hash":{"type":"string"}},"required":["id","document_id","started_at","ended_at","status"],"description":"One auto-refresh attempt. `running` only appears mid-tick;\nterminal values are the ones the drawer renders.\n","title":"RefreshHistoryEntry"},"ListRefreshHistoryResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"entries":{"type":"array","items":{"$ref":"#/components/schemas/RefreshHistoryEntry"}}},"required":["next_cursor","has_more","entries"],"description":"Payload for `GET /v1/agents/knowledge-bases/{kb_id}/documents/{document_id}/refresh-history`.","title":"ListRefreshHistoryResponse"},"KnowledgeBaseFolder":{"type":"object","properties":{"id":{"type":"string"},"kb_id":{"type":"string","description":"Prefixed wire identifier (`kb_<26 char Crockford base32>`) of\nthe owning knowledge base.\n"},"parent_folder_id":{"type":["string","null"]},"name":{"type":"string"},"document_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","kb_id","parent_folder_id","name","document_count","created_at","updated_at"],"description":"Folder inside a knowledge base. Root-level folders have\n`parent_folder_id: null`. `document_count` is populated only\non the list endpoint.\n","title":"KnowledgeBaseFolder"},"ListKnowledgeBaseFoldersResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"folders":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeBaseFolder"}}},"required":["next_cursor","has_more","folders"],"description":"Flat list of folders for a knowledge base. Build the folder\ntree from `parent_folder_id` references, so callers should\nwalk every page before rendering.\n","title":"ListKnowledgeBaseFoldersResponse"},"CreateFolderRequest":{"type":"object","properties":{"name":{"type":"string"},"parent_folder_id":{"type":["string","null"],"description":"Parent folder. Prefixed wire identifier\n(`kfolder_<26 char Crockford base32>`); null/omitted creates a\nroot-level folder.\n"}},"required":["name"],"title":"CreateFolderRequest"},"UpdateFolderRequest":{"type":"object","properties":{"name":{"type":"string"},"parent_folder_id":{"type":["string","null"],"description":"Folder to reparent under (prefixed wire identifier\n`kfolder_<26 char Crockford base32>`), or `null` to move the\nfolder to the knowledge base root. Omit to leave unchanged.\n"}},"description":"PATCH body (JSON merge-patch). All fields optional; omit a field\nto leave it unchanged. Set `parent_folder_id` to reparent into\nthat folder, or send `parent_folder_id: null` to move the folder\nto the knowledge base root.\n","title":"UpdateFolderRequest"},"ListImportJobsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/ImportJob"}}},"required":["next_cursor","has_more","jobs"],"description":"Payload for `GET /v1/agents/knowledge-bases/{kb_id}/imports`.","title":"ListImportJobsResponse"},"AttachedKnowledgeBasesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"knowledge_bases":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeBase"}}},"required":["next_cursor","has_more","knowledge_bases"],"description":"Cursor-paginated list of the knowledge bases attached to an agent.\n","title":"AttachedKnowledgeBasesResponse"},"ToolKind":{"type":"string","enum":["builtin","webhook","client","mcp"],"description":"What kind of tool this is, and where it executes.\n- `builtin`: a worker-resident platform capability (e.g. end_call, play_audio), configured per-agent\n- `webhook`: worker signs a payload and POSTs it to your URL\n- `client`:  worker dispatches to the caller's browser/SDK via data channel\n- `mcp`:     worker connects to a customer-hosted MCP server and proxies tool calls\n","title":"ToolKind"},"SystemBuiltin":{"type":"string","description":"Identifier of a built-in system tool. New builtins are added by\nSpeechify across releases. Read the catalogue from\n`GET /v1/agents/tool-capabilities` rather than depending on this\nstring set staying stable across releases.\n","title":"SystemBuiltin"},"ToolParamType":{"type":"string","enum":["string","number","integer","boolean"],"description":"Permitted JSON-Schema primitive types for tool params.","title":"ToolParamType"},"ToolParam":{"type":"object","properties":{"name":{"type":"string"},"type":{"$ref":"#/components/schemas/ToolParamType"},"description":{"type":"string"},"required":{"type":"boolean"},"enum":{"type":"array","items":{"type":"string"}}},"required":["name","type","description","required"],"description":"One argument the LLM can pass when calling the tool. Mirrors the JSON-Schema subset standard function-calling schemas support.","title":"ToolParam"},"BuiltinToolConfig":{"type":"object","properties":{"builtin":{"$ref":"#/components/schemas/SystemBuiltin"},"params":{"type":"array","items":{"$ref":"#/components/schemas/ToolParam"}},"builtin_config":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-builtin extras (e.g. allowed_numbers for transfer_to_number)."}},"required":["builtin"],"description":"Config shape for `kind=builtin`. The `builtin` value names the\nworker-resident capability; the catalogue served by\n`GET /v1/agents/tool-capabilities` is the runtime source of truth\nfor valid names plus their human-readable labels. `builtin_config`\ncarries per-instance extras (e.g. allowed_numbers for\ntransfer_to_number, audio_asset_id for play_audio).\n","title":"BuiltinToolConfig"},"WebhookToolConfigMethod":{"type":"string","enum":["POST","GET"],"title":"WebhookToolConfigMethod"},"WebhookToolConfig":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"method":{"$ref":"#/components/schemas/WebhookToolConfigMethod"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Static headers sent with every call. `Authorization` and `Speechify-Signature` are reserved."},"timeout_ms":{"type":"integer","description":"Per-call timeout in milliseconds. Defaults to 10000 server-side when omitted."},"params":{"type":"array","items":{"$ref":"#/components/schemas/ToolParam"}},"fire_and_forget":{"type":"boolean","description":"When true the worker dispatches the HTTP request and returns\nimmediately to the LLM with a synthetic \"queued\" result\ninstead of waiting for the response body. The customer's\nendpoint is expected to enqueue the work and return any\nnon-error status quickly; errors raised after dispatch are\nlogged but never surfaced to the LLM. Use for long-running\ncustomer-side work (job triggers, async ticket creation,\netc.) where blocking the call on the response would hurt\nthe conversation. Defaults to false.\n"}},"required":["url"],"description":"Config shape for `kind=webhook`.","title":"WebhookToolConfig"},"ClientToolConfig":{"type":"object","properties":{"params":{"type":"array","items":{"$ref":"#/components/schemas/ToolParam"}},"timeout_ms":{"type":"integer","description":"Per-call timeout in milliseconds. Defaults to 10000 server-side when omitted."}},"description":"Config shape for `kind=client`. Execution happens in the caller's browser / SDK.","title":"ClientToolConfig"},"MCPTransport":{"type":"string","enum":["http_streamable","sse"],"description":"MCP transport. `http_streamable` is the default; `sse` is the\nlegacy fallback for servers that haven't migrated yet.\n","title":"MCPTransport"},"MCPAuth":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["none"],"description":"Discriminator value: none"}},"required":["type"],"description":"none variant"},{"type":"object","properties":{"type":{"type":"string","enum":["bearer"],"description":"Discriminator value: bearer"},"credential_id":{"type":"string","description":"`cred_<crockford>` id of a `bearer` credential in the workspace\nvault. Create the credential first via `POST /v1/credentials`,\nthen reference it here.\n"}},"required":["type","credential_id"],"description":"Bearer auth for an MCP server. References a workspace credential of\nkind `bearer` by id; the secret lives in the credentials vault and is\nresolved server-side at dispatch, never inlined on the tool.\n"},{"type":"object","properties":{"type":{"type":"string","enum":["oauth2_client_credentials"],"description":"Discriminator value: oauth2_client_credentials"},"credential_id":{"type":"string","description":"`cred_<crockford>` id of an `oauth2_client_credentials` credential\nin the workspace vault.\n"}},"required":["type","credential_id"],"description":"OAuth2 client-credentials auth for an MCP server. References a\nworkspace credential of kind `oauth2_client_credentials` by id; the\ntoken_url / client_id / client_secret / scopes all live in the vault\ncredential and are resolved server-side at dispatch.\n"}],"discriminator":{"propertyName":"type"},"description":"Discriminated union over `type`.","title":"MCPAuth"},"MCPToolConfig":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri"},"transport":{"$ref":"#/components/schemas/MCPTransport"},"auth":{"$ref":"#/components/schemas/MCPAuth"}},"required":["endpoint","auth"],"description":"Config shape for `kind=mcp`. The worker opens the\nconfigured transport at session start, runs `initialize` +\n`list_tools`, and registers each discovered remote tool as a\nlivekit-agents function_tool proxying through the long-lived\nClientSession.\n","title":"MCPToolConfig"},"AgentToolConfig":{"oneOf":[{"$ref":"#/components/schemas/BuiltinToolConfig"},{"$ref":"#/components/schemas/WebhookToolConfig"},{"$ref":"#/components/schemas/ClientToolConfig"},{"$ref":"#/components/schemas/MCPToolConfig"}],"description":"Resolved config - `BuiltinToolConfig`, `WebhookToolConfig`, `ClientToolConfig`, or `MCPToolConfig` depending on `kind`.","title":"AgentToolConfig"},"AgentTool":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`tool_<26 char Crockford base32>`), stable across kinds."},"kind":{"$ref":"#/components/schemas/ToolKind"},"name":{"type":"string"},"description":{"type":"string"},"enabled":{"type":"boolean","description":"When false the tool is configured but skipped at dispatch."},"definition_id":{"type":["string","null"],"description":"Provenance: the backing workspace tool definition id for\nshared kinds (webhook/client/mcp), or `null` for a built-in.\nNon-null ⟺ the tool's config is shared and edited at\n`/v1/agents/tool-definitions/{tool_definition_id}`.\n"},"config":{"$ref":"#/components/schemas/AgentToolConfig","description":"Resolved config - `BuiltinToolConfig`, `WebhookToolConfig`, `ClientToolConfig`, or `MCPToolConfig` depending on `kind`."},"webhook_secret":{"type":"string","description":"HMAC signing secret for a `webhook` tool. Returned in full\n**only** on the create response; subsequent reads return a\nmasked placeholder.\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","kind","name","description","enabled","definition_id","config","created_at","updated_at"],"description":"One thing an agent can do, in the unified per-agent view. Kind\ndiscriminates a per-agent built-in instance (`builtin`) from an\nattached workspace tool definition (`webhook`/`client`/`mcp`).\nThe config is resolved + embedded so consumers never have to fetch\nthe backing definition. `id` is a `tool_<...>` for every kind.\n","title":"AgentTool"},"ListAgentToolsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"tools":{"type":"array","items":{"$ref":"#/components/schemas/AgentTool"}}},"required":["next_cursor","has_more","tools"],"description":"The agent's full, mixed-kind toolbelt, cursor-paginated.\n","title":"ListAgentToolsResponse"},"CreateAgentToolRequestConfig":{"oneOf":[{"$ref":"#/components/schemas/BuiltinToolConfig"},{"$ref":"#/components/schemas/WebhookToolConfig"},{"$ref":"#/components/schemas/ClientToolConfig"},{"$ref":"#/components/schemas/MCPToolConfig"}],"title":"CreateAgentToolRequestConfig"},"CreateAgentToolRequest":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ToolKind"},"name":{"type":"string"},"description":{"type":"string"},"enabled":{"type":"boolean","description":"Defaults to true on the server when omitted."},"config":{"$ref":"#/components/schemas/CreateAgentToolRequestConfig"}},"required":["kind","name","config"],"description":"Add a tool to an agent. With `kind=builtin`, `config` carries a\n`BuiltinToolConfig` and a per-agent built-in instance is created.\nWith `kind=webhook`/`client`/`mcp`, `config` carries that kind's\nconfig and a workspace definition is created AND attached in one\ncall.\n","title":"CreateAgentToolRequest"},"UpdateAgentToolRequestConfig":{"oneOf":[{"$ref":"#/components/schemas/BuiltinToolConfig"}],"description":"For a built-in, the full `BuiltinToolConfig`. Rejected for shared kinds.","title":"UpdateAgentToolRequestConfig"},"UpdateAgentToolRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"config":{"$ref":"#/components/schemas/UpdateAgentToolRequestConfig","description":"For a built-in, the full `BuiltinToolConfig`. Rejected for shared kinds."},"params":{"type":"array","items":{"$ref":"#/components/schemas/ToolParam"}},"enabled":{"type":"boolean"}},"description":"PATCH body. For a built-in, all fields apply. For an attached\nexternal tool only `enabled` is honoured - editing the shared\nconfig/name from here returns `tool_config_shared`.\n","title":"UpdateAgentToolRequest"},"SystemBuiltinInfo":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/SystemBuiltin"},"label":{"type":"string","description":"Human-readable display label for the builtin."},"description":{"type":"string","description":"One-line summary of what the builtin does."}},"required":["name","label","description"],"description":"One entry in the system-builtin catalogue.","title":"SystemBuiltinInfo"},"ListSystemBuiltinsResponse":{"type":"object","properties":{"builtins":{"type":"array","items":{"$ref":"#/components/schemas/SystemBuiltinInfo"}}},"required":["builtins"],"title":"ListSystemBuiltinsResponse"},"ToolConfig":{"oneOf":[{"$ref":"#/components/schemas/WebhookToolConfig"},{"$ref":"#/components/schemas/ClientToolConfig"},{"$ref":"#/components/schemas/MCPToolConfig"}],"description":"One of `WebhookToolConfig`, `ClientToolConfig`, or `MCPToolConfig` depending on `kind`.","title":"ToolConfig"},"Tool":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`tool_<26 char Crockford base32>`).\n"},"name":{"type":"string"},"description":{"type":"string"},"kind":{"$ref":"#/components/schemas/ToolKind"},"config":{"$ref":"#/components/schemas/ToolConfig","description":"One of `WebhookToolConfig`, `ClientToolConfig`, or `MCPToolConfig` depending on `kind`."},"webhook_secret":{"type":"string","description":"HMAC signing secret for `kind=webhook`. Returned in full **only** on the create\nresponse; all subsequent reads return a masked placeholder. Store it on first\ncreate — there is no way to retrieve it later.\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","description","kind","config","created_at","updated_at"],"description":"A workspace tool definition: a reusable webhook / client / MCP\nintegration created once and attached to many agents. Built-ins\nare NOT definitions - they are per-agent (see `AgentTool`).\n","title":"Tool"},"ListToolsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"tools":{"type":"array","items":{"$ref":"#/components/schemas/Tool"}}},"required":["next_cursor","has_more","tools"],"description":"Payload for `GET /v1/agents/tool-definitions` — the workspace-level\ntool-definition catalog. Cursor-paginated; the per-agent toolbelt\nendpoint uses a different (bare, mixed-kind) shape — see\nListAgentToolsResponse.\n","title":"ListToolsResponse"},"CreateToolRequestConfig":{"oneOf":[{"$ref":"#/components/schemas/WebhookToolConfig"},{"$ref":"#/components/schemas/ClientToolConfig"},{"$ref":"#/components/schemas/MCPToolConfig"}],"title":"CreateToolRequestConfig"},"CreateToolRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"kind":{"$ref":"#/components/schemas/ToolKind"},"config":{"$ref":"#/components/schemas/CreateToolRequestConfig"}},"required":["name","description","kind","config"],"description":"Create a workspace tool definition (webhook / client / mcp only).","title":"CreateToolRequest"},"UpdateToolRequestConfig":{"oneOf":[{"$ref":"#/components/schemas/WebhookToolConfig"},{"$ref":"#/components/schemas/ClientToolConfig"},{"$ref":"#/components/schemas/MCPToolConfig"}],"title":"UpdateToolRequestConfig"},"UpdateToolRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"config":{"$ref":"#/components/schemas/UpdateToolRequestConfig"}},"description":"All fields optional. `kind` is immutable — create a new definition to change it.","title":"UpdateToolRequest"},"ToolAttachedAgent":{"type":"object","properties":{"id":{"type":"string","description":"Opaque agent ID."},"name":{"type":"string","description":"Human-readable agent name."}},"required":["id","name"],"description":"Minimal agent identity returned alongside a tool so a client\ncan render \"this tool is attached to: X, Y\" before a\ndestructive action runs.\n","title":"ToolAttachedAgent"},"ListToolAttachedAgentsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"agents":{"type":"array","items":{"$ref":"#/components/schemas/ToolAttachedAgent"}}},"required":["next_cursor","has_more","agents"],"description":"Response shape for GET /v1/agents/tool-definitions/{tool_definition_id}/attached-agents.\nAgents are tenant-scoped and ordered by name ASC.\n","title":"ListToolAttachedAgentsResponse"},"TestMCPConnectionRequest":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/MCPToolConfig"}},"required":["config"],"description":"Body for `POST /v1/agents/tool-definitions/test-mcp-connection`. `config` is the\nsame MCPToolConfig shape `POST /v1/agents/tool-definitions` would persist; nothing\nis persisted by the probe itself. For a non-none auth, the server\nresolves `auth.credential_id` to the vault secret before probing —\nthe credential is created up front via `POST /v1/credentials`, so it\nresolves independently of any tool.\n","title":"TestMCPConnectionRequest"},"MCPProbeTool":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}},"required":["name"],"description":"One discovered tool in a probe result.","title":"MCPProbeTool"},"McpProbeErrorDetailsStage":{"type":"string","enum":["validation","oauth2_token","mcp_connect","mcp_initialize","mcp_notify","mcp_list_tools"],"title":"McpProbeErrorDetailsStage"},"MCPProbeErrorDetails":{"type":"object","properties":{"stage":{"$ref":"#/components/schemas/McpProbeErrorDetailsStage"},"http_status":{"type":"integer"},"oauth2_error":{"type":"string"},"oauth2_error_description":{"type":"string"},"upstream_body":{"type":"string"},"field_hint":{"type":"string"}},"description":"Structured upstream signal for an MCP probe failure. All fields\nare optional; a client renders what's present. `stage` names\nthe phase the probe was in (`validation`, `oauth2_token`,\n`mcp_connect`, `mcp_initialize`, `mcp_notify`, `mcp_list_tools`).\n`oauth2_error` / `oauth2_error_description` mirror RFC 6749 §5.2\nwhen the customer's auth server returned the standard error\nshape. `http_status` is the upstream status code for transport\nfailures. `upstream_body` is a truncated prefix (max ~1 KiB) of\nthe upstream response body when the failure isn't structured.\n`field_hint` names a form field (`endpoint`, `transport`,\n`token`, `token_url`, `client_id`, `client_secret`, `scope`)\na client should highlight so the customer knows what to fix.\n","title":"MCPProbeErrorDetails"},"MCPProbeResult":{"type":"object","properties":{"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MCPProbeTool"}},"error":{"type":"string"},"details":{"$ref":"#/components/schemas/MCPProbeErrorDetails"}},"required":["tools"],"description":"Result of an MCP probe. On success, `tools` is the discovered\ncatalogue and `error` is absent. On failure, `tools` is `null`\nand `error` carries a human-readable reason a client can render\ninline next to the form. `details` is optional structured\nsignal from the upstream (OAuth2 RFC 6749 fields, HTTP status,\ntruncated upstream body, form field hint) a client can use to\nexpand the inline banner and highlight the offending input.\nOlder clients ignore `details` and fall back to `error`. Both\nvalidation and network failures land in `error` rather than\nnon-2xx responses, so consumers must check `error` before\nreading `tools`.\n","title":"MCPProbeResult"},"TestWebhookConnectionRequest":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/WebhookToolConfig"},"tool_id":{"type":"string","description":"Optional `tool_<crockford>` id of the existing tool to sign\nthe probe with. Raw UUIDs and other-resource prefixes are\nrejected.\n"}},"required":["config"],"description":"Body for `POST /v1/agents/tool-definitions/test-webhook-connection`.\n`config` is the same WebhookToolConfig shape `POST /v1/agents/tool-definitions`\nwould persist; nothing is persisted by the probe. `tool_id` is\nonly meaningful in the edit-form flow — when set, the server\nsigns the probe request with the tool's stored HMAC secret so\nthe test exercises the real signature path.\n","title":"TestWebhookConnectionRequest"},"WebhookProbeResult":{"type":"object","properties":{"ok":{"type":"boolean"},"status_code":{"type":"integer","description":"HTTP status the endpoint returned. Absent on a transport failure."},"latency_ms":{"type":"integer","format":"int64","description":"Wall-clock round-trip time in milliseconds."},"response_body":{"type":"string","description":"Truncated prefix (max ~2 KiB) of the endpoint's response body."},"signed":{"type":"boolean","description":"Whether the probe request carried an HMAC signature header."},"error":{"type":"string","description":"Human-readable transport-level failure reason. Absent when any response was received."}},"required":["ok","signed"],"description":"Result of a webhook probe. `ok` is true only when the endpoint\nreturned a 2xx. A non-2xx response still populates `status_code`\nand `response_body` with `ok=false` — the request reached the\nendpoint, the endpoint just declined it. `error` is set only for\ntransport-level failures (DNS, connect, TLS, timeout, blocked\naddress range) where no response was received; `status_code` is\nabsent in that case. `signed` reports whether the probe carried\na `Speechify-Signature` header — false on the create-form\nflow, which has no stored secret yet. Both success and failure\nuse the 200 envelope so a client can render them inline.\n","title":"WebhookProbeResult"},"TestType":{"type":"string","enum":["reply","tool","simulation"],"description":"Discriminates the shape of `AgentTest.config`.\n- `reply` - send one message to the agent and judge the response with an LLM.\n- `tool` - assert that the agent calls a specific tool given a context.\n- `simulation` - run a multi-turn conversation between the agent and an AI caller.\n","title":"TestType"},"SimulationMessageRole":{"type":"string","enum":["user","assistant"],"title":"SimulationMessageRole"},"SimulationMessage":{"type":"object","properties":{"role":{"$ref":"#/components/schemas/SimulationMessageRole"},"content":{"type":"string"}},"required":["role","content"],"description":"One turn in a simulation conversation. `role` is `user` (the AI caller) or `assistant` (the agent).","title":"SimulationMessage"},"ReplyConfig":{"type":"object","properties":{"context":{"type":"string","description":"User message sent to the agent to trigger the behaviour under test. Optional when `initial_chat_history` already ends with a user message."},"success_criteria":{"type":"string","description":"Natural-language description of what a passing agent response looks like."},"success_examples":{"type":"array","items":{"type":"string"},"description":"Concrete examples of passing responses (few-shot for the judge)."},"failure_examples":{"type":"array","items":{"type":"string"},"description":"Concrete examples of failing responses (few-shot for the judge)."},"initial_chat_history":{"type":"array","items":{"$ref":"#/components/schemas/SimulationMessage"},"description":"Optional seed conversation prepended before `context`. Lets you test the agent's reply mid-conversation rather than on a cold single-turn prompt."},"system_prompt_override":{"type":"string","description":"Deprecated. Prefer the run-level `config_override`\non `POST /v1/agents/{agent_id}/tests/runs`, which applies a proposed\nprompt to every test in the run without editing each one.\nStill honoured; the run-level override wins when both are set.\nReplaces the agent's system prompt for this run only."},"first_message_override":{"type":"string","description":"Replaces the agent's first message for this run only."},"model_override":{"type":"string","description":"Deprecated. Prefer the run-level `config_override`\non `POST /v1/agents/{agent_id}/tests/runs`. Still honoured; the\nrun-level override wins when both are set. Overrides the LLM\nmodel used by the agent for this run only."}},"required":["success_criteria"],"description":"Configuration for a `reply` test. The runner sends `context` as\na user message and asks an LLM judge to evaluate the agent response\nagainst `success_criteria`. Optional few-shot examples sharpen the\njudge's calibration. Use `initial_chat_history` to prepend prior\nturns before `context`; when the history already ends with a user\nmessage, `context` may be omitted and the agent is evaluated on\nits reply to that last history turn.","title":"ReplyConfig"},"ParameterCheckMode":{"type":"string","enum":["exact","regex","llm"],"description":"How a `ParameterCheck` validates a tool argument.\n- `exact` - JSON equality.\n- `regex` - the argument stringified is matched against the pattern.\n- `llm` - an LLM judge decides whether the value semantically satisfies\n  the criteria (e.g. \"is a plausible email address\").\n","title":"ParameterCheckMode"},"ParameterCheck":{"type":"object","properties":{"path":{"type":"string","description":"Dotted JSON path to the argument being checked. Empty means the whole args object."},"mode":{"$ref":"#/components/schemas/ParameterCheckMode"},"expected":{"type":"string","description":"Expected value string for `exact` and `regex` modes."},"criteria":{"type":"string","description":"Natural-language criteria for `llm` mode (e.g. \"is a valid email address\")."}},"required":["path","mode"],"description":"Validates one argument of an expected tool call. `path` is a\ndotted JSON path (e.g. `customer.email`); use zero-indexed\nnotation for arrays (`items.0.sku`). An empty path checks the\nwhole args object.","title":"ParameterCheck"},"ToolCallConfig":{"type":"object","properties":{"context":{"type":"string","description":"User message that should cause the agent to invoke the expected tool. Optional when `initial_chat_history` already ends with a user message."},"expected_tool":{"type":"string","description":"Name of the tool the agent is expected to call. Leave empty to\ninvert the assertion: the test passes only when the agent calls\nno tool at all."},"parameter_checks":{"type":"array","items":{"$ref":"#/components/schemas/ParameterCheck"},"description":"Assertions on specific arguments of the tool call."},"initial_chat_history":{"type":"array","items":{"$ref":"#/components/schemas/SimulationMessage"},"description":"Optional seed conversation prepended before `context`."},"system_prompt_override":{"type":"string","description":"Deprecated. Prefer the run-level `config_override`\non `POST /v1/agents/{agent_id}/tests/runs`. Still honoured; the\nrun-level override wins when both are set. Replaces the\nagent's system prompt for this run only."},"model_override":{"type":"string","description":"Deprecated. Prefer the run-level `config_override`\non `POST /v1/agents/{agent_id}/tests/runs`. Still honoured; the\nrun-level override wins when both are set. Overrides the LLM\nmodel used by the agent for this run only."}},"required":["expected_tool"],"description":"Configuration for a `tool` test. The runner sends `context` as a\nuser message and asserts that the agent calls `expected_tool` with\narguments matching all `parameter_checks`. Use\n`initial_chat_history` to test tool invocations that only make\nsense mid-conversation.","title":"ToolCallConfig"},"DataAssertionMode":{"type":"string","enum":["exact","regex","llm"],"description":"How the assertion validates the extracted value.","title":"DataAssertionMode"},"DataAssertion":{"type":"object","properties":{"key":{"type":"string","description":"Name of the data-collection field on the agent's evaluation config. The assertion fails when this key is missing from the extracted data."},"mode":{"$ref":"#/components/schemas/DataAssertionMode","description":"How the assertion validates the extracted value."},"expected":{"type":"string","description":"Expected value string for `exact` and `regex` modes."},"criteria":{"type":"string","description":"Natural-language criteria for `llm` mode."}},"required":["key","mode"],"description":"Asserts on one entry in the LLM-extracted data-collection map\nproduced by the unified evaluator. `key` matches a\ndata-collection field configured on the agent; the assertion\nruns against the value the judge wrote under that key. Same\nexact / regex / llm modes as `ParameterCheck` so the tool-call\nand data-collection assertion surfaces are uniform.","title":"DataAssertion"},"SimulationConfig":{"type":"object","properties":{"scenario":{"type":"string","description":"Instructions for the AI caller describing who they are and what they want."},"max_turns":{"type":"integer","default":5,"description":"Maximum agent turns before the simulation is cut off and judged."},"initial_chat_history":{"type":"array","items":{"$ref":"#/components/schemas/SimulationMessage"},"description":"Optional seed conversation that precedes the AI caller's first generated message."},"data_assertions":{"type":"array","items":{"$ref":"#/components/schemas/DataAssertion"},"description":"Optional assertions on the LLM-extracted data-collection\nmap. Each entry references a key from the agent's\ndata_collection config and validates the extracted value.\nThe test fails if any assertion fails."},"system_prompt_override":{"type":"string","description":"Deprecated. Prefer the run-level `config_override`\non `POST /v1/agents/{agent_id}/tests/runs`. Still honoured; the\nrun-level override wins when both are set. Replaces the\nagent's system prompt for this run only."},"model_override":{"type":"string","description":"Deprecated. Prefer the run-level `config_override`\non `POST /v1/agents/{agent_id}/tests/runs`. Still honoured; the\nrun-level override wins when both are set. Overrides the LLM\nmodel used by the agent for this run only."}},"required":["scenario"],"description":"Configuration for a `simulation` test. An AI caller drives a\nmulti-turn conversation with the agent according to `scenario`.\nAfter `max_turns` exchanges (or when the agent ends the call),\nthe unified post-call evaluator scores the synthetic transcript\nagainst the agent's configured evaluation criteria + data\ncollection fields. A test passes when no configured criterion\nfails and every `data_assertions` entry passes.","title":"SimulationConfig"},"AgentTestConfig":{"oneOf":[{"$ref":"#/components/schemas/ReplyConfig"},{"$ref":"#/components/schemas/ToolCallConfig"},{"$ref":"#/components/schemas/SimulationConfig"}],"description":"Type-specific configuration document.","title":"AgentTestConfig"},"MockingStrategy":{"type":"string","enum":["none","all","selected"],"description":"Controls which tool calls the runner intercepts during a run.\nSystem tools (`end_call`, `transfer_to_number`, etc.) are never\nmocked regardless of strategy.\n- `none` - no interception; all tools are called normally.\n- `all` - every non-system tool call is intercepted and matched\n  against the `mocks` list.\n- `selected` - only tools explicitly listed in `mocks` are\n  intercepted; others are called normally.\n","title":"MockingStrategy"},"ToolMock":{"type":"object","properties":{"tool_name":{"type":"string","description":"Name of the tool to intercept."},"args_match":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Optional structured argument matcher. When set, the mock fires\nonly if the tool call's arguments deep-contain every key/value\nin this object: nested objects match recursively as subsets,\narrays and scalar leaves match by deep equality. An empty\nobject matches unconditionally. When absent the mock matches\nunconditionally for this tool."},"response":{"description":"JSON value returned to the agent as the tool result."}},"required":["tool_name","response"],"description":"A canned response returned when the agent calls `tool_name`. If\n`args_match` is set the mock only triggers when the call arguments\ndeep-contain it (a structured subset match). A mock without\n`args_match` always matches for its tool.","title":"ToolMock"},"NoMatchBehavior":{"type":"string","enum":["call_real_tool","finish_with_error","skip"],"description":"Fallback when a mockable tool is called but no configured mock\nmatches the call arguments.\n- `call_real_tool` - pass-through: actually invoke the underlying\n  tool (a webhook tool POSTs to the customer endpoint). Use only\n  when the real call is safe to make from a test.\n- `finish_with_error` - fail: the run finishes as a `failed`\n  verdict. Useful when a test wants to assert that a specific\n  mocked response path is taken - any unmocked tool call fails the\n  test.\n- `skip` - return an empty stub (`{\"skipped\":true}`) to the agent so\n  the simulation proceeds without treating the call as a failure.\n  Useful when a tool's output is irrelevant to the behaviour under\n  test but the model may still decide to call it. This is the\n  default for a test with no mock configuration.\n","title":"NoMatchBehavior"},"ToolMockConfig":{"type":"object","properties":{"strategy":{"$ref":"#/components/schemas/MockingStrategy"},"mocks":{"type":"array","items":{"$ref":"#/components/schemas/ToolMock"},"description":"Canned responses for specific tools (order matters - first match wins)."},"no_match_behavior":{"$ref":"#/components/schemas/NoMatchBehavior"}},"required":["strategy","no_match_behavior"],"description":"Controls tool-call interception during a test run.","title":"ToolMockConfig"},"TestVerdict":{"type":"string","enum":["passed","failed"],"description":"The domain pass/fail judgment of an agent-test run or suite run,\nseparate from the lifecycle `status`. Present only once the run\nreached a verdict (`status` is `completed`); absent for a run that\ncould not execute (`status` `failed`), was `cancelled`, or is still\nin flight.\n","title":"TestVerdict"},"ReplyResult":{"type":"object","properties":{"agent_response":{"type":"string","description":"The raw text response the agent produced."},"passed":{"type":"boolean"},"rationale":{"type":"string","description":"LLM judge's explanation of the verdict."},"score":{"type":"number","format":"double","description":"0-1 judge confidence score."},"duration_ms":{"type":"integer","format":"int64","description":"Wall-clock time for the run in milliseconds."}},"required":["agent_response","passed","rationale","score","duration_ms"],"description":"Result details for a `reply` test run.","title":"ReplyResult"},"ParameterCheckResult":{"type":"object","properties":{"path":{"type":"string"},"mode":{"$ref":"#/components/schemas/ParameterCheckMode"},"actual_json":{"type":"string","description":"JSON-serialised actual value at `path`."},"passed":{"type":"boolean"},"rationale":{"type":"string","description":"LLM rationale (populated for `llm` mode checks)."}},"required":["path","mode","actual_json","passed"],"description":"Result of one `ParameterCheck` within a tool-call test run.","title":"ParameterCheckResult"},"ToolCallResult":{"type":"object","properties":{"tool_called":{"type":"string","description":"Name of the tool the agent actually called (may differ from `expected_tool`)."},"tool_args":{"description":"Arguments the agent passed to the tool, as a JSON object."},"expected_tool":{"type":"string","description":"Name of the tool the test expected the agent to call."},"tool_matched":{"type":"boolean","description":"True when `tool_called` equals `expected_tool`."},"parameter_results":{"type":"array","items":{"$ref":"#/components/schemas/ParameterCheckResult"}},"passed":{"type":"boolean"},"rationale":{"type":"string","description":"Explanation of the overall verdict."},"duration_ms":{"type":"integer","format":"int64"}},"required":["tool_called","expected_tool","tool_matched","parameter_results","passed","rationale","duration_ms"],"description":"Result details for a `tool` test run.","title":"ToolCallResult"},"SimulationToolCall":{"type":"object","properties":{"turn_index":{"type":"integer","description":"Zero-based index of the conversation turn in which this call occurred."},"tool_name":{"type":"string"},"args":{"description":"Arguments passed to the tool, as a JSON object."},"response":{"description":"Response returned to the agent (absent for system tools that end the call)."},"mocked":{"type":"boolean"}},"required":["turn_index","tool_name","args","mocked"],"description":"One tool invocation that occurred during a simulation run.\n`mocked` is true when the call was intercepted by the run's\nmock config; false when the real tool was called or when the\ntool is a system tool.","title":"SimulationToolCall"},"SimulationResultSentiment":{"type":"string","enum":["positive","neutral","negative"],"description":"Overall sentiment classification.","title":"SimulationResultSentiment"},"SimulationCriterionResultStatus":{"type":"string","enum":["success","failure","unknown"],"description":"Three-state outcome. `unknown` means the criterion did not\napply on this run (the topic never came up); `failure`\nmeans it did apply and the agent did not satisfy it.","title":"SimulationCriterionResultStatus"},"SimulationCriterionResult":{"type":"object","properties":{"criterion_id":{"type":"string"},"name":{"type":"string"},"status":{"$ref":"#/components/schemas/SimulationCriterionResultStatus","description":"Three-state outcome. `unknown` means the criterion did not\napply on this run (the topic never came up); `failure`\nmeans it did apply and the agent did not satisfy it."},"score":{"type":"number","format":"double","description":"0.0..1.0 continuous estimate of how well the criterion was met."},"rationale":{"type":"string"}},"required":["criterion_id","name","status","rationale"],"description":"One scored entry of an agent's configured evaluation criterion\nagainst a simulation transcript. Mirrors the per-criterion row\nthe post-call evaluator persists, so test runs and live\nconversations carry identical per-criterion shapes.","title":"SimulationCriterionResult"},"DataAssertionResultMode":{"type":"string","enum":["exact","regex","llm"],"title":"DataAssertionResultMode"},"DataAssertionResult":{"type":"object","properties":{"key":{"type":"string"},"mode":{"$ref":"#/components/schemas/DataAssertionResultMode"},"actual_json":{"type":"string","description":"The extracted value rendered as JSON (`null` when the key was missing from the data map)."},"passed":{"type":"boolean"},"rationale":{"type":"string","description":"Empty on pass; reason for failure otherwise."}},"required":["key","mode","actual_json","passed"],"description":"Outcome of one `data_assertions` entry: did the value the\nevaluator extracted under `key` pass the configured exact /\nregex / llm check.","title":"DataAssertionResult"},"SimulationResult":{"type":"object","properties":{"transcript":{"type":"array","items":{"$ref":"#/components/schemas/SimulationMessage"},"description":"Full synthetic conversation in order."},"tool_calls":{"type":"array","items":{"$ref":"#/components/schemas/SimulationToolCall"},"description":"Every tool invocation across all turns."},"turns_used":{"type":"integer","description":"Number of agent turns that ran before the simulation ended."},"passed":{"type":"boolean"},"rationale":{"type":"string","description":"Top-level verdict explanation (run summary on pass; first failing criterion or assertion on fail)."},"duration_ms":{"type":"integer","format":"int64"},"summary":{"type":"string","description":"One-sentence narrative summary of what happened in the conversation."},"sentiment":{"$ref":"#/components/schemas/SimulationResultSentiment","description":"Overall sentiment classification."},"criteria":{"type":"array","items":{"$ref":"#/components/schemas/SimulationCriterionResult"},"description":"One result row per configured EvaluationCriterion on the\nagent. Same shape as the per-criterion rows persisted on\nthe post-call evaluations table."},"data":{"type":"object","additionalProperties":{"description":"Any type"},"description":"LLM-extracted values for the agent's configured\ndata-collection fields. Keys mirror the agent's\ndata_collection field keys; values are typed per the\ndeclared field type."},"data_assertions":{"type":"array","items":{"$ref":"#/components/schemas/DataAssertionResult"},"description":"One result row per `data_assertions` entry on the simulation config."}},"required":["transcript","turns_used","passed","rationale","duration_ms"],"description":"Result details for a `simulation` test run. Scoring is unified\nwith the post-call evaluator: the synthetic transcript\nis scored against the agent's configured evaluation criteria\nand data-collection fields, then per-test `data_assertions`\ncheck the extracted values. The top-level `passed` is derived\n— every criterion must resolve to `success` or `unknown` and\nevery assertion must pass.","title":"SimulationResult"},"TestRunResult":{"type":"object","properties":{"test_type":{"$ref":"#/components/schemas/TestType"},"passed":{"type":"boolean"},"rationale":{"type":"string","description":"Top-level verdict explanation duplicated from the inner result for quick rendering."},"duration_ms":{"type":"integer","format":"int64"},"reply":{"oneOf":[{"$ref":"#/components/schemas/ReplyResult"},{"type":"null"}]},"tool_call":{"oneOf":[{"$ref":"#/components/schemas/ToolCallResult"},{"type":"null"}]},"simulation":{"oneOf":[{"$ref":"#/components/schemas/SimulationResult"},{"type":"null"}]}},"required":["test_type","passed","rationale","duration_ms"],"description":"Union-like result of a completed test run. Exactly one of\n`reply`, `tool_call`, or `simulation` is populated, matching\nthe `test_type`.","title":"TestRunResult"},"AgentTestRun":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`run_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"test_id":{"type":"string","description":"Prefixed wire identifier (`test_<26 char Crockford base32>`)\nof the parent test.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the agent this run executed against.\n"},"status":{"$ref":"#/components/schemas/JobStatus"},"verdict":{"oneOf":[{"$ref":"#/components/schemas/TestVerdict"},{"type":"null"}],"description":"The pass/fail judgment, present only once the run reached a\nverdict (`status` is `completed`).\n"},"started_at":{"type":["string","null"],"format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"result":{"oneOf":[{"$ref":"#/components/schemas/TestRunResult"},{"type":"null"}],"description":"Populated once the run reached a verdict."},"error":{"type":"string","description":"Human-readable error message when `status` is `failed`."},"created_at":{"type":"string","format":"date-time"}},"required":["id","test_id","agent_id","status","created_at"],"description":"One execution of a test. The lifecycle `status` is the unified\nasync-job vocabulary; the pass/fail judgment lives in the separate\n`verdict` field. `result` is populated when the run reached a\nverdict (`status` is `completed`); see `TestRunResult` for the\nshape. A run that could not execute is `status` `failed` with no\n`verdict`, and `error` carries the reason.","title":"AgentTestRun"},"AgentTestWithLastRun":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`test_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the owning agent.\n"},"name":{"type":"string"},"description":{"type":"string"},"type":{"$ref":"#/components/schemas/TestType"},"config":{"$ref":"#/components/schemas/AgentTestConfig","description":"Type-specific configuration document."},"tool_mock_config":{"$ref":"#/components/schemas/ToolMockConfig","description":"Optional tool-mocking config applied during runs of this test."},"variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-test dynamic-variable overrides. Keys substitute `{{key}}`\nplaceholders inside the test config at run-start. Unknown keys\nrender as empty string, matching session dispatch behaviour.\n"},"folder_id":{"type":["string","null"],"description":"When set, prefixed wire identifier\n(`folder_<26 char Crockford base32>`) of the containing folder.\nNull means root (unfiled).\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_run":{"oneOf":[{"$ref":"#/components/schemas/AgentTestRun"},{"type":"null"}],"description":"The most recent run, or null if the test has never been run."}},"required":["id","agent_id","name","description","type","config","created_at","updated_at"],"description":"List-view projection of a test that includes the most recent run\nso a client can display pass/fail badges without an extra\nround-trip.","title":"AgentTestWithLastRun"},"ListTestsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"tests":{"type":"array","items":{"$ref":"#/components/schemas/AgentTestWithLastRun"}}},"required":["next_cursor","has_more","tests"],"description":"Workspace-wide paginated list of tests. Walk pages while\n`has_more` is true; pass `next_cursor` back as the request\n`cursor` parameter.","title":"ListTestsResponse"},"AgentTestFolder":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`folder_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"parent_folder_id":{"type":["string","null"],"description":"When set, prefixed wire identifier\n(`folder_<26 char Crockford base32>`) of the parent folder.\nNull means root.\n"},"name":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","created_at","updated_at"],"description":"One organisational node in the per-owner tests tree.","title":"AgentTestFolder"},"ListAgentTestFoldersResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"folders":{"type":"array","items":{"$ref":"#/components/schemas/AgentTestFolder"}}},"required":["next_cursor","has_more","folders"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListAgentTestFoldersResponse"},"CreateAgentTestFolderRequest":{"type":"object","properties":{"name":{"type":"string"},"parent_folder_id":{"type":["string","null"],"description":"Prefixed wire identifier (`folder_<26 char Crockford base32>`)\nof the parent folder. Omit / null for a root-level folder.\n"}},"required":["name"],"title":"CreateAgentTestFolderRequest"},"UpdateAgentTestFolderRequest":{"type":"object","properties":{"name":{"type":"string"},"parent_folder_id":{"type":["string","null"],"description":"Prefixed wire identifier (`folder_<26 char Crockford base32>`)\nof the folder to reparent this folder under, or `null` to\nreparent it to root. Omit to leave unchanged.\n"}},"description":"PATCH body (JSON merge-patch). All fields optional; omit a field\nto leave it unchanged. Set `parent_folder_id` to a target folder\nid to reparent into that folder, or send `parent_folder_id: null`\nto reparent this folder to root.","title":"UpdateAgentTestFolderRequest"},"BatchRunEntry":{"type":"object","properties":{"test_id":{"type":"string","description":"Prefixed wire identifier (`test_<26 char Crockford base32>`)\nof the test to run.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the agent to run the test against. Omit to run against the\ntest's owner agent.\n"}},"required":["test_id"],"description":"One entry in a batch-run request. Omit `agent_id` to run the test\nagainst its owner agent.","title":"BatchRunEntry"},"RunBatchRequest":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/BatchRunEntry"}}},"required":["entries"],"description":"Batch-run payload. Total expanded runs across all entries are\ncapped at 100 per call.","title":"RunBatchRequest"},"SuiteRunTrigger":{"type":"string","enum":["run_all","batch","resubmit"],"description":"Which entry point created a suite run.\n- `run_all`  - POST /v1/agents/{agent_id}/tests/runs.\n- `batch`    - POST /v1/agents/tests/runs/batch.\n- `resubmit` - POST /v1/agents/tests/suite-runs/{suite_run_id}/resubmit.\n","title":"SuiteRunTrigger"},"AgentTestSuiteRunResults":{"type":"object","properties":{"passed":{"type":"integer"},"failed":{"type":"integer"}},"required":["passed","failed"],"description":"Per-verdict breakdown among the `completed` child runs.","title":"AgentTestSuiteRunResults"},"TestRunConfigOverride":{"type":"object","properties":{"prompt":{"type":"string","description":"Replaces the agent's system prompt for every test in the run."},"model":{"type":"string","description":"Overrides the LLM model for every test in the run. The model\nid rides on the agent's configured provider — a\ncross-provider switch is not supported."},"tool_ids":{"type":"array","items":{"type":"string"},"description":"Replaces the agent's attached external tools for the run with\nexactly this set. Each entry is a prefixed `tool_<crockford>`\nid; `builtin_` ids are rejected. An empty array runs with no\ntools; omit the field to keep the agent's attachments."}},"description":"A run-level config override applied to every test in a Run All.\nLayered on top of the agent's stored config for the duration of\nthe suite run, so the whole suite can be validated against a\nproposed prompt / model / toolbelt without editing any test. An\nabsent field leaves the agent's value untouched; a run-level\noverride wins over a deprecated per-test `system_prompt_override`\n/ `model_override`.","title":"TestRunConfigOverride"},"AgentTestSuiteRun":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`srun_<26 char Crockford base32>`)."},"agent_id":{"type":["string","null"],"description":"Prefixed `agent_<crockford>` id of the agent whose suite\nwas run. Set for the `run_all` trigger; null for `batch`,\nwhich can span many agents.\n"},"agent_name":{"type":["string","null"],"description":"Display name of `agent_id`'s agent, resolved at read time.\nNull whenever `agent_id` is null, and on the suite run\nembedded in run/resubmit creation responses.\n"},"trigger":{"$ref":"#/components/schemas/SuiteRunTrigger"},"parent_suite_run_id":{"type":["string","null"],"description":"Set on a `resubmit`: the prefixed `srun_<crockford>` id of\nthe suite run whose failed/errored tests this one re-ran.\nNull for `run_all` and `batch`.\n"},"status":{"$ref":"#/components/schemas/JobStatus"},"verdict":{"oneOf":[{"$ref":"#/components/schemas/TestVerdict"},{"type":"null"}],"description":"The suite's pass/fail judgment, present only when `status` is\n`completed`.\n"},"total":{"type":"integer","description":"Number of child runs in the suite."},"completed":{"type":"integer","description":"Child runs that produced a verdict."},"failed":{"type":"integer","description":"Child runs that could not execute (an infrastructure failure)."},"running":{"type":"integer","description":"Child runs actively executing."},"pending":{"type":"integer","description":"Child runs queued, not yet executing."},"cancelled":{"type":"integer","description":"Child runs cancelled."},"results":{"$ref":"#/components/schemas/AgentTestSuiteRunResults","description":"Per-verdict breakdown among the `completed` child runs."},"created_at":{"type":"string","format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time","description":"Newest child-run completion; null until every child run is terminal."},"config_override":{"oneOf":[{"$ref":"#/components/schemas/TestRunConfigOverride"},{"type":"null"}],"description":"The run-level config override this suite was run\nwith, or null for an ordinary Run All / batch."},"flow_version_id":{"type":["string","null"],"description":"The flow version (`agent_versions` row) this suite targeted\n(prefixed external id, `fver_...`), or null for the agent's\nactive / synthesized flow."},"flow_version_number":{"type":["integer","null"],"description":"Human-facing version number of `flow_version_id`; null when no version was targeted."}},"required":["id","trigger","status","total","completed","failed","running","pending","cancelled","results","created_at"],"description":"A suite run (test invocation): the grouping object over every\ntest run dispatched by one Run All, batch, or resubmit call.\n`status`, `verdict`, and the count fields are derived from the\nchild runs. `status` is the unified async-job lifecycle: `running`\nwhile any child is pending/running, then `cancelled` (any child\ncancelled), `failed` (any child could not execute), or `completed`\n(every child produced a verdict). When `completed`, `verdict` is\n`passed` if every child passed, else `failed`. `results` carries\nthe per-verdict breakdown.","title":"AgentTestSuiteRun"},"RunAgentTestsResponse":{"type":"object","properties":{"runs":{"type":"array","items":{"$ref":"#/components/schemas/AgentTestRun"}},"suite_run":{"oneOf":[{"$ref":"#/components/schemas/AgentTestSuiteRun"},{"type":"null"}],"description":"The suite run grouping the queued runs."}},"required":["runs"],"description":"Response from `POST /v1/agents/{agent_id}/tests/runs` and the suite-run\nresubmit endpoint. Contains every newly-queued run so the client\ncan poll each for completion, plus the `suite_run` that groups\nthem. `suite_run` is null only when a Run All found no tests.","title":"RunAgentTestsResponse"},"TestStatsBucket":{"type":"object","properties":{"day":{"type":"string","description":"ISO date (YYYY-MM-DD)."},"passed":{"type":"integer"},"failed":{"type":"integer"},"errored":{"type":"integer"}},"required":["day","passed","failed","errored"],"description":"One daily point on the aggregate pass-rate chart.","title":"TestStatsBucket"},"TestStats":{"type":"object","properties":{"window_days":{"type":"integer"},"buckets":{"type":"array","items":{"$ref":"#/components/schemas/TestStatsBucket"}},"total_runs":{"type":"integer"},"passed_runs":{"type":"integer"},"failed_runs":{"type":"integer"},"errored_runs":{"type":"integer"},"avg_duration_ms":{"type":"integer"},"by_type":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["window_days","buckets","total_runs","passed_runs","failed_runs","errored_runs","avg_duration_ms"],"description":"Aggregate run metrics over the requested window. `buckets` is\ndense - one entry per day in the window, zero-filled, so a chart\nnever has gaps. `by_type` counts runs per test type across the\nwhole window.","title":"TestStats"},"ListSuiteRunsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"suite_runs":{"type":"array","items":{"$ref":"#/components/schemas/AgentTestSuiteRun"}}},"required":["next_cursor","has_more","suite_runs"],"description":"One page of suite runs, newest first. Walk pages while\n`has_more` is true; pass `next_cursor` back as the request\n`cursor` parameter.","title":"ListSuiteRunsResponse"},"AgentTestSuiteRunWithRunsResults":{"type":"object","properties":{"passed":{"type":"integer"},"failed":{"type":"integer"}},"required":["passed","failed"],"description":"Per-verdict breakdown among the `completed` child runs.","title":"AgentTestSuiteRunWithRunsResults"},"SuiteChildRun":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`run_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"test_id":{"type":"string","description":"Prefixed wire identifier (`test_<26 char Crockford base32>`)\nof the parent test.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the agent this run executed against.\n"},"status":{"$ref":"#/components/schemas/JobStatus"},"verdict":{"oneOf":[{"$ref":"#/components/schemas/TestVerdict"},{"type":"null"}],"description":"The pass/fail judgment, present only once the run reached a\nverdict (`status` is `completed`).\n"},"started_at":{"type":["string","null"],"format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"result":{"oneOf":[{"$ref":"#/components/schemas/TestRunResult"},{"type":"null"}],"description":"Populated once the run reached a verdict."},"error":{"type":"string","description":"Human-readable error message when `status` is `failed`."},"created_at":{"type":"string","format":"date-time"},"test_name":{"type":"string","description":"Name of the test this run executed."},"agent_name":{"type":"string","description":"Display name of the agent this run executed against."}},"required":["id","test_id","agent_id","status","created_at","test_name","agent_name"],"description":"One child run inside a suite run, carrying the parent test's\nname and the target agent's name so the grouped result view can\nlabel each row. The agent name disambiguates results when the\nsuite spans multiple agents.","title":"SuiteChildRun"},"AgentTestSuiteRunWithRuns":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`srun_<26 char Crockford base32>`)."},"agent_id":{"type":["string","null"],"description":"Prefixed `agent_<crockford>` id of the agent whose suite\nwas run. Set for the `run_all` trigger; null for `batch`,\nwhich can span many agents.\n"},"agent_name":{"type":["string","null"],"description":"Display name of `agent_id`'s agent, resolved at read time.\nNull whenever `agent_id` is null, and on the suite run\nembedded in run/resubmit creation responses.\n"},"trigger":{"$ref":"#/components/schemas/SuiteRunTrigger"},"parent_suite_run_id":{"type":["string","null"],"description":"Set on a `resubmit`: the prefixed `srun_<crockford>` id of\nthe suite run whose failed/errored tests this one re-ran.\nNull for `run_all` and `batch`.\n"},"status":{"$ref":"#/components/schemas/JobStatus"},"verdict":{"oneOf":[{"$ref":"#/components/schemas/TestVerdict"},{"type":"null"}],"description":"The suite's pass/fail judgment, present only when `status` is\n`completed`.\n"},"total":{"type":"integer","description":"Number of child runs in the suite."},"completed":{"type":"integer","description":"Child runs that produced a verdict."},"failed":{"type":"integer","description":"Child runs that could not execute (an infrastructure failure)."},"running":{"type":"integer","description":"Child runs actively executing."},"pending":{"type":"integer","description":"Child runs queued, not yet executing."},"cancelled":{"type":"integer","description":"Child runs cancelled."},"results":{"$ref":"#/components/schemas/AgentTestSuiteRunWithRunsResults","description":"Per-verdict breakdown among the `completed` child runs."},"created_at":{"type":"string","format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time","description":"Newest child-run completion; null until every child run is terminal."},"config_override":{"oneOf":[{"$ref":"#/components/schemas/TestRunConfigOverride"},{"type":"null"}],"description":"The run-level config override this suite was run\nwith, or null for an ordinary Run All / batch."},"flow_version_id":{"type":["string","null"],"description":"The flow version (`agent_versions` row) this suite targeted\n(prefixed external id, `fver_...`), or null for the agent's\nactive / synthesized flow."},"flow_version_number":{"type":["integer","null"],"description":"Human-facing version number of `flow_version_id`; null when no version was targeted."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/SuiteChildRun"}}},"required":["id","trigger","status","total","completed","failed","running","pending","cancelled","results","created_at","runs"],"description":"A suite run plus every child run, for the grouped detail view.","title":"AgentTestSuiteRunWithRuns"},"AgentTest":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`test_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the owning agent.\n"},"name":{"type":"string"},"description":{"type":"string"},"type":{"$ref":"#/components/schemas/TestType"},"config":{"$ref":"#/components/schemas/AgentTestConfig","description":"Type-specific configuration document."},"tool_mock_config":{"$ref":"#/components/schemas/ToolMockConfig","description":"Optional tool-mocking config applied during runs of this test."},"variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-test dynamic-variable overrides. Keys substitute `{{key}}`\nplaceholders inside the test config at run-start. Unknown keys\nrender as empty string, matching session dispatch behaviour.\n"},"folder_id":{"type":["string","null"],"description":"When set, prefixed wire identifier\n(`folder_<26 char Crockford base32>`) of the containing folder.\nNull means root (unfiled).\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","agent_id","name","description","type","config","created_at","updated_at"],"description":"A configured test against a voice agent. `config` is a\ntype-specific document - see `ReplyConfig`, `ToolCallConfig`,\nand `SimulationConfig` for the per-type shapes (discriminated by `type`).","title":"AgentTest"},"UpdateAgentTestRequestConfig":{"oneOf":[{"$ref":"#/components/schemas/ReplyConfig"},{"$ref":"#/components/schemas/ToolCallConfig"},{"$ref":"#/components/schemas/SimulationConfig"}],"description":"Replaces the test config when present.","title":"UpdateAgentTestRequestConfig"},"UpdateAgentTestRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"config":{"$ref":"#/components/schemas/UpdateAgentTestRequestConfig","description":"Replaces the test config when present."},"tool_mock_config":{"$ref":"#/components/schemas/ToolMockConfig","description":"Replaces the tool-mock config when present."},"folder_id":{"type":["string","null"],"description":"Prefixed wire identifier (`folder_<26 char Crockford base32>`)\nof the folder to move the test into, or `null` to move the\ntest back to root. Omit to leave unchanged.\n"}},"description":"Payload for `PATCH /v1/agents/tests/{test_id}` (JSON merge-patch).\nAll fields are optional; omitting a field leaves it unchanged. Set\n`folder_id` to a target folder id to move the test into that\nfolder, or send `folder_id: null` to move the test back to root.","title":"UpdateAgentTestRequest"},"ListAgentTestRunsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/AgentTestRun"}}},"required":["next_cursor","has_more","runs"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListAgentTestRunsResponse"},"CreateAgentTestRequestConfig":{"oneOf":[{"$ref":"#/components/schemas/ReplyConfig"},{"$ref":"#/components/schemas/ToolCallConfig"},{"$ref":"#/components/schemas/SimulationConfig"}],"description":"Type-specific configuration. Must match the shape for the given `type`.","title":"CreateAgentTestRequestConfig"},"CreateAgentTestRequest":{"type":"object","properties":{"name":{"type":"string","description":"Short human-readable label for the test."},"description":{"type":"string","description":"Optional longer description of what this test verifies."},"type":{"$ref":"#/components/schemas/TestType"},"config":{"$ref":"#/components/schemas/CreateAgentTestRequestConfig","description":"Type-specific configuration. Must match the shape for the given `type`."},"tool_mock_config":{"$ref":"#/components/schemas/ToolMockConfig","description":"Optional tool-mocking config applied during every run of this test."},"variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-test variable values substituted into string fields of the\nconfig at run-start. Keys use the same rules as agent-level\n`DynamicVariable` keys.\n"},"folder_id":{"type":["string","null"],"description":"Prefixed wire identifier (`folder_<26 char Crockford base32>`)\nof the folder to place the test in. Omit / null for root.\n"}},"required":["name","type","config"],"description":"Payload for `POST /v1/agents/{agent_id}/tests`.","title":"CreateAgentTestRequest"},"RunAllTestsRequest":{"type":"object","properties":{"config_override":{"$ref":"#/components/schemas/TestRunConfigOverride"},"flow_version_id":{"type":"string","description":"Targets a specific flow version (an `agent_versions` row)\ninstead of the agent's active flow — version-targeted\nregression. Must be a flow version of the agent under test.\nPrefixed external id (`fver_...`)."}},"description":"Optional body of `POST /v1/agents/{agent_id}/tests/runs`. Omit it\nentirely to run every test against the agent's live config and\nactive flow.","title":"RunAllTestsRequest"},"BatchCall":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`batch_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the agent that will run the batch.\n"},"phone_number_id":{"type":["string","null"],"description":"Caller-ID override. When set, prefixed wire identifier\n(`phone_<26 char Crockford base32>`) of the phone number to\nuse; falls back to the agent's bound number when null.\n"},"name":{"type":"string","description":"Human-readable batch name."},"status":{"$ref":"#/components/schemas/JobStatus","description":"Lifecycle status. A batch deferred to a future time is\n`pending` with a non-null `scheduled_at`; it moves to `running`\nonce the scheduled time arrives and the dispatcher starts\ndialing.\n"},"total":{"type":"integer","description":"Total number of recipients (the progress denominator)."},"completed":{"type":"integer","description":"Recipients successfully dialed."},"failed":{"type":"integer","description":"Recipients that failed."},"error":{"type":"string","description":"Populated when the batch itself fails."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time","description":"When the dispatcher started dialing."},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the last recipient was resolved."},"scheduled_at":{"type":["string","null"],"format":"date-time","description":"If set, the batch waits until this time before dialing."},"ringing_timeout_ms":{"type":["integer","null"],"description":"Per-call ringing timeout in milliseconds applied to every\nrecipient in the batch. Null when the batch uses the 30s\ndefault.\n"}},"required":["id","agent_id","name","status","total","completed","failed","created_at","updated_at"],"description":"A batch of outbound calls dispatched to a list of recipients.","title":"BatchCall"},"ListBatchCallsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"batches":{"type":"array","items":{"$ref":"#/components/schemas/BatchCall"}}},"required":["next_cursor","has_more","batches"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListBatchCallsResponse"},"BatchRecipientRequest":{"type":"object","properties":{"phone":{"type":"string","description":"Recipient phone number in E.164 format."},"dynamic_variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-recipient variable overrides injected into the agent prompt.\nValues may be any JSON type, matching the outbound-call and\nweb-session `dynamic_variables` surfaces. CSV uploads carry\nstring values.\n"}},"required":["phone"],"description":"One entry in a batch-call request.","title":"BatchRecipientRequest"},"CreateBatchCallRequest":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable batch name."},"agent_id":{"type":"string","description":"Agent that handles each call."},"phone_number_id":{"type":"string","description":"Caller-ID override. Falls back to the agent's bound number."},"scheduled_at":{"type":"string","format":"date-time","description":"Schedule the batch for a future time (RFC 3339). Omit to start immediately."},"ringing_timeout_ms":{"type":"integer","description":"Ringing timeout in milliseconds applied to every call in the\nbatch (how long each recipient rings before the dial gives\nup). Range 1000-80000 (1-80s). Omit to use the 30s default.\nExpress this in milliseconds even if a UI collects seconds.\n"},"recipients":{"type":"array","items":{"$ref":"#/components/schemas/BatchRecipientRequest"}}},"required":["name","agent_id","recipients"],"description":"Body for `POST /v1/agents/batch-calls`. Also accepts `multipart/form-data`\nwith a CSV file upload (`csv_file` field) where the `phone` column is\nrequired and remaining columns become per-recipient `dynamic_variables`.\n","title":"CreateBatchCallRequest"},"BatchRecipientStatus":{"type":"string","enum":["pending","dialing","completed","failed"],"title":"BatchRecipientStatus"},"BatchRecipient":{"type":"object","properties":{"id":{"type":"string"},"batch_id":{"type":"string","description":"Prefixed wire identifier (`batch_<26 char Crockford base32>`)\nof the parent batch.\n"},"phone":{"type":"string","description":"Recipient phone number in E.164 format."},"dynamic_variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-recipient variable overrides injected into the agent prompt."},"status":{"$ref":"#/components/schemas/BatchRecipientStatus"},"conversation_id":{"type":["string","null"],"description":"Set once the call is placed. Prefixed wire identifier\n(`conv_<26 char Crockford base32>`).\n"},"error":{"type":"string","description":"Populated when this recipient fails."},"attempted_at":{"type":["string","null"],"format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"}},"required":["id","batch_id","phone","status"],"description":"One recipient row in a batch call.","title":"BatchRecipient"},"GetBatchCallResponse":{"type":"object","properties":{"batch":{"$ref":"#/components/schemas/BatchCall"},"recipients":{"type":"array","items":{"$ref":"#/components/schemas/BatchRecipient"}}},"required":["batch","recipients"],"description":"Batch row plus all recipients for the detail view.","title":"GetBatchCallResponse"},"IvrMenuListEntryMenuTree":{"type":"object","properties":{},"description":"Validated menu_tree per contracts/agents/ivr_menu.schema.json. Opaque to consumers other than the worker.","title":"IvrMenuListEntryMenuTree"},"IVRMenuListEntry":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`menu_<26 char Crockford base32>`)."},"fingerprint_id":{"type":"string"},"transcript_sample":{"type":"string"},"schema_version":{"type":"integer"},"menu_tree":{"$ref":"#/components/schemas/IvrMenuListEntryMenuTree","description":"Validated menu_tree per contracts/agents/ivr_menu.schema.json. Opaque to consumers other than the worker."},"confidence_score":{"type":"number","format":"double"},"succeeded_traversals":{"type":"integer"},"total_traversals":{"type":"integer"},"last_validated_at":{"type":"string","format":"date-time"},"last_observed_at":{"type":"string","format":"date-time"},"occurrence_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}},"required":["id","fingerprint_id","transcript_sample","schema_version","menu_tree","confidence_score","succeeded_traversals","total_traversals","last_validated_at","last_observed_at","occurrence_count","created_at"],"description":"One row in the list-IVR-menus response. Carries the sample\ntranscript so a client can render the IVR identity (keyed on\nthe prefixed `fingerprint_id`) without a second round-trip.\n`last_observed_at` and `occurrence_count` are projected from\n`ivr_fingerprints` for the \"when did we last see this IVR\" signal.\n","title":"IVRMenuListEntry"},"ListIVRMenusResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"menus":{"type":"array","items":{"$ref":"#/components/schemas/IVRMenuListEntry"}}},"required":["next_cursor","has_more","menus"],"description":"Payload for `GET /v1/agents/ivr-menus`.","title":"ListIVRMenusResponse"},"IvrMenuMenuTree":{"type":"object","properties":{},"description":"Validated menu_tree per contracts/agents/ivr_menu.schema.json. Opaque to consumers other than the worker.","title":"IvrMenuMenuTree"},"IVRMenu":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`menu_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"fingerprint_id":{"type":"string"},"schema_version":{"type":"integer"},"menu_tree":{"$ref":"#/components/schemas/IvrMenuMenuTree","description":"Validated menu_tree per contracts/agents/ivr_menu.schema.json. Opaque to consumers other than the worker."},"confidence_score":{"type":"number","format":"double"},"succeeded_traversals":{"type":"integer"},"total_traversals":{"type":"integer"},"last_validated_at":{"type":"string","format":"date-time"},"invalidated_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","fingerprint_id","schema_version","menu_tree","confidence_score","succeeded_traversals","total_traversals","last_validated_at","created_at","updated_at"],"description":"One memorized IVR menu level. Identified by the\nSHA-256 fingerprint of the normalized greeting transcript;\nscoped to the caller's workspace (foreign-tenant menus are\nnever returned).\n\n`menu_tree` is the validated JSONB blob the worker consumes:\nprompt text plus the options offered (label + DTMF). Sub-menus\nreached by pressing an option are their own rows, looked up at\ndescent time by a fresh fingerprint - the tree structure is the\nimplicit graph of fingerprint -> fingerprint transitions.\n\n`confidence_score` is `succeeded_traversals / total_traversals`.\nThe worker's plan-then-execute fast path only activates at or\nabove 0.5.\n\n`invalidated_at` is non-null on a soft-deleted row; the API\nfilters these out of list / lookup / get responses so this field\nis informational only.\n","title":"IVRMenu"},"UpdateIVRMenuLabelRequest":{"type":"object","properties":{"dtmf":{"type":"string","description":"DTMF value of the option to relabel (e.g. \"1\", \"*\", \"#\")."},"label":{"type":"string","description":"New label. Capped at 256 chars server-side."}},"required":["dtmf","label"],"description":"Re-label one option in the stored menu_tree. The option is\nmatched by its DTMF value; the label is the human-readable text\nshown for review and surfaced to the agent at navigate time.\n","title":"UpdateIVRMenuLabelRequest"},"InvalidateIVRMenuRequest":{"type":"object","properties":{"reason":{"type":"string","description":"Operator-debug cause string. Bounded to 256 chars."}},"description":"Optional reason captured in structured logs. The column today\nis the timestamp, not the cause; a future audit table may\npersist the reason if customer demand justifies it.\n","title":"InvalidateIVRMenuRequest"},"CreateOutboundCallRequest":{"type":"object","properties":{"agent_id":{"type":"string","description":"ID of the agent that handles the answered call."},"to":{"type":"string","description":"Destination phone number in E.164 format (e.g. `+12025559876`)."},"caller_id_number":{"type":"string","description":"The number shown to the callee as caller ID, in E.164 format.\nDefaults to the first outbound-capable number in the workspace.\nUseful for multi-number campaigns where you want to rotate\ncaller IDs.\n"},"dtmf_prefix":{"type":"string","description":"DTMF digits dialed automatically after the call is answered,\nbefore the agent begins speaking. Use this for IVR navigation\n(e.g. `1ww2` presses 1, waits two seconds, presses 2). `w`\nis a half-second pause; `W` is a one-second pause.\n"},"dynamic_variables":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Per-call variable overrides merged on top of the agent's stored\ndefaults. Keys must not use the reserved `system__` prefix.\nUseful for injecting per-call context (customer name, order ID)\ninto the agent prompt.\n"},"ringing_timeout_ms":{"type":"integer","description":"How long to wait for the callee to answer before abandoning,\nin milliseconds. Defaults to 30000 (30s). Capped at 80000 (80s).\n"},"amd":{"$ref":"#/components/schemas/AMDConfig","description":"Optional per-call override for the AMD routing config. When\nset, wholesale-replaces the agent's stored AMD shape for\nthis single call (PATCH-replace, not merge). Unlocks the\nbatch-campaign pattern: one agent dialling many recipients\nwith per-row tailored voicemail messages via the existing\ndynamic_variables substitution. Validation rules match\nthe agent-update boundary.\n"}},"required":["agent_id","to"],"description":"Body for `POST /v1/agents/outbound-calls`. Requires a Twilio or BYOC\ntrunk; LiveKit-native numbers do not support outbound today.\n","title":"CreateOutboundCallRequest"},"CreateOutboundCallResponse":{"type":"object","properties":{"conversation_id":{"type":"string","description":"ID of the conversation created for this call. Use to poll status."}},"required":["conversation_id"],"description":"Returned synchronously when LiveKit accepts the SIP INVITE. Poll\n`GET /v1/agents/conversations/{conversation_id}` for status transitions:\n`pending` (ringing) → `active` (answered) → `completed`.\n","title":"CreateOutboundCallResponse"},"PhoneNumberProvider":{"type":"string","enum":["livekit","twilio","telnyx","byoc","twilio_purchased","telnyx_purchased","verified_caller_id"],"description":"Which provider the number came from. Determines the provisioning\nand portability path.\n\n- `livekit` - LiveKit owns the carrier relationship; US inbound only.\n- `twilio` - Customer's own Twilio number bridged via Elastic SIP Trunk.\n- `telnyx` - Customer's own Telnyx number bridged via a Telnyx FQDN connection.\n- `byoc` - Any SIP provider using a customer-supplied trunk.\n- `twilio_purchased` - Bought through `POST /v1/agents/phone-numbers/purchase` on Speechify's master Twilio account; billed to Speechify.\n- `telnyx_purchased` - Bought through `POST /v1/agents/phone-numbers/purchase` (with `provider=telnyx`) on Speechify's master Telnyx account; billed to Speechify.\n- `verified_caller_id` - Customer-verified outbound caller ID on\n  their own Twilio account (Twilio's OutgoingCallerIds resource).\n  Server-determined at import time: when an `e164` submitted with\n  `provider=twilio` is not a full DID on the customer's account but\n  IS a verified caller ID, the resulting row gets this provider.\n  Outbound-only, never agent-bindable, rides the customer's\n  existing shared Twilio trunk for outbound routing. Requires a\n  prior `twilio` full-DID import from the same account; without\n  it the import returns 400.\n","title":"PhoneNumberProvider"},"PhoneNumberCapability":{"type":"string","enum":["inbound","outbound"],"description":"What the number can do. LiveKit-native numbers are `inbound` only;\nverified caller IDs are `outbound` only; Twilio and BYOC full-DID\nnumbers (and Speechify-purchased numbers) support both directions.\n","title":"PhoneNumberCapability"},"PhoneNumber":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`phone_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"e164":{"type":"string","description":"The phone number in E.164 format (e.g. `+12025551234`)."},"type":{"$ref":"#/components/schemas/PhoneNumberProvider"},"label":{"type":"string","description":"Optional human-readable label set by the customer."},"trunk_id":{"type":"string","description":"ID of the SIP trunk backing this number, if applicable."},"agent_id":{"type":"string","description":"ID of the agent that answers calls to this number. Null when unbound."},"capabilities":{"type":"array","items":{"$ref":"#/components/schemas/PhoneNumberCapability"},"description":"What this number can do."},"created_at":{"type":"string","format":"date-time","description":"When the number was imported."},"updated_at":{"type":"string","format":"date-time","description":"When the number was last modified."}},"required":["id","e164","type","capabilities","created_at","updated_at"],"description":"A phone number in the workspace inventory. Bound to an agent via\n`agent_id`; unbound numbers are valid but non-functional until\nassigned.\n","title":"PhoneNumber"},"ListPhoneNumbersResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"numbers":{"type":"array","items":{"$ref":"#/components/schemas/PhoneNumber"},"description":"Phone numbers in the workspace."}},"required":["next_cursor","has_more","numbers"],"description":"Response for `GET /v1/agents/phone-numbers`.","title":"ListPhoneNumbersResponse"},"TwilioImportSpec":{"type":"object","properties":{"account_sid":{"type":"string","description":"Twilio Account SID (starts with `AC`)."},"auth_token":{"type":"string","description":"Twilio Auth Token. Write-only - never echoed back."}},"required":["account_sid","auth_token"],"description":"Twilio credentials for the one-click import flow. Used only when\n`provider=twilio`. The Account SID and Auth Token are used to\nprovision an Elastic SIP Trunk on the customer's Twilio account\npointing at LiveKit's SIP endpoint, then stored for future trunk\nmanagement operations.\n","title":"TwilioImportSpec"},"TelnyxImportSpec":{"type":"object","properties":{"connection_id":{"type":"string","description":"The Telnyx FQDN connection id (numeric string) the number is\nrouted through. Required.\n"},"sip_username":{"type":"string","description":"Optional credential-auth username for the Telnyx connection.\nWhen both `sip_username` and `sip_password` are provided, the\nimport also provisions outbound calling for the number; omit them\nfor an inbound-only import. Write-only - never echoed back.\n"},"sip_password":{"type":"string","description":"Optional credential-auth password for the Telnyx connection,\npaired with `sip_username`. Write-only - never echoed back.\n"}},"required":["connection_id"],"description":"Telnyx connection details for the bring-your-own-connection import\nflow. Used only when `provider=telnyx`. You provision an FQDN\nconnection on your Telnyx account whose inbound calls forward to\nSpeechify's LiveKit SIP ingress, assign the number to it, then import\nby passing the connection's id. A second number on the same connection\nreuses the one shared trunk + dispatch rule.\n","title":"TelnyxImportSpec"},"ImportPhoneNumberRequest":{"type":"object","properties":{"e164":{"type":"string","description":"The phone number in E.164 format. For `provider=livekit` this\nis the number you want LiveKit to purchase. For `provider=twilio`,\n`provider=telnyx`, and `provider=byoc` it is the number you\nalready own.\n"},"provider":{"$ref":"#/components/schemas/PhoneNumberProvider"},"label":{"type":"string","description":"Optional human-readable label."},"trunk_id":{"type":"string","description":"For `provider=byoc`: the SIP trunk to bind this number to.\nPrefixed wire identifier (`trunk_<26 char Crockford base32>`).\nNot required for `provider=livekit`, `provider=twilio`, or\n`provider=telnyx`.\n"},"agent_id":{"type":"string","description":"Optional agent to bind on import. Prefixed wire identifier\n(`agent_<26 char Crockford base32>`).\n"},"twilio":{"$ref":"#/components/schemas/TwilioImportSpec"},"telnyx":{"$ref":"#/components/schemas/TelnyxImportSpec"}},"required":["e164","provider"],"description":"Body for `POST /v1/agents/phone-numbers`. The required fields vary by\n`provider` - see the individual provider descriptions.\n","title":"ImportPhoneNumberRequest"},"PurchasedPhoneNumberProvider":{"type":"string","enum":["twilio_purchased","telnyx_purchased"],"description":"The carrier a Speechify-managed number is bought on, used by\n`POST /v1/agents/phone-numbers/purchase`. Restricted to the\npurchasable providers - the resulting `phone_numbers` row carries\nthe matching `PhoneNumberProvider` value.\n","title":"PurchasedPhoneNumberProvider"},"AvailablePhoneNumber":{"type":"object","properties":{"e164":{"type":"string","description":"The phone number in E.164 format."},"friendly_name":{"type":"string","description":"Carrier-formatted display variant, e.g. \"(415) 555-2671\"."},"locality":{"type":"string","description":"City the number is associated with, when known."},"region":{"type":"string","description":"Two-letter state code for US numbers."},"iso_country":{"type":"string","description":"ISO-3166 alpha-2 country code."},"provider":{"$ref":"#/components/schemas/PurchasedPhoneNumberProvider","description":"The purchasable carrier this number comes from. Pass it back\nverbatim as `provider` on the purchase request so the buy is\nplaced on the matching Speechify-managed account.\n"}},"required":["e164","iso_country","provider"],"description":"One hit from `GET /v1/agents/phone-numbers/available`. The number is\nnot held: a concurrent buy by another customer may take it\nbetween this response and a subsequent purchase request.\n","title":"AvailablePhoneNumber"},"SearchAvailablePhoneNumbersResponse":{"type":"object","properties":{"numbers":{"type":"array","items":{"$ref":"#/components/schemas/AvailablePhoneNumber"},"description":"Available numbers (may be empty if no inventory matches)."}},"required":["numbers"],"description":"Response for `GET /v1/agents/phone-numbers/available`.","title":"SearchAvailablePhoneNumbersResponse"},"PurchasePhoneNumberRequest":{"type":"object","properties":{"e164":{"type":"string","description":"The E.164 number to buy. Must currently be in carrier inventory."},"label":{"type":"string","description":"Optional human-readable label."},"provider":{"$ref":"#/components/schemas/PurchasedPhoneNumberProvider","description":"Which carrier's Speechify-managed account to buy on. Optional;\ndefaults to `twilio_purchased`.\n"},"agent_id":{"type":"string","description":"Optional agent to bind the number to at purchase time.\nPrefixed wire identifier (`agent_<26 char Crockford base32>`).\n"}},"required":["e164"],"description":"Body for `POST /v1/agents/phone-numbers/purchase`. The `e164` must come\nfrom a recent `SearchAvailablePhoneNumbers` response.\n","title":"PurchasePhoneNumberRequest"},"UpdatePhoneNumberRequest":{"type":"object","properties":{"label":{"type":"string","description":"New label. Pass an empty string to clear."}},"description":"PATCH body for `PATCH /v1/agents/phone-numbers/{phone_number_id}`. Edits the\nnumber's own attributes only - today just `label`. The number's\nprovider and `e164` are immutable after import. The agent binding is managed\nseparately as a relationship, via\n`POST`/`DELETE /v1/agents/{agent_id}/phone-numbers/{phone_number_id}`.\n","title":"UpdatePhoneNumberRequest"},"SIPTrunkProvider":{"type":"string","enum":["livekit","twilio","telnyx","byoc"],"description":"Which provider backs the trunk. Informs the provisioning path and\nportability story.\n\n- `livekit` - Provisioned by LiveKit's native phone-number API.\n- `twilio` - Backed by a Twilio Elastic SIP Trunk on the customer's account.\n- `telnyx` - Backed by a Telnyx FQDN connection on the customer's account.\n- `byoc` - Any SIP provider with a customer-managed trunk.\n","title":"SIPTrunkProvider"},"SIPTrunkDirection":{"type":"string","enum":["inbound","outbound","both"],"description":"Whether the trunk handles inbound calls, outbound calls, or both.\nA `both` trunk has distinct provider inbound and outbound trunk IDs.\n","title":"SIPTrunkDirection"},"SIPTransport":{"type":"string","enum":["auto","udp","tcp","tls"],"description":"SIP transport protocol. `auto` lets LiveKit negotiate. Use `tls`\nfor production where available - note that TLS is incompatible\nwith SIP REFER (cold transfer). Trunks that need `transfer_to_number`\nshould use `udp` or `tcp`.\n","title":"SIPTransport"},"SIPMediaEncryption":{"type":"string","enum":["disable","allow","require"],"description":"SRTP media encryption policy.\n\n- `disable` - Unencrypted media only.\n- `allow` - Negotiate SRTP; fall back to unencrypted. Recommended default.\n- `require` - Reject calls that do not support SRTP.\n","title":"SIPMediaEncryption"},"SIPTrunk":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`trunk_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"name":{"type":"string","description":"Human-readable name."},"provider":{"$ref":"#/components/schemas/SIPTrunkProvider"},"direction":{"$ref":"#/components/schemas/SIPTrunkDirection"},"outbound_trunk_set":{"type":"boolean","description":"Whether an outbound trunk is provisioned for this trunk (i.e. it can place outbound calls)."},"sip_address":{"type":"string","description":"SIP endpoint hostname (e.g. `sip.telnyx.com`). Required for `provider=byoc`."},"auth_username":{"type":"string","description":"SIP digest auth username."},"auth_password_set":{"type":"boolean","description":"Whether a SIP digest auth password is configured. The value is never returned."},"allowed_addresses":{"type":"array","items":{"type":"string"},"description":"IP address / CIDR allowlist for inbound SIP connections."},"destination_country":{"type":"string","description":"ISO 3166-1 alpha-2 country code for the outbound dial plan\n(e.g. `US`, `DE`). Required for international outbound on\nsome carriers.\n"},"transport":{"$ref":"#/components/schemas/SIPTransport"},"media_encryption":{"$ref":"#/components/schemas/SIPMediaEncryption"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","provider","direction","allowed_addresses","transport","media_encryption","created_at","updated_at"],"description":"A SIP trunk in the workspace. Trunks back one or more phone numbers\nand hold the carrier credentials LiveKit uses to route calls.\n`auth_password` is never echoed - `auth_password_set` indicates\nwhether one is configured.\n","title":"SIPTrunk"},"ListSIPTrunksResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"trunks":{"type":"array","items":{"$ref":"#/components/schemas/SIPTrunk"},"description":"SIP trunks in the workspace (up to 20)."}},"required":["next_cursor","has_more","trunks"],"description":"Response for `GET /v1/agents/sip-trunks`.","title":"ListSIPTrunksResponse"},"CreateSipTrunkRequestCredentials":{"type":"object","properties":{},"description":"Provider-specific credential blob (for future extensibility).","title":"CreateSipTrunkRequestCredentials"},"CreateSIPTrunkRequest":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable name for the trunk."},"provider":{"$ref":"#/components/schemas/SIPTrunkProvider"},"direction":{"$ref":"#/components/schemas/SIPTrunkDirection"},"sip_address":{"type":"string","description":"SIP endpoint hostname. Required for `provider=byoc`."},"auth_username":{"type":"string","description":"SIP digest auth username."},"auth_password":{"type":"string","description":"SIP digest auth password. Write-only."},"allowed_addresses":{"type":"array","items":{"type":"string"},"description":"IP / CIDR allowlist for inbound connections. Empty means any source is accepted."},"destination_country":{"type":"string","description":"ISO 3166-1 alpha-2 country for the outbound dial plan."},"transport":{"$ref":"#/components/schemas/SIPTransport"},"media_encryption":{"$ref":"#/components/schemas/SIPMediaEncryption"},"credentials":{"$ref":"#/components/schemas/CreateSipTrunkRequestCredentials","description":"Provider-specific credential blob (for future extensibility)."}},"required":["name","provider","direction"],"description":"Body for `POST /v1/agents/sip-trunks`.","title":"CreateSIPTrunkRequest"},"Caller":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`caller_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"tenant_id":{"type":"string","description":"Prefixed wire identifier (`ws_<26 char Crockford base32>`) of\nthe owning workspace.\n"},"agent_id":{"type":"string","description":"Prefixed wire identifier (`agent_<26 char Crockford base32>`)\nof the agent the caller is scoped under.\n"},"caller_identity":{"type":"string","description":"The raw identifier the caller arrived with (E.164 phone for SIP, LiveKit\nparticipant id for web). Stable for the life of the caller row.\n"},"display_name":{"type":["string","null"],"description":"Operator-editable display name, nullable."},"external_ref":{"type":["string","null"],"description":"Optional handle into the customer's own CRM, nullable."},"metadata":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Customer-supplied JSON metadata blob."},"first_seen_at":{"type":"string","format":"date-time","description":"Timestamp of the earliest observed conversation / memory for this caller."},"last_seen_at":{"type":"string","format":"date-time","description":"Timestamp of the most recent observation. Drives the default list ordering."},"conversation_count":{"type":"integer","description":"Number of conversation rows currently pointing at this caller."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","tenant_id","agent_id","caller_identity","metadata","first_seen_at","last_seen_at","conversation_count","created_at","updated_at"],"description":"First-class Caller entity. Identified by\nthe (tenant, agent, identity) triple. Memories and conversations\nFK at it via `caller_id`.\n","title":"Caller"},"ListCallersResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"callers":{"type":"array","items":{"$ref":"#/components/schemas/Caller"}}},"required":["next_cursor","has_more","callers"],"description":"Payload for GET /v1/agents/callers.","title":"ListCallersResponse"},"DeleteCallerResponse":{"type":"object","properties":{"caller_purged":{"type":"integer","description":"1 on the first delete; 0 on idempotent re-delete."},"memories_purged":{"type":"integer","description":"Number of user_memories rows cascade-soft-deleted under this caller."}},"required":["caller_purged","memories_purged"],"description":"Audit envelope returned by DELETE /v1/agents/callers/{caller_id}. Surfaces\nthe cascade row counts so a privacy operator has direct evidence\nof the purge without re-querying.\n","title":"DeleteCallerResponse"},"UpdateCallerRequest":{"type":"object","properties":{"display_name":{"type":["string","null"],"description":"Operator-editable display name. Empty string clears the column."},"external_ref":{"type":["string","null"],"description":"Optional handle into the customer's own CRM. Empty string clears the column."},"metadata":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Replacement metadata JSONB. Must not be `null`."}},"description":"PATCH payload. Omitted fields are unchanged; present fields\noverwrite. Empty string clears nullable text columns; `metadata`\nreplaces the JSONB blob in full when supplied.\n","title":"UpdateCallerRequest"},"ListCallerConversationsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"conversations":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}}},"required":["next_cursor","has_more","conversations"],"description":"Payload for GET /v1/agents/callers/{caller_id}/conversations.","title":"ListCallerConversationsResponse"},"ListCallerMemoriesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"memories":{"type":"array","items":{"$ref":"#/components/schemas/Memory"}}},"required":["next_cursor","has_more","memories"],"description":"Payload for GET /v1/agents/callers/{caller_id}/memories.","title":"ListCallerMemoriesResponse"},"AudioAsset":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire identifier (`audio_<26 char Crockford base32>`).\nURL paths accept only this\nprefixed form; legacy UUID path parameters are rejected with\n404.\n"},"original_filename":{"type":"string","description":"The filename supplied at upload time, kept for display."},"content_type":{"type":"string","description":"Always `audio/wav`. Pinned server-side after WAV validation\nrather than trusting the upload's multipart Content-Type\nheader.\n"},"size_bytes":{"type":"integer","description":"Stored byte length. Capped at 4 MiB at upload time."},"duration_ms":{"type":"integer","description":"Clip duration in milliseconds. Capped at 30000 (30s) at upload time."},"sample_rate_hz":{"type":"integer","description":"WAV sample rate. Always 48000 (the rate voice agents play back natively)."},"channels":{"type":"integer","description":"Channel count. Always 1 (mono)."},"bit_depth":{"type":"integer","description":"PCM sample bit depth. Always 16."},"created_at":{"type":"string","format":"date-time"}},"required":["id","original_filename","content_type","size_bytes","duration_ms","sample_rate_hz","channels","bit_depth","created_at"],"description":"Metadata for a pre-recorded WAV clip stored in the workspace's\naudio-asset bucket. Bytes are immutable once uploaded — to\nreplace a clip, upload a new asset and update any references.\n","title":"AudioAsset"},"ListAudioAssetsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"assets":{"type":"array","items":{"$ref":"#/components/schemas/AudioAsset"}}},"required":["next_cursor","has_more","assets"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListAudioAssetsResponse"},"ChatCompletionRequestModel":{"type":"string","enum":["waymark-fast","waymark-moa","waymark-max"],"description":"The route to run. `waymark-fast` favors latency, `waymark-moa`\nbalances quality and cost, and `waymark-max` runs the widest panel\nfor the highest quality. Access to the higher routes depends on your\nplan.","title":"ChatCompletionRequestModel"},"ChatMessageRole":{"type":"string","enum":["system","developer","user","assistant","tool"],"description":"The role of the message author.","title":"ChatMessageRole"},"ChatMessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}}],"description":"The message content. A plain string for most messages; OpenAI-style\ncontent-part arrays are also accepted for multimodal input.","title":"ChatMessageContent"},"ChatMessage":{"type":"object","properties":{"role":{"$ref":"#/components/schemas/ChatMessageRole","description":"The role of the message author."},"content":{"$ref":"#/components/schemas/ChatMessageContent","description":"The message content. A plain string for most messages; OpenAI-style\ncontent-part arrays are also accepted for multimodal input."}},"required":["role"],"description":"A single message in an OpenAI-format conversation.","title":"ChatMessage"},"ChatCompletionRequest":{"type":"object","properties":{"model":{"$ref":"#/components/schemas/ChatCompletionRequestModel","description":"The route to run. `waymark-fast` favors latency, `waymark-moa`\nbalances quality and cost, and `waymark-max` runs the widest panel\nfor the highest quality. Access to the higher routes depends on your\nplan."},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"},"description":"The conversation so far, in OpenAI chat-message format."},"stream":{"type":"boolean","description":"When true, the answer is streamed back as a `text/event-stream` of\nserver-sent events instead of a single JSON response. Defaults to\nfalse."}},"required":["model","messages"],"description":"OpenAI-compatible chat-completion request. Only `model` and `messages`\nare required; any other OpenAI parameter (`temperature`, `max_tokens`,\n`tools`, `response_format`, …) is accepted and forwarded unchanged.","title":"ChatCompletionRequest"},"WaymarkModelUsage":{"type":"object","properties":{"model":{"type":"string","description":"The upstream model identifier."},"input_tokens":{"type":"integer","format":"int64","description":"Prompt (input) tokens this model consumed."},"output_tokens":{"type":"integer","format":"int64","description":"Completion (output) tokens this model produced."},"cached_input_tokens":{"type":"integer","format":"int64","description":"Input tokens served from provider cache reads."}},"required":["model","input_tokens","output_tokens","cached_input_tokens"],"description":"Token usage for a single upstream model in the fan-out.","title":"WaymarkModelUsage"},"WaymarkUsage":{"type":"object","properties":{"route":{"type":"string","description":"The route that served the request."},"escalated":{"type":"boolean","description":"Whether the gateway escalated to a higher route for this request."},"models":{"type":"array","items":{"$ref":"#/components/schemas/WaymarkModelUsage"},"description":"One entry per upstream model that ran, summed across the fan-out."}},"required":["escalated","models"],"description":"Per-request routing and token breakdown. Reports the route taken,\nwhether it escalated, and the input, output, and cached-input token counts for each\nupstream model that ran. Token counts only — no pricing or cost.","title":"WaymarkUsage"},"ChatCompletionResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the chat completion."},"object":{"type":"string","description":"The object type, always `chat.completion`."},"created":{"type":"integer","format":"int64","description":"Unix timestamp (seconds) of when the completion was created."},"model":{"type":"string","description":"The route that served the request."},"choices":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}},"description":"The list of completion choices, in OpenAI format."},"usage":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Standard OpenAI token-usage totals for the request."},"waymark":{"$ref":"#/components/schemas/WaymarkUsage"}},"required":["id","choices"],"description":"OpenAI-compatible chat completion. Carries the standard OpenAI fields\n(`id`, `choices`, `usage`, …) plus a `waymark` object describing the\nupstream models that ran. Standard OpenAI clients ignore the extra\nfield.","title":"ChatCompletionResponse"},"AnthropicMessageRequestModel":{"type":"string","enum":["waymark-fast","waymark-moa","waymark-max"],"description":"The route to run. `waymark-fast` favors latency, `waymark-moa`\nbalances quality and cost, and `waymark-max` runs the widest panel\nfor the highest quality. Access to the higher routes depends on your\nplan.","title":"AnthropicMessageRequestModel"},"AnthropicMessageRequestMessagesItemsRole":{"type":"string","enum":["user","assistant"],"description":"The role of the message author.","title":"AnthropicMessageRequestMessagesItemsRole"},"AnthropicMessageRequestMessagesItemsContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}}],"description":"The message content: a plain string for simple turns, or an\narray of Anthropic content blocks for multimodal / tool input.","title":"AnthropicMessageRequestMessagesItemsContent"},"AnthropicMessageRequestMessagesItems":{"type":"object","properties":{"role":{"$ref":"#/components/schemas/AnthropicMessageRequestMessagesItemsRole","description":"The role of the message author."},"content":{"$ref":"#/components/schemas/AnthropicMessageRequestMessagesItemsContent","description":"The message content: a plain string for simple turns, or an\narray of Anthropic content blocks for multimodal / tool input."}},"required":["role","content"],"title":"AnthropicMessageRequestMessagesItems"},"AnthropicMessageRequestSystem":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}}],"description":"A system prompt giving the model context and instructions: a plain\nstring, or an array of Anthropic text blocks.","title":"AnthropicMessageRequestSystem"},"AnthropicMessageRequest":{"type":"object","properties":{"model":{"$ref":"#/components/schemas/AnthropicMessageRequestModel","description":"The route to run. `waymark-fast` favors latency, `waymark-moa`\nbalances quality and cost, and `waymark-max` runs the widest panel\nfor the highest quality. Access to the higher routes depends on your\nplan."},"max_tokens":{"type":"integer","format":"int64","description":"The maximum number of tokens to generate before stopping. Required\nby the Anthropic Messages API."},"messages":{"type":"array","items":{"$ref":"#/components/schemas/AnthropicMessageRequestMessagesItems"},"description":"The conversation so far, in Anthropic message format."},"system":{"$ref":"#/components/schemas/AnthropicMessageRequestSystem","description":"A system prompt giving the model context and instructions: a plain\nstring, or an array of Anthropic text blocks."},"stream":{"type":"boolean","description":"When true, the answer is streamed back as a `text/event-stream` of\nAnthropic server-sent events instead of a single JSON response.\nDefaults to false."},"temperature":{"type":"number","format":"double","description":"Amount of randomness injected into the response (0 to 1)."},"top_p":{"type":"number","format":"double","description":"Use nucleus sampling over the given cumulative probability."},"stop_sequences":{"type":"array","items":{"type":"string"},"description":"Custom text sequences that will cause the model to stop generating."}},"required":["model","max_tokens","messages"],"description":"Anthropic-compatible Messages request. Only `model`, `max_tokens`, and\n`messages` are required; any other Anthropic parameter (`system`,\n`temperature`, `top_p`, `stop_sequences`, `tools`, …) is accepted and\nforwarded unchanged.","title":"AnthropicMessageRequest"},"AnthropicMessageUsage":{"type":"object","properties":{"input_tokens":{"type":"integer","format":"int64","description":"The number of input tokens consumed."},"output_tokens":{"type":"integer","format":"int64","description":"The number of output tokens produced."}},"description":"Anthropic token-usage totals for the request.","title":"AnthropicMessageUsage"},"AnthropicMessage":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the message."},"type":{"type":"string","description":"The object type, always `message`."},"role":{"type":"string","description":"The conversational role of the generated message, always `assistant`."},"model":{"type":"string","description":"The route that served the request."},"content":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}},"description":"The generated content blocks, in Anthropic format."},"stop_reason":{"type":["string","null"],"description":"The reason generation stopped (e.g. `end_turn`, `max_tokens`,\n`stop_sequence`); null while a streamed message is still in flight."},"stop_sequence":{"type":["string","null"],"description":"The custom stop sequence that was generated, if any; otherwise null."},"usage":{"$ref":"#/components/schemas/AnthropicMessageUsage","description":"Anthropic token-usage totals for the request."},"waymark":{"$ref":"#/components/schemas/WaymarkUsage"}},"required":["id","type","role","content"],"description":"Anthropic-compatible Messages response. Carries the standard Anthropic\nfields (`id`, `type`, `role`, `content`, `usage`, …) plus a `waymark`\nobject describing the upstream models that ran. Standard Anthropic\nclients ignore the extra field.","title":"AnthropicMessage"},"LlmModelInfoClass":{"type":"string","enum":["managed","standard","premium"],"description":"Access class controlling which plans may select the model.\n`premium` models are available only on higher plans.\n","title":"LlmModelInfoClass"},"LLMModelInfo":{"type":"object","properties":{"provider":{"type":"string","description":"LLM provider serving the model (e.g. \"openai\", \"speechify\")."},"model":{"type":"string","description":"Model identifier passed through to the provider."},"label":{"type":"string","description":"Human-readable picker label."},"description":{"type":"string","description":"One-line picker description."},"class":{"$ref":"#/components/schemas/LlmModelInfoClass","description":"Access class controlling which plans may select the model.\n`premium` models are available only on higher plans.\n"}},"required":["provider","model","label","description","class"],"description":"One selectable LLM model in the agent model picker.","title":"LLMModelInfo"},"LLMPlatformDefault":{"type":"object","properties":{"provider":{"type":"string","description":"Provider the \"Platform default\" picker entry resolves to."},"model":{"type":"string","description":"Model the \"Platform default\" picker entry resolves to."}},"required":["provider","model"],"description":"The provider/model pair an agent left on the \"Platform default\" picker\nentry resolves to at dispatch time. Introduced 2026-06-25 (pin\n`Speechify-Version: 2026-06-24` or earlier to receive the previous flat\n`platform_default_provider` / `platform_default_model` fields instead).\n","title":"LLMPlatformDefault"},"LLMModelsResponse":{"type":"object","properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/LLMModelInfo"}},"custom_endpoint_allowed":{"type":"boolean","description":"Whether the workspace plan permits a bring-your-own custom LLM endpoint."},"platform_default":{"$ref":"#/components/schemas/LLMPlatformDefault"}},"required":["models","custom_endpoint_allowed","platform_default"],"title":"LLMModelsResponse"},"DeleteMemoriesByCallerResponse":{"type":"object","properties":{"deleted":{"type":"integer","description":"Number of memories soft-deleted."}},"required":["deleted"],"title":"DeleteMemoriesByCallerResponse"},"ConversationLiveKitRoom":{"type":"object","properties":{"room_name":{"type":"string","description":"LiveKit room name. Equals the conversation `id` for `web`\nand `sip_outbound` transports; `sip_inbound` rooms use a\n`sip_<e164>_<random>` name assigned by the SIP dispatch rule.\n"},"room_sid":{"type":"string","description":"LiveKit room SID (`RM_...`), stamped once the room exists.\nAbsent for a conversation whose room was never created.\n"}},"required":["room_name"],"description":"Operator-only projection of a conversation's internal LiveKit\nroom handles, returned by\n`GET /v1/agents/conversations/{conversation_id}/livekit-room`.\nThese are kept off the conversation read responses so they never\nfreeze into the public contract, and are available only to\nSpeechify operators.\n","title":"ConversationLiveKitRoom"},"ConversationTraceEventKind":{"type":"string","enum":["tool","dtmf"],"description":"The kind of action.","title":"ConversationTraceEventKind"},"ConversationTraceEvent":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ConversationTraceEventKind","description":"The kind of action."},"name":{"type":"string","description":"The tool name (agent configuration, not caller data). Empty for DTMF."},"offset_ms":{"type":"integer","format":"int64","description":"Milliseconds from the start of the call to when the action fired."},"duration_ms":{"type":"number","format":"double","description":"How long the action took, in milliseconds."},"is_error":{"type":"boolean","description":"True when the tool call failed."}},"required":["kind","offset_ms"],"description":"A discrete action that fired during a turn - a tool call or a DTMF\nkeypress. Carries timing and kind only, no free-text arguments.","title":"ConversationTraceEvent"},"ConversationTraceTurn":{"type":"object","properties":{"index":{"type":"integer","description":"1-based position of this turn within the call."},"start_offset_ms":{"type":"integer","format":"int64","description":"Milliseconds from the start of the call to the start of this turn."},"e2e_ms":{"type":"number","format":"double","description":"End-to-end response time - caller stopped speaking to agent started speaking."},"stt_ms":{"type":"number","format":"double","description":"Speech-to-text latency for the caller's utterance."},"eou_ms":{"type":"number","format":"double","description":"End-of-turn (end-of-utterance) detection latency."},"llm_ttft_ms":{"type":"number","format":"double","description":"The LLM's time to first token."},"tts_ttfb_ms":{"type":"number","format":"double","description":"TTS time to first audio byte."},"llm_model":{"type":"string","description":"The LLM model that ACTUALLY served this turn's reply (the resolved model, not a wrapper)."},"llm_provider":{"type":"string","description":"The provider that actually served this turn's LLM (e.g. inference.baseten.co, openai)."},"llm_fallback":{"type":"boolean","description":"True when the model that served differs from the agent's configured model - i.e. a provider fallback kicked in."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ConversationTraceEvent"},"description":"Tool calls and DTMF presses that fired during this turn."}},"required":["index","start_offset_ms"],"description":"One conversational exchange: the caller spoke and the agent replied.\nThe stage latencies are the time that went into producing that reply -\nspeech-to-text, end-of-turn detection, the LLM's time to first token,\nand TTS time to first byte - with `e2e_ms` (caller stopped speaking ->\nagent started speaking) as the headline. Stage fields are omitted when\nthat stage produced no span for the turn.","title":"ConversationTraceTurn"},"ConversationTrace":{"type":"object","properties":{"turns":{"type":"array","items":{"$ref":"#/components/schemas/ConversationTraceTurn"}},"first_response_ms":{"type":"number","format":"double","description":"Milliseconds to the agent's first audio (greeting / first reply). Absent when the agent never started speaking."},"end_reason":{"type":"string","description":"How the call ended (e.g. caller_hangup), surfaced even when there are no completed turns."}},"required":["turns"],"description":"The per-call timeline: the conversation's turns in order, each with the\nlatency of the pipeline stages that produced the agent's reply, plus a\ncall-level opening summary. The `turns` array is empty for a call that\nnever connected or produced no completed turns - in which case\n`first_response_ms` and `end_reason` still describe what happened (e.g.\nthe agent's greeting started, then the caller hung up).","title":"ConversationTrace"},"AnalyticsDimensionType":{"type":"string","enum":["enum","bool","number","string"],"description":"The dimension's value type.","title":"AnalyticsDimensionType"},"AnalyticsDimensionSource":{"type":"string","enum":["conversation","evaluation","data_field"],"description":"Where the dimension comes from, used to group the picker.","title":"AnalyticsDimensionSource"},"AnalyticsDimension":{"type":"object","properties":{"key":{"type":"string","description":"Stable dimension key used in filter + group-by requests."},"label":{"type":"string","description":"Human-readable label for the picker."},"type":{"$ref":"#/components/schemas/AnalyticsDimensionType","description":"The dimension's value type."},"source":{"$ref":"#/components/schemas/AnalyticsDimensionSource","description":"Where the dimension comes from, used to group the picker."},"filterable":{"type":"boolean","description":"Whether the dimension can be used as a filter."},"groupable":{"type":"boolean","description":"Whether the dimension can be used as a group-by breakdown."},"enum_values":{"type":"array","items":{"type":"string"},"description":"The closed value set, when known server-side."},"agent_id":{"type":"string","description":"The agent this per-agent dimension belongs to (prefixed id)."}},"required":["key","label","type","source","filterable","groupable"],"description":"One filterable / groupable axis in the analytics catalog. `type` is\nthe value shape; `filterable` and `groupable` are the authoritative\ncapabilities (a discrete number such as agent_version is groupable,\na continuous one such as duration is not). `enum_values` is present\nonly for closed enums whose value set is known server-side.\n`agent_id` is set only on per-agent evaluation / data-collection\ndimensions. Free-text fields are never returned as dimensions.\n","title":"AnalyticsDimension"},"AnalyticsDimensionsResponse":{"type":"object","properties":{"dimensions":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsDimension"}}},"required":["dimensions"],"description":"Payload for GET /v1/agents/analytics/dimensions.","title":"AnalyticsDimensionsResponse"},"AnalyticsMetricAgg":{"type":"string","enum":["count","avg","sum","min","max","rate"],"description":"Aggregation. `count` ignores `field`; `avg`/`sum`/`min`/`max` reduce over a numeric `field`; `rate` is the share of rows matching `rate_predicate`.","title":"AnalyticsMetricAgg"},"AnalyticsFilterOp":{"type":"string","enum":["eq","neq","in","gt","gte","lt","lte"],"title":"AnalyticsFilterOp"},"AnalyticsFilter":{"type":"object","properties":{"field":{"type":"string"},"op":{"$ref":"#/components/schemas/AnalyticsFilterOp"},"value":{"description":"Comparison value — a string, number, boolean, or array of strings (for `in`)."}},"required":["field","op"],"description":"One filter condition. `field` is a filterable dimension key; `op` is the comparison; `value` is a scalar (or array for `in`). Numeric comparison operators require a numeric field.","title":"AnalyticsFilter"},"AnalyticsMetric":{"type":"object","properties":{"agg":{"$ref":"#/components/schemas/AnalyticsMetricAgg","description":"Aggregation. `count` ignores `field`; `avg`/`sum`/`min`/`max` reduce over a numeric `field`; `rate` is the share of rows matching `rate_predicate`."},"field":{"type":"string","description":"Numeric dimension key for avg / sum / min / max (e.g. `duration_ms`, `eval_pass_rate`, `data.<key>`)."},"rate_predicate":{"$ref":"#/components/schemas/AnalyticsFilter"}},"required":["agg"],"description":"The value each group / bucket reduces to.","title":"AnalyticsMetric"},"AnalyticsTimeField":{"type":"string","enum":["started_at","created_at"],"description":"Which timestamp to scope + bucket on. `started_at` excludes never-connected calls; `created_at` counts all attempts.","title":"AnalyticsTimeField"},"AnalyticsTimeBucket":{"type":"string","enum":["none","day","week","month"],"title":"AnalyticsTimeBucket"},"AnalyticsTime":{"type":"object","properties":{"field":{"$ref":"#/components/schemas/AnalyticsTimeField","description":"Which timestamp to scope + bucket on. `started_at` excludes never-connected calls; `created_at` counts all attempts."},"bucket":{"$ref":"#/components/schemas/AnalyticsTimeBucket"},"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"timezone":{"type":"string","description":"IANA timezone for bucket boundaries (default UTC)."}},"description":"Time scope + bucketing. Defaults to the last 30 days, the `started_at` field, no bucketing, and UTC.","title":"AnalyticsTime"},"AnalyticsQueryRequest":{"type":"object","properties":{"metric":{"$ref":"#/components/schemas/AnalyticsMetric"},"group_by":{"type":"array","items":{"type":"string"},"description":"Up to 5 groupable dimension keys. Empty for a single-value (number) result."},"filters":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsFilter"}},"time":{"$ref":"#/components/schemas/AnalyticsTime"},"compare_to_previous":{"type":"boolean","description":"When true, also return the same query for the immediately preceding period of equal length."},"breakdown_limit":{"type":"integer","description":"Max number of breakdown groups (default 50, capped at 50). Excess groups are dropped and `meta.truncated` is set."}},"required":["metric"],"description":"One tenant-scoped aggregation that powers a dashboard widget.","title":"AnalyticsQueryRequest"},"AnalyticsQueryResultBucket":{"type":"string","enum":["none","day","week","month"],"title":"AnalyticsQueryResultBucket"},"AnalyticsPoint":{"type":"object","properties":{"t":{"type":"string","format":"date-time","description":"Bucket start instant."},"value":{"type":"number","format":"double"}},"required":["t","value"],"description":"One time-bucket value in a series.","title":"AnalyticsPoint"},"AnalyticsSeries":{"type":"object","properties":{"group":{"type":"object","additionalProperties":{"type":"string"},"description":"The group-by dimension values for this series (absent when ungrouped)."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsPoint"}},"total":{"type":"number","format":"double"}},"required":["total"],"description":"One breakdown group (or the single ungrouped result). `points` is present only for bucketed (time-series) queries; `total` is the group's value (sum of points when bucketed).","title":"AnalyticsSeries"},"AnalyticsPreviousResult":{"type":"object","properties":{"series":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsSeries"}}},"required":["series"],"description":"The same query over the immediately preceding period.","title":"AnalyticsPreviousResult"},"AnalyticsQueryMeta":{"type":"object","properties":{"group_count":{"type":"integer","description":"Number of breakdown groups returned."},"truncated":{"type":"boolean","description":"True when more groups existed than `breakdown_limit` allowed."}},"required":["group_count","truncated"],"title":"AnalyticsQueryMeta"},"AnalyticsQueryResult":{"type":"object","properties":{"metric":{"$ref":"#/components/schemas/AnalyticsMetric"},"group_by":{"type":"array","items":{"type":"string"}},"bucket":{"$ref":"#/components/schemas/AnalyticsQueryResultBucket"},"series":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsSeries"}},"previous":{"$ref":"#/components/schemas/AnalyticsPreviousResult"},"meta":{"$ref":"#/components/schemas/AnalyticsQueryMeta"},"labels":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"}},"description":"Display names for open-enum group values the client can't resolve from its own list endpoints, keyed by dimension then by the group value. Populated for `agent_id` so a soft-deleted agent (absent from the live agent list) renders \"<name> (deleted)\" instead of a bare `agent_<id>`. Absent when no group needs server-side resolution.\n"}},"required":["metric","group_by","bucket","series","meta"],"description":"Payload for POST /v1/agents/analytics/query.","title":"AnalyticsQueryResult"},"DashboardWidgetChartType":{"type":"string","enum":["number","line","bar","column","donut","table"],"title":"DashboardWidgetChartType"},"DashboardPosition":{"type":"object","properties":{"x":{"type":"integer"},"y":{"type":"integer"},"w":{"type":"integer"},"h":{"type":"integer"}},"required":["x","y","w","h"],"description":"A widget's place + size in the responsive grid (12-column units).","title":"DashboardPosition"},"DashboardWidget":{"type":"object","properties":{"id":{"type":"string","description":"Stable widget id, unique within the dashboard."},"title":{"type":"string"},"chart_type":{"$ref":"#/components/schemas/DashboardWidgetChartType"},"query":{"$ref":"#/components/schemas/AnalyticsQueryRequest"},"group_dim":{"type":"string","description":"Which of the query's group_by dimensions a categorical chart (bar / column / donut / table) renders. Omitted for number / line."},"position":{"$ref":"#/components/schemas/DashboardPosition"}},"required":["id","title","chart_type","query","position"],"description":"One chart on a dashboard — a chart type rendering an analytics query at a grid position.","title":"DashboardWidget"},"DashboardLayout":{"type":"object","properties":{"widgets":{"type":"array","items":{"$ref":"#/components/schemas/DashboardWidget"}}},"required":["widgets"],"title":"DashboardLayout"},"Dashboard":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire id (`dash_<26 char Crockford base32>`)."},"name":{"type":"string"},"description":{"type":["string","null"]},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","layout","created_at","updated_at"],"description":"A saved, workspace-shared analytics dashboard.","title":"Dashboard"},"ListDashboardsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"dashboards":{"type":"array","items":{"$ref":"#/components/schemas/Dashboard"}}},"required":["next_cursor","has_more","dashboards"],"description":"Payload for GET /v1/agents/dashboards.","title":"ListDashboardsResponse"},"CreateDashboardRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":["string","null"]},"layout":{"$ref":"#/components/schemas/DashboardLayout"}},"required":["name","layout"],"title":"CreateDashboardRequest"},"UpdateDashboardRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":["string","null"]},"layout":{"$ref":"#/components/schemas/DashboardLayout"}},"description":"Partial update; omitted fields are left unchanged.","title":"UpdateDashboardRequest"},"TakeOverConversationResponse":{"type":"object","properties":{"conversation_id":{"type":"string"},"signaling_url":{"type":"string","description":"Signaling URL the real-time client connects to."},"token":{"type":"string","description":"Short-lived access token authorizing the operator to publish\naudio to and subscribe to the live call.\n"},"identity":{"type":"string","description":"Opaque participant identity for the operator's session."},"expires_at":{"type":"string","format":"date-time","description":"When the token stops being accepted. The client should re-mint past this point."}},"required":["conversation_id","signaling_url","token","identity","expires_at"],"description":"Connection details for an authorized operator (workspace owner or\nadmin) taking over an active conversation. A real-time client\nconsumes `signaling_url` + `token` to join the live call publishing\nthe operator's microphone; the AI agent stands down for the\nduration and resumes when the operator leaves.\n","title":"TakeOverConversationResponse"},"CredentialKind":{"type":"string","enum":["oauth2_client_credentials","oauth2_jwt","basic","bearer","custom_headers"],"description":"Discriminates the auth flow a credential carries. The matching\n`config.<kind>` block is the one that must be populated.\n","title":"CredentialKind"},"CredentialConfigViewOauth2ClientCredentials":{"type":"object","properties":{"token_url":{"type":"string"},"client_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"audience":{"type":"string"},"client_secret_set":{"type":"boolean","description":"Whether a client secret is stored."}},"required":["token_url","client_id","client_secret_set"],"title":"CredentialConfigViewOauth2ClientCredentials"},"CredentialConfigViewOauth2Jwt":{"type":"object","properties":{"token_url":{"type":"string"},"issuer":{"type":"string"},"subject":{"type":"string"},"audience":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"key_id":{"type":"string"},"private_key_set":{"type":"boolean","description":"Whether a signing key is stored."}},"required":["token_url","issuer","audience","private_key_set"],"title":"CredentialConfigViewOauth2Jwt"},"CredentialConfigViewBasic":{"type":"object","properties":{"username":{"type":"string"},"password_set":{"type":"boolean","description":"Whether a password is stored."}},"required":["username","password_set"],"title":"CredentialConfigViewBasic"},"CredentialConfigViewBearer":{"type":"object","properties":{"token_set":{"type":"boolean","description":"Whether a bearer token is stored."}},"required":["token_set"],"title":"CredentialConfigViewBearer"},"CredentialConfigViewCustomHeaders":{"type":"object","properties":{"header_names":{"type":"array","items":{"type":"string"},"description":"The configured header names; the values are write-only."}},"required":["header_names"],"title":"CredentialConfigViewCustomHeaders"},"CredentialConfigView":{"type":"object","properties":{"oauth2_client_credentials":{"$ref":"#/components/schemas/CredentialConfigViewOauth2ClientCredentials"},"oauth2_jwt":{"$ref":"#/components/schemas/CredentialConfigViewOauth2Jwt"},"basic":{"$ref":"#/components/schemas/CredentialConfigViewBasic"},"bearer":{"$ref":"#/components/schemas/CredentialConfigViewBearer"},"custom_headers":{"$ref":"#/components/schemas/CredentialConfigViewCustomHeaders"}},"description":"The masked, read-safe projection of a credential's config. Returned\non every read (list / get / create / rotate response). Non-secret\nfields (token URLs, client ids, issuer, header names) pass through;\neach secret is replaced by a `*_set` boolean. Secret values are never\nreturned — to change one, rotate it via `PATCH /v1/credentials/{credential_id}`.\nExactly one block is populated, matching the credential's `kind`.\n","title":"CredentialConfigView"},"Credential":{"type":"object","properties":{"id":{"type":"string","description":"Workspace-scoped credential identifier (prefixed external id)."},"name":{"type":"string","description":"Human-readable label, unique per workspace among active\ncredentials.\n"},"kind":{"$ref":"#/components/schemas/CredentialKind"},"config":{"$ref":"#/components/schemas/CredentialConfigView"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","kind","config","created_at","updated_at"],"description":"A workspace-shared secret in the credentials vault. Tools (and\nfuture MCP servers) reference a credential by id rather than\ninlining a secret per row, so one OAuth / Basic / Bearer /\nheaders blob is reused across many tools and rotated centrally.\n\nThe vault is write-only: `config` here is the masked\n`CredentialConfigView` (non-secret fields plus `*_set` markers).\nSecret values are never returned; rotate them via\n`PATCH /v1/credentials/{credential_id}`.\n","title":"Credential"},"ListCredentialsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"credentials":{"type":"array","items":{"$ref":"#/components/schemas/Credential"}}},"required":["next_cursor","has_more","credentials"],"description":"Shared pagination metadata composed into every cursor-paginated\nlist response via `allOf`. Ships `has_more` alongside `next_cursor`\nas two equivalent end-of-pages signals (defense-in-depth).\n","title":"ListCredentialsResponse"},"OAuth2ClientCredentialsConfig":{"type":"object","properties":{"token_url":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"audience":{"type":"string"}},"required":["token_url","client_id","client_secret"],"description":"Static client_id + client_secret pair for the OAuth2\nclient-credentials flow. The tool runtime mints an access token\nat request time and caches it per credential id.\n","title":"OAuth2ClientCredentialsConfig"},"OAuth2JWTConfig":{"type":"object","properties":{"token_url":{"type":"string"},"issuer":{"type":"string"},"subject":{"type":"string"},"audience":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"private_key":{"type":"string"},"key_id":{"type":"string"}},"required":["token_url","issuer","audience","private_key"],"description":"Issuer, audience, and signing key for the JWT-bearer flow\n(RFC 7523) — e.g. Google service accounts that exchange a\nsigned JWT for an access token.\n","title":"OAuth2JWTConfig"},"BasicAuthConfig":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}},"required":["username","password"],"description":"HTTP Basic auth — username + password.","title":"BasicAuthConfig"},"BearerAuthConfig":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"],"description":"A static bearer token sent as `Authorization: Bearer …`. For\nrotating tokens prefer one of the oauth2 kinds.\n","title":"BearerAuthConfig"},"CustomHeadersConfig":{"type":"object","properties":{"headers":{"type":"object","additionalProperties":{"type":"string"}}},"required":["headers"],"description":"An arbitrary set of headers sent on every outbound tool\nrequest. Useful for vendor signature schemes that don't fit\nBasic / Bearer.\n","title":"CustomHeadersConfig"},"CredentialConfig":{"type":"object","properties":{"oauth2_client_credentials":{"$ref":"#/components/schemas/OAuth2ClientCredentialsConfig"},"oauth2_jwt":{"$ref":"#/components/schemas/OAuth2JWTConfig"},"basic":{"$ref":"#/components/schemas/BasicAuthConfig"},"bearer":{"$ref":"#/components/schemas/BearerAuthConfig"},"custom_headers":{"$ref":"#/components/schemas/CustomHeadersConfig"}},"description":"Kind-specific credential payload, used on WRITES only (create and\nrotate). Exactly one block is populated — the one named by the\ncredential's `kind`. The secret fields are write-only: they are\naccepted here but are NEVER returned on reads — a read returns the\nmasked `CredentialConfigView` instead.\n","title":"CredentialConfig"},"CreateCredentialRequest":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable label, unique per workspace."},"kind":{"$ref":"#/components/schemas/CredentialKind"},"config":{"$ref":"#/components/schemas/CredentialConfig"}},"required":["name","kind","config"],"description":"Body for `POST /v1/credentials`.","title":"CreateCredentialRequest"},"UpdateCredentialRequest":{"type":"object","properties":{"name":{"type":"string","description":"New human-readable label, unique per workspace."},"config":{"$ref":"#/components/schemas/CredentialConfig"}},"description":"Body for `PATCH /v1/credentials/{credential_id}`. Rotates a credential's secret\nand/or renames it in place, keeping the same id so every referencing\nconfig picks up the change. Both fields are optional; provide at least\none. The kind is immutable — a rotated `config` must populate the same\nblock as the credential's existing kind.\n","title":"UpdateCredentialRequest"},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed wire id (`whe_<26 char Crockford base32>`)."},"url":{"type":"string","format":"uri","description":"HTTPS destination Speechify POSTs signed events to."},"enabled_events":{"type":"array","items":{"type":"string"},"description":"The events this endpoint receives: a list of catalog event names\n(see `WebhookEventType`) or `[\"*\"]` for every event, current and\nfuture.\n"},"include":{"type":"array","items":{"type":"string"},"description":"Per-event payload shaping. Deliveries are lean by default:\n`data.object` carries only the resource GET snapshot. List heavy\ncollections here to have them appended under the event's `data`\nalongside `object`, so receivers behind hard request-size caps stay\nlean unless they opt in. Recognised keys (conversation events only):\n`messages` (the full transcript) and `evaluations`. Empty = lean.\n"},"description":{"type":["string","null"],"description":"Optional human-readable label for the endpoint."},"disabled":{"type":"boolean","description":"When true, Speechify stops delivering to this endpoint."},"secret":{"type":"string","description":"The HMAC-SHA256 signing secret (`whsec_…`) used to verify the\n`Speechify-Signature` header. Returned ONLY when the endpoint is\ncreated or its secret is rotated — it is never shown again.\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","url","enabled_events","include","disabled","created_at","updated_at"],"description":"A workspace webhook endpoint: a destination URL, the events it\nsubscribes to, and a server-minted HMAC signing secret. `secret` is\nreturned ONLY in the create and rotate-secret responses — store it\nthen; every other read omits it.\n","title":"WebhookEndpoint"},"ListWebhookEndpointsResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"required":["next_cursor","has_more","endpoints"],"description":"Payload for GET /v1/webhooks/endpoints.","title":"ListWebhookEndpointsResponse"},"CreateWebhookEndpointRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"HTTPS destination for event deliveries."},"enabled_events":{"type":"array","items":{"type":"string"},"description":"Catalog event names to subscribe to, or `[\"*\"]` for all events."},"include":{"type":"array","items":{"type":"string"},"description":"Optional payload-shaping keys (see `WebhookEndpoint.include`):\n`messages`, `evaluations`. Omit for the lean default.\n"},"description":{"type":["string","null"]}},"required":["url","enabled_events"],"title":"CreateWebhookEndpointRequest"},"UpdateWebhookEndpointRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"enabled_events":{"type":"array","items":{"type":"string"}},"include":{"type":"array","items":{"type":"string"},"description":"Payload-shaping keys (see `WebhookEndpoint.include`). Send `[]` to\nclear back to the lean default.\n"},"description":{"type":["string","null"]},"disabled":{"type":"boolean"}},"description":"Partial update; omitted fields are left unchanged.","title":"UpdateWebhookEndpointRequest"},"WebhookEndpointDelivery":{"type":"object","properties":{"id":{"type":"string","description":"Prefixed delivery id (`whd_<26 char Crockford base32>`)."},"webhook_endpoint_id":{"type":"string","description":"The endpoint this delivery targeted (`whe_…`)."},"event":{"type":"string","description":"The event type delivered (see `WebhookEventType`)."},"url":{"type":"string","description":"The destination URL at delivery time."},"status":{"$ref":"#/components/schemas/WebhookDeliveryStatus"},"attempt_count":{"type":"integer"},"last_attempt_at":{"type":"string","format":"date-time"},"last_status_code":{"type":"integer"},"last_error":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"request_body":{"type":"string","description":"The verbatim payload the `Speechify-Signature` HMAC was computed over\n(as `<t>.<raw_body>`).\n"},"request_headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Headers sent, including `Speechify-Signature` / `Speechify-Event` / `Speechify-Delivery-Id`."},"last_response_body":{"type":"string","description":"Your server's response body on the most recent attempt (truncated to 8 KiB)."},"last_response_headers":{"type":"object","additionalProperties":{"type":"string"}}},"required":["id","webhook_endpoint_id","event","url","status","attempt_count","created_at"],"description":"One row of an endpoint's delivery log. One row per (endpoint, event,\nresource); updated in place across retry attempts. Each row records the\nexact request payload + signed headers Speechify sent and the response\nyour server returned, so you can verify the signature and debug failures.\n","title":"WebhookEndpointDelivery"},"ListWebhookEndpointDeliveriesResponse":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Opaque keyset cursor for the next page. Pass back as the\n`cursor` request parameter. `null` when the caller has\nreached the end of the list (`has_more` is also `false`\nin that case).\n"},"has_more":{"type":"boolean","description":"True when more rows exist beyond this page."},"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpointDelivery"}}},"required":["next_cursor","has_more","deliveries"],"description":"Payload for GET /v1/webhooks/endpoints/{webhook_endpoint_id}/deliveries.","title":"ListWebhookEndpointDeliveriesResponse"}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'."}}}}