Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: SignalWire REST AI Webhooks API
version: 1.0.0
contact:
name: SignalWire
url: https://support.signalwire.com/portal/en/newticket?departmentId=1029313000000006907&layoutId=1029313000000074011
email: support@signalwire.com
license:
name: MIT
url: https://github.com/signalwire/docs/blob/main/LICENSE
termsOfService: https://signalwire.com/legal/signalwire-cloud-agreement
description: Callbacks an AI agent sends to your server. The same payloads apply to every surface an agent runs on — voice calls, Amazon Bedrock agents, sidecar agents, and text conversations.
servers:
- url: https://{space_name}.signalwire.com
description: SignalWire API
variables:
space_name:
default: '{Your_Space_Name}'
description: Your SignalWire Space name
security:
- SignalWireBasicAuth: []
tags:
- name: AI Webhooks
description: Callbacks an AI agent sends to your server. The same payloads apply to every surface an agent runs on — voice calls, Amazon Bedrock agents, sidecar agents, and text conversations.
externalDocs:
url: https://signalwire.com/docs/apis
description: Developer documentation on AI webhooks
paths: {}
webhooks:
aiDebugWebhook:
post:
operationId: ai_debug_webhook
summary: AI debug webhook
description: 'A diagnostic feed for a call that is still in progress. Set `debug_webhook_url` on your agent and
every step it takes is posted to that URL as it happens: speech recognized, model called, tool
invoked, context switched, error hit. Use it to work out why a call went the way it did — which
tool the agent reached for, what came back, where a turn went wrong — or to react while the call is
still live, such as paging a supervisor.
Each request carries `call_info` plus one or more event properties, where the property name is the
event. One moment can produce several: evaluating a `data_map` webhook sends `webhook`, `input`,
`output`, `error_keys`, and `match` together. Handle the properties you recognize and ignore the
rest, since the set grows over time.
Setting the URL is what enables the feed. `debug_webhook_level` only widens it: at `2` it also
carries `conversation_add`, `llm_request`, and `llm_response`, which fire on every turn and every
model call.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.AiDebugWebhookPayload'
security:
- {}
aiPostPromptCallback:
post:
operationId: ai_post_prompt_callback
summary: AI post-prompt callback
description: 'Sent to your `ai.post_prompt_url` when the AI session ends. It
carries the agent''s answer to your `post_prompt`
alongside the full record of the call: the conversation, the tool calls, the timings, and the
token counts. This is the one report you get per call, so store the body verbatim and extract only
the fields you query. Nothing you return in the response is read.
Read `action` first. It is `post_conversation` on the end-of-call report described here. The same
URL also receives `fetch_conversation` when the agent starts with a stored conversation
(`save_conversation` with a
`conversation_id`), asking your endpoint to return that conversation; that request carries the
call and session fields but none of the summary fields. Answer it with the stored
`conversation_summary`.
The conversation appears three times. `call_log` is the filtered view, with interrupted segments
consolidated. `raw_call_log` is unfiltered and append-only, and is the only place barge-in detail
survives. `call_timeline` is a flat stream of typed events aligned to `raw_call_log`.
`amazon_bedrock` agents send a different report.
Write your handler against the
Bedrock post-prompt callback instead.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.AiPostPromptCallbackPayload'
security:
- {}
aiSidecarCallback:
post:
operationId: ai_sidecar_callback
summary: AI sidecar callback
description: 'Sent to the sidecar''s `url` as an HTTP `POST` whenever you set one. The same event is always
published in real time on the SignalWire Relay event channel (`calling.ai.sidecar`), so the
webhook is optional. Each event is wrapped under `sidecar_event` — read that before checking its
`type` and fields.
This payload covers the envelope shared by every callback. For the fields specific to each `type`
(such as `insight.raw`, `turn.transcript_delta`, or `final.summary`), see the
SWML ai_sidecar reference.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.AISidecarCallbackPayload'
security:
- {}
aiSidecarSwaigToolWebhook:
post:
operationId: ai_sidecar_swaig_tool_webhook
summary: AI sidecar SWAIG tool webhook
description: 'Sent to a sidecar tool''s `web_hook_url` (or the SWAIG `defaults.web_hook_url`) when the sidecar
calls one of your functions.
Your endpoint runs the function and replies with a JSON object. Both fields are optional, so `{}`
is a valid reply:
- `response` — the result the model reads next. A plain string only; the
`{tool_result, tool_prompt}` object form that `ai` agents
accept is not read. Omit it and the model reads a default result.
- `action` — a single action object or an array of them. See
Supported SWAIG actions for
what you can return.
There is no `post_process` on a sidecar reply.
The sidecar only listens to the call and never speaks on it, so a `say` action is reported back to
you as a callback rather than being spoken aloud.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.AISidecarSwaigToolWebhookPayload'
security:
- {}
aiSwaigToolWebhook:
post:
operationId: ai_swaig_tool_webhook
summary: AI SWAIG tool webhook
description: 'Sent to a tool''s `web_hook_url` (or the SWAIG `defaults.web_hook_url`) when an
`ai` agent calls one of your functions.
Your endpoint runs the function and replies with a JSON object — the same shape a `data_map`
output produces, because the platform reads both the same way. Every field is optional, so `{}` is
a valid reply and a handler that only steers the call can return `action` alone:
- `response` — the result the agent reads next, written to the AI rather than spoken to the
caller. A plain string becomes the tool message as-is; the object form
`{tool_result, tool_prompt}` splits the data half from the steering half. Omit it and the agent
reads a default result.
- `action` — a single action object or an array of them, executed on the live call.
- `post_process` — hold the actions until after the agent has spoken. **Default:** `false`.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.AiSwaigToolWebhookPayload'
security:
- {}
bedrockPostPromptCallback:
post:
operationId: bedrock_post_prompt_callback
summary: Amazon Bedrock post-prompt callback
description: 'Sent to your `amazon_bedrock.post_prompt_url` when
the agent''s session ends, carrying its answer to your `post_prompt` alongside the record of the
call. Nothing you return in the response is read.
Bedrock agents send a different report from `ai` agents. There
is no `call_timeline`, `previous_contexts`, `hard_timeout`, `call_ended_by`, or `ai_id_tag`;
`raw_call_log` is a copy of `call_log` rather than a separate unfiltered view; `swaig_log` is
always empty; `conversation_summary` is always present; and the `total_*` fields arrive without
your having to enable accounting. `post_prompt_url` also takes no separate credentials here — put
them in the URL as `username:password@url`. Write your handler against this payload, not the
AI post-prompt callback.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.BedrockPostPromptCallbackPayload'
security:
- {}
bedrockSwaigToolWebhook:
post:
operationId: bedrock_swaig_tool_webhook
summary: Amazon Bedrock SWAIG tool webhook
description: 'Sent to a tool''s `web_hook_url` (or the SWAIG `defaults.web_hook_url`) when an
`amazon_bedrock` agent calls one of your functions.
Your endpoint runs the function and replies with a JSON object. Both fields are optional, so `{}`
is a valid reply:
- `response` — the result the agent reads next. A plain string only here; the
`{tool_result, tool_prompt}` object form that `ai` agents
accept is not read. Omit it and the agent reads a default result.
- `action` — a single action object or an array of them, executed on the live call.
There is no `post_process`: a Bedrock agent always defers actions until after it has spoken.
Bedrock agents send a different payload from `ai` agents. Notably
`content_type` is `text/json` rather than `text/swaig`, `argument` carries no `substituted` value,
there is no `version`, `description`, or `argument_desc`, and the call''s timing and caller fields
are named differently. Write your handler against this payload, not the
AI SWAIG tool webhook.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.BedrockSwaigToolWebhookPayload'
security:
- {}
swaigSignatureRequest:
post:
operationId: swaig_signature_request
summary: SWAIG function signature request
description: 'Sent once per `SWAIG.includes` entry when an AI
agent loads, to discover the functions your server hosts. Every way of building an agent sends it —
SWML you write yourself, SWML a Server SDK generates, or an agent you configure in your Dashboard —
because they all resolve `includes` the same way.
Reply with the function definitions you host, each shaped like an entry in
`SWAIG.functions` — `function`,
`description`, and `parameters`. Three forms are accepted:
- an array of definitions, the usual one;
- a single definition on its own;
- an object `{functions, defaults}`, where `defaults` sets SWAIG defaults across the definitions
it carries — useful when they share a `web_hook_url` or auth.
Every definition you return is registered, whether or not it was named in the request''s
`functions` list.
This is not the payload a function call sends. It goes to the `includes` entry''s `url`, using
`auth_user` and `auth_password` when set. Your endpoint can also receive it outside of a call, as a
check that it answers, so answer it the same way. When your project has a signing key, the request
carries an `X-SignalWire-Signature` header you can verify.'
parameters: []
responses:
'200':
description: Webhook received
tags:
- AI Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Webhooks.AI.SwaigSignatureRequestPayload'
security:
- {}
components:
schemas:
Webhooks.AI.AISidecarCallbackPayload:
type: object
required:
- call_info
- sidecar_event
properties:
call_info:
allOf:
- $ref: '#/components/schemas/Webhooks.AI.AICallInfo'
description: Envelope describing the call. `project_id` and `space_id` are included when available.
sidecar_event:
allOf:
- $ref: '#/components/schemas/Webhooks.AI.AISidecarEvent'
description: The sidecar callback.
unevaluatedProperties:
not: {}
Webhooks.AI.AISidecarSwaigToolWebhookPayload:
type: object
required:
- function
- argument
- channel_data
properties:
function:
type: string
description: The name of the function the model is calling.
examples:
- lookup_competitor
argument:
type: object
properties:
parsed:
type: array
items:
type: object
unevaluatedProperties: {}
description: The arguments parsed into objects. Usually a single-element array.
examples:
- - competitor: ACME
raw:
type: string
description: The raw argument string, exactly as the model produced it.
examples:
- '{"competitor":"ACME"}'
substituted:
type: string
description: 'Any text that surrounded the JSON, with the JSON itself removed. Omitted when the whole
argument was JSON, which is the usual case.'
examples:
- ''
required:
- parsed
- raw
unevaluatedProperties:
not: {}
description: The arguments the model passed to your function.
call_id:
type: string
description: The ID of the call the sidecar is attached to.
examples:
- 2e1e66e5-5d07-413d-9668-55542992eec0
global_data:
type: object
unevaluatedProperties: {}
description: The sidecar's current `global_data`. Present when the sidecar has any.
channel_data:
allOf:
- $ref: '#/components/schemas/Webhooks.AI.AISidecarChannelData'
description: Identifies the call the sidecar is attached to.
unevaluatedProperties:
not: {}
Webhooks.AI.AiSwaigToolWebhookPayload:
type: object
required:
- function
- argument
- argument_desc
- description
- call_id
- ai_session_id
- app_name
- meta_data_token
- meta_data
- channel_active
- channel_offhook
- channel_ready
- content_type
- version
- content_disposition
- conversation_type
properties:
function:
type: string
description: The name of the function the AI is calling.
examples:
- get_weather
argument:
type: object
properties:
parsed:
type: array
items:
type: object
unevaluatedProperties: {}
description: The arguments parsed into objects. Usually a single-element array.
examples:
- - city: San Francisco
raw:
type: string
description: The raw argument string, exactly as the AI produced it.
examples:
- '{"city":"San Francisco"}'
substituted:
type: string
description: 'Any text that surrounded the JSON, with the JSON itself removed. Omitted when the whole
argument was JSON, which is the usual case.'
examples:
- ''
required:
- parsed
- raw
unevaluatedProperties:
not: {}
description: The arguments the AI passed to your function.
argument_desc:
type: object
unevaluatedProperties: {}
description: The function's parameter definition, as you declared it in `parameters`.
examples:
- type: object
properties:
city:
type: string
description: Name of the city
required:
- city
description:
type: string
description: 'The description you gave the function in
[`SWAIG.functions`](/docs/swml/reference/calling/ai/swaig/functions#properties).'
examples:
- Look up the current weather for a city.
call_id:
type: string
description: The ID of the call. On a chat conversation this carries the conversation id instead.
examples:
- 2e1e66e5-5d07-413d-9668-55542992eec0
ai_session_id:
type: string
description: The ID of the AI session on the call.
examples:
- a0d4e6e5-5d07-413d-9668-55542992eec0
conversation_id:
type: string
description: 'The conversation ID, when the AI session has one. A text conversation held over the
[AI chat endpoint](/docs/apis/rest/ai-chat/chat-methods) always has one, and it matches
`call_id`.'
app_name:
type: string
description: The name of your AI application.
examples:
- ai
global_data:
type: object
unevaluatedProperties: {}
description: The AI session's current `global_data`, when it has any.
examples:
- customer_tier: premium
pickup_address: 123 Main St, Springfield
meta_data_token:
type: string
description: 'The token that scopes `meta_data`. This is the `meta_data_token` you set on the function, or a
value derived from the function''s `web_hook_url` and credentials when you did not set one.'
examples:
- my-token
meta_data:
type: object
unevaluatedProperties: {}
description: Metadata scoped to `meta_data_token`. An empty object when the function has none yet.
examples:
- order_number: '12345'
caller_id_name:
type: string
description: The caller's name, when available.
examples:
- Jane Doe
caller_id_num:
type: string
description: The caller's number, when available.
examples:
- '+15555550100'
channel_active:
type: boolean
description: Whether the call is still up.
examples:
- true
channel_offhook:
type: boolean
description: Whether the call is answered.
examples:
- true
channel_ready:
type: boolean
description: Whether the AI session is ready to take actions.
examples:
- true
content_type:
type: string
description: The content type of the request body. Always `text/swaig`.
examples:
- text/swaig
version:
type: string
description: The SWAIG protocol version.
examples:
- '2.0'
content_disposition:
type: string
description: How the body is delivered. Always `SWAIG Function`.
examples:
- SWAIG Function
conversation_type:
type: string
enum:
- voice
- chat
description: 'The kind of conversation the agent is running: a call, or a text conversation held over the
[AI chat endpoint](/docs/apis/rest/ai-chat/chat-methods).'
examples:
- voice
project_id:
type: string
description: Your project ID, when available.
examples:
- 4d0d6f16-5881-4fcc-92a4-02c51a91954d
space_id:
type: string
description: Your Space ID, when available.
examples:
- 451ed9ff-e568-4222-8af9-4f9ab7428d09
fatal_error:
type: boolean
description: '`true` when the AI session has hit an unrecoverable error. Included only in that case.'
error_reason:
type: string
description: A description of the error. Included only when `fatal_error` is set.
SWMLVars:
type: object
unevaluatedProperties: {}
description: SWML variables for the call. Included when you enable `swaig_post_swml_vars`.
SWMLCall:
type: object
unevaluatedProperties: {}
description: SWML call state. Included when you enable `swaig_post_swml_vars`.
call_log:
type: array
items:
$ref: '#/components/schemas/Webhooks.AI.AICallLogEntry'
description: The conversation so far, with sensitive values redacted. Included when you enable `swaig_post_conversation`.
raw_call_log:
type: array
items:
$ref: '#/components/schemas/Webhooks.AI.AICallLogEntry'
description: The full, unredacted conversation so far. Included when you enable `swaig_post_conversation`.
unevaluatedProperties:
not: {}
Webhooks.AI.AISwaigLogEntry:
type: object
required:
- command_name
- command_arg
- epoch_time
properties:
command_name:
type: string
description: The name of the function the agent called.
examples:
- get_weather
command_arg:
type: string
description: The arguments it passed, as the raw string the model produced.
examples:
- '{"city":"San Francisco"}'
epoch_time:
type: integer
description: When the call was made, as a Unix timestamp in seconds.
examples:
- 1694541334
native:
type: boolean
description: Always `true` when present, meaning the function ran inside the platform rather than on your server.
examples:
- true
active_count:
anyOf:
- type: integer
- type: string
description: 'How many times the function may still be called, or `endless` when it has no limit. Present only
on a function you limited.'
examples:
- 2
url:
type: string
description: The URL the function was served from. Present when the call reached your server.
examples:
- https://example.com/tools/get_weather
post_data:
type: object
unevaluatedProperties: {}
description: The body sent to your server. Present when the call reached it.
post_response:
type: object
unevaluatedProperties: {}
description: The response your server returned. Present when the call reached it and got a reply.
delayed_post_response:
type: object
unevaluatedProperties: {}
description: A response that arrived after the agent had already moved on. Present only when that happened.
mcp_url:
type: string
description: The MCP server the tool was served from. Present only for an MCP-backed tool.
mcp_tool:
type: string
description: The tool name on that MCP server. Present only for an MCP-backed tool.
mcp_response:
type: string
description: What the MCP server returned. Present only for an MCP-backed tool.
mcp_error:
type: boolean
description: Always `true` when present, meaning the MCP call failed.
examples:
- true
unevaluatedProperties:
not: {}
description: One tool call the agent made, in the order it was made.
Webhooks.AI.AISidecarChannelData:
type: object
properties:
call_id:
type: string
description: ID of the call the sidecar is attached to.
examples:
- 2e1e66e5-5d07-413d-9668-55542992eec0
caller_id_name:
type: string
description: The caller's name.
examples:
- Jane Doe
caller_id_number:
type: string
description: The caller's number.
examples:
- '+15555550100'
destination_number:
type: string
description: The number that was called.
examples:
- '+15555550199'
unevaluatedProperties:
not: {}
description: Identifies the call a sidecar callback came from. Each field is included when the call has it.
Webhooks.AI.BedrockPostPromptCallbackPayload:
type: object
required:
- content_type
- content_disposition
- conversation_type
- call_id
- app_name
- ai_session_id
- action
- call_log
- raw_call_log
- post_prompt_data
- global_data
- swaig_log
- conversation_summary
properties:
project_id:
type: string
description: Your project ID, when available.
examples:
- 4d0d6f16-5881-4fcc-92a4-02c51a91954d
space_id:
type: string
description: Your Space ID, when available.
examples:
- 451ed9ff-e568-4222-8af9-4f9ab7428d09
content_type:
type: string
description: The content type of the request body. Always `text/json`.
examples:
- text/json
content_disposition:
type: string
description: How the body is delivered. Always `agent.summary` for the end-of-call report.
examples:
- agent.summary
conversation_type:
type: string
description: The kind of conversation the agent ran. Always `voice`.
examples:
- voice
call_id:
type: string
description: The ID of the call.
examples:
- 2e1e66e5-5d07-413d-9668-55542992eec0
app_name:
type: string
description: The name of your Bedrock application. Defaults to `bedrock`.
examples:
- bedrock
ai_session_id:
type: string
description: The ID of the AI session on the call. Matches `call_id` for Bedrock agents.
examples:
- 2e1e66e5-5d07-413d-9668-55542992eec0
conversation_id:
type: string
description: The conversation ID, when the agent was configured with one.
examples:
- support-thread-4821
action:
type: string
description: What the request is asking of you. Always `post_conversation` for the end-of-call report.
examples:
- post_conversation
call_log:
type: array
items:
$ref: '#/components/schemas/Webhooks.AI.AICallLogEntry'
description: 'The conversation. Each entry carries a `role` of `system`, `user`, or `assistant` and its
`content`.'
examples:
- - role: system
content: You dispatch taxis.
- role: user
content: I need a ride to the airport.
raw_call_log:
type: array
items:
$ref: '#/components/schemas/Webhooks.AI.AICallLogEntry'
description: A copy of `call_log`. Bedrock agents do not keep a separate unfiltered log.
call_start_date:
type: integer
format: int64
description: When the call was created, as a Unix timestamp in microseconds.
examples:
- 1694541295773508
call_answer_date:
type: integer
format: int64
description: When the call was answered, as a Unix timestamp in microseconds. `0` when it never was.
examples:
- 1694541296799504
call_end_date:
type: integer
format: int64
description: When the call ended, as a Unix timestamp in microseconds. `0` while the call is still up.
examples:
- 1694541335435503
ai_start_date:
type: integer
format: int64
description: When the agent started, as a Unix timestamp in microseconds.
examples:
- 1694541297950440
ai_end_date:
type: integer
format: int64
description: When the agent stopped, as a Unix timestamp in microseconds. Omitted while it is still running.
examples:
- 1694541335425164
caller_id_name:
type: string
description: The caller's name, when available.
examples:
- Jane Doe
caller_id_number:
type: string
description: The caller's number, when available.
examples:
- '+15555550100'
times:
type: array
items:
$ref: '#/components/schemas/Webhooks.AI.AIResponseTiming'
description: Per-response performance metrics, one entry per generated reply. Included once the agent has any.
total_minutes:
type: number
description: 'The number of billable minutes, with a minimum of one. Fractional durations are kept as they are;
only a call under a minute is raised to `1`. Included once the agent has stopped.'
examples:
- 3.14
total_input_tokens:
type: integer
description: Input tokens the session consumed. Included once the agent has stopped.
examples:
- 5627
total_output_tokens:
type: integer
description: Output tokens the session produced. Included once the agent has stopped.
examples:
- 119
total_wire_input_tokens:
type: integer
description: A copy of `total_input_tokens`. Included once the agent has stopped.
examples:
- 5627
total_wire_input_tokens_per_minute:
type: number
description: '`total_input_tokens` divided by `total_minutes`. Included once the agent has stopped.'
examples:
- 1792.04
total_wire_output_tokens:
type: integer
description: A copy of `total_output_tokens`. Included once the agent has stopped.
examples:
- 119
total_wire_output_tokens_per_minute:
type: number
description: '`total_output_tokens` divided by `total_minutes`. Included once the agent has stopped.'
examples:
- 37.9
total_tts_chars:
type: integer
description: Characters sent to text-to-speech. Included once the agent has stopped.
examples:
- 842
total_tts_chars_per_min:
type: number
description: '`total_tts_chars` divided by `total_minutes`. Included once the agent has stopped.'
examples:
- 268.15
total_asr_minutes:
type: number
description: Minutes of audio sent to speech recognition. Included once the agent has stopped.
examples:
- 2.41
total_asr_cost_factor:
type: number
description: Always `1`. Bedrock agents do not vary the factor. Included once the agent has stopped.
examples:
- 1
SWMLVars:
type: object
unevaluatedProperties: {}
# --- truncated at 32 KB (103 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/signalwire/refs/heads/main/openapi/signalwire-ai-webhooks-api-openapi.yml