---
title: "AI debug webhook"
method: POST
path: "aiDebugWebhook"
tags: ["AI Webhooks"]
---

# AI debug webhook

`POST aiDebugWebhook` (webhook)

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.

## Payload

- WebhooksAIAiDebugWebhookPayload
  - `call_info` WebhooksAIAICallInfo, required — Identifies the call an AI callback came from. `project_id` and `space_id` are included when available.
    - `project_id` string, uuid — Universal Unique Identifier.
    - `space_id` string, uuid — Universal Unique Identifier.
    - `call_id` string, uuid, required — Universal Unique Identifier.
    - `content_type` string, required — The content type of the POST body. Always `text/json`.
    - `content_disposition` string, required — How the body is delivered. Always `post_data`.
    - `conversation_type` string, required — The conversation type. Always `voice`.
  - `session_start` object — The AI session started. Sent once per session. The fields differ by session type: a standard session reports the voice it will use, while a speech-to-speech session reports `mode` as `oart` along with its audio settings and reports no voice at all. Every field is optional, so read `mode` to tell which kind of session you have.
    - `model` string — The model the agent is running. `unknown` on a speech-to-speech session with no model set.
    - `tts_engine` string — The text-to-speech engine. Standard sessions only, and only when a voice is configured.
    - `tts_voice` string — The text-to-speech voice. Standard sessions only, and only when a voice is configured.
    - `language` string — The language code the session started in. Standard sessions only, and only when a voice is configured.
    - `mode` string — Always `oart` when present, marking a speech-to-speech session. Absent on a standard session.
    - `rate` integer — The audio sample rate, in hertz. Speech-to-speech sessions only.
    - `audio_format` string — The audio encoding. Speech-to-speech sessions only.
    - `tool_model` string — The separate model used for tool calls. Speech-to-speech sessions only, and only when one is configured.
    - `local_vad` boolean — Always `true` when present, meaning voice activity detection runs on the media rather than at the model. Speech-to-speech sessions only.
  - `session_end` object — The AI session ended. Sent once per session.
    - `reason` 'normal' | 'hard_timeout' | 'end_call' | 'error', required — Why the session ended. `normal` on an ordinary finish, `hard_timeout` when it hit its configured time limit, and `end_call` or `error` on a speech-to-speech session that was hung up or failed.
    - `ended_by` string — Who or what ended the call, `system` when nothing recorded it. Absent on a speech-to-speech session.
    - `fatal_error_reason` string — A description of the error. Included only when the session ended on one.
    - `duration_ms` integer, required — How long the session ran, in milliseconds.
    - `input_tokens` integer, required — Input tokens the session consumed.
    - `output_tokens` integer, required — Output tokens the session produced.
  - `startup_hook` object — Your `startup_hook` function finished, whether or not it succeeded.
    - `duration_ms` integer, required — How long the hook took, in milliseconds.
    - `success` boolean, required — Whether the hook ran successfully.
    - `error` string — Why the hook failed. Included only when `success` is `false`.
  - `hangup_hook` object — Your `hangup_hook` function finished, whether or not it succeeded.
    - `duration_ms` integer, required — How long the hook took, in milliseconds.
    - `success` boolean, required — Whether the hook ran successfully.
    - `has_fatal_error` boolean — Whether the session ended on an unrecoverable error. Included only when the hook succeeded.
    - `error` string — Why the hook failed. Included only when `success` is `false`.
  - `speech_detect` object — Speech was recognized from the caller. Suppressed when you enable `redact_prompt`.
    - `text` string, required — The recognized text.
    - `source` string, required — Which recognizer produced the text.
  - `barge` object — The caller interrupted the agent. The fields differ by session type: a standard session reports `barge_type`, `barge_elapsed_ms`, and `interrupt_count`, while a speech-to-speech session reports `audio_played_ms` and `barge_count`.
    - `barge_type` 'transparent' | 'normal' — `transparent` when the agent keeps what it already said, `normal` otherwise.
    - `barge_elapsed_ms` integer — How long the agent had been speaking when the caller cut in, in milliseconds.
    - `interrupt_count` integer — How many times the caller has interrupted so far.
    - `audio_played_ms` integer — How much of the reply had played when the caller cut in, in milliseconds. Speech-to-speech sessions only.
    - `barge_count` integer — How many times the caller has interrupted so far. Speech-to-speech sessions only.
  - `ai_completion` object — The agent finished speaking a reply.
    - `type` 'normal' | 'barged', required — `barged` when the caller interrupted the reply, `normal` when it played to the end.
  - `filler` object — The agent played a filler phrase while it worked.
    - `text` string, required — The phrase that was spoken.
    - `filler_type` 'function' | 'thinking', required — `function` while a tool runs, `thinking` while the model does.
  - `attention_timeout` object, nullable — The caller went quiet for longer than `attention_timeout`. Sent as `null` on speech-to-speech sessions.
    - `timeout_ms` integer, required — The configured timeout, in milliseconds.
  - `hold` object — The agent was placed on hold, or taken off it. `timeout` and `loop` come with `hold` only.
    - `event` 'hold' | 'unhold', required — Which way the hold went.
    - `timeout` integer — How long the hold lasts, in seconds. Absent on `unhold`.
    - `loop` boolean — Whether the hold repeats. Absent on `unhold`.
  - `function_call` object — The agent called one of your functions and the call returned.
    - `function` string, required — The name of the function.
    - `duration_ms` integer, required — How long the function took, in milliseconds.
    - `native` boolean — Whether the function ran inside the platform rather than on your server. Absent on a speech-to-speech shadow call, which reports `shadow` instead.
    - `shadow` boolean — Always `true` when present, marking a call the agent made in the background while it kept talking. Speech-to-speech sessions only.
    - `phase` string — Where in the session the call happened. Included only for a call made while running the post-prompt.
  - `function_loop` object — The agent called the same function repeatedly and was stopped. `consecutive` means it was called several times in a row; `repeated` means it was called with the same arguments each time.
    - `function` string, required — The name of the function.
    - `type` 'consecutive' | 'repeated', required — Which loop guard tripped.
    - `count` integer, required — How many calls triggered the guard.
  - `swaig_call` WebhooksAIAISwaigLogEntry — One tool call the agent made, in the order it was made.
    - `command_name` string, required — The name of the function the agent called.
    - `command_arg` string, required — The arguments it passed, as the raw string the model produced.
    - `epoch_time` integer, required — When the call was made, as a Unix timestamp in seconds.
    - `native` boolean — Always `true` when present, meaning the function ran inside the platform rather than on your server.
    - `active_count` union — How many times the function may still be called, or `endless` when it has no limit. Present only on a function you limited.
      - integer
      - string
    - `url` string — The URL the function was served from. Present when the call reached your server.
    - `post_data` object — The body sent to your server. Present when the call reached it.
    - `post_response` object — The response your server returned. Present when the call reached it and got a reply.
    - `delayed_post_response` object — A response that arrived after the agent had already moved on. Present only when that happened.
    - `mcp_url` string — The MCP server the tool was served from. Present only for an MCP-backed tool.
    - `mcp_tool` string — The tool name on that MCP server. Present only for an MCP-backed tool.
    - `mcp_response` string — What the MCP server returned. Present only for an MCP-backed tool.
    - `mcp_error` boolean — Always `true` when present, meaning the MCP call failed.
  - `process_action` object — A tool returned a SWAIG action. Carries the action exactly as your endpoint returned it.
  - `tool_distill` object — A tool result was shortened before the agent read it.
    - `function` string, required — The function whose result was shortened.
    - `raw_chars` integer, required — Length of the original result, in characters.
    - `distilled_chars` integer, required — Length of the shortened result, in characters.
    - `model` string, required — The model that did the shortening. `default` when none was configured.
  - `webhook` object — The webhook definition as you wrote it. Arrives alongside `input`, and alongside `output` and `match` when the call produced a reply, or `error` when the definition was unusable.
  - `input` object — The body sent to the webhook, or the input an output template was expanded against.
  - `output` object, nullable — The reply the webhook produced, or the output template that matched. `null` when nothing matched.
  - `match` object, nullable — The entry that matched. `null` when none did.
  - `error_keys` unknown[], nullable — The `error_keys` declared on the webhook. `null` when it declares none.
    - unknown
  - `error` object — The webhook could not be evaluated.
    - `error` string, required — What went wrong.
    - `errorText` string, required — The detail behind it.
  - `expression` object — The `expressions` entry as you wrote it. Arrives alongside `input` and `output`.
  - `webhook_log` object — A webhook request completed, with the request and response recorded.
    - `request_url` string, required — The URL that was called, after variable expansion.
    - `request_payload` object — The body that was sent. Omitted on a request with no body.
    - `webhook_response` object, required — The response, plus `http_code` and any `parse_error` or `protocol_error` flags.
  - `webhook_reply` object, nullable — The final reply the webhook produced, after matching. An array reply is wrapped as `{ "array": [...] }`. `null` when the webhook produced no reply.
  - `webhook_fail` WebhooksAIAIDebugWebhookFail — Reports a tool webhook that could not be reached or did not answer usefully. Carries whatever detail the attempt produced, so unlisted keys can appear.
    - `call_info` WebhooksAIAICallInfo, required — Identifies the call an AI callback came from. `project_id` and `space_id` are included when available.
      - `project_id` string, uuid — Universal Unique Identifier.
      - `space_id` string, uuid — Universal Unique Identifier.
      - `call_id` string, uuid, required — Universal Unique Identifier.
      - `content_type` string, required — The content type of the POST body. Always `text/json`.
      - `content_disposition` string, required — How the body is delivered. Always `post_data`.
      - `conversation_type` string, required — The conversation type. Always `voice`.
    - `error` string, required — Always `webhook error`.
    - `request_url` string, required — The URL that was called.
    - `attempts` integer, required — How many attempts were made, including the first.
    - `request_payload` object — The body that was sent, when there was one.
    - `parse_error` boolean — Always `true` when present, meaning the response body was not valid JSON.
    - `raw_response` string — The response body as received. Included only when `parse_error` is set.
    - `parsed_response` object — The response body parsed as JSON. Omitted when the body could not be parsed, where `parse_error` and `raw_response` carry the detail instead.
    - `protocol_error` boolean — Always `true` when present, meaning the request failed before a response was received.
    - `curl_code` integer — The transport error code. Included only when `protocol_error` is set.
    - `http_code` integer, required — The HTTP status code. `0` when no response was received.
  - `step_change` object — The agent moved to a different step.
    - `from_step` string — The step it left. Omitted on the first step.
    - `from_index` integer, required — The index of the step it left.
    - `to_step` string, required — The step it moved to.
    - `to_index` integer, required — The index of the step it moved to.
    - `trigger` 'ai_function' | 'webhook_action' | 'gather_complete' | 'auto_advance' — What caused the move. `ai_function` when the agent called `next_step`, `webhook_action` when a tool's response asked for it, `gather_complete` when a gather finished, and `auto_advance` when the step's own advance condition was met.
  - `context_change` object — The agent moved to a different context.
    - `to_context` string, required — The context it moved to.
    - `from_context` string — The context it left. Omitted on the first context.
    - `trigger` 'ai_function' | 'webhook_action' — What caused the move. `ai_function` when the agent called `change_context`, `webhook_action` when a tool's response asked for it.
    - `isolated` boolean, required — Whether the new context starts without the previous conversation.
  - `context_switch_data` object — The data a context switch was rendered against.
    - `data_root` object, required — The variables available to the new context's prompt.
    - `info` object, required — The context definition as you wrote it.
  - `gather_start` object — A `gather` started collecting answers.
    - `context` string, required — The context the agent was in. `default` when you define no contexts.
    - `step` string — The step the agent was on. Included only when the context defines steps.
    - `step_index` integer — The step's index. Included only when the context defines steps.
    - `output_key` string — The key the collected answers are stored under. Omitted when none was set.
    - `total_questions` integer, required — How many questions the gather will ask.
  - `gather_question` object — A `gather` asked a question.
    - `context` string, required — The context the agent was in. `default` when you define no contexts.
    - `step` string — The step the agent was on. Included only when the context defines steps.
    - `step_index` integer — The step's index. Included only when the context defines steps.
    - `key` string — The key this question fills. Omitted when none was set.
    - `question_index` integer, required — The question's position in the gather, starting at 0.
    - `question_type` string — The kind of answer expected. Omitted when unset.
    - `requires_confirm` boolean, required — Whether the answer has to be confirmed before the gather moves on.
  - `gather_answer` object — A `gather` accepted an answer.
    - `context` string, required — The context the agent was in. `default` when you define no contexts.
    - `step` string — The step the agent was on. Included only when the context defines steps.
    - `step_index` integer — The step's index. Included only when the context defines steps.
    - `key` string — The key the answer filled. Omitted when none was set.
    - `question_index` integer, required — The question's position in the gather, starting at 0.
    - `attempt` integer, required — Which attempt produced the answer, counting from 0.
    - `confirmed` boolean, required — Whether the question required the caller to confirm the answer back before it was accepted.
  - `gather_reject` object — A `gather` rejected an answer and will ask again.
    - `context` string, required — The context the agent was in. `default` when you define no contexts.
    - `step` string — The step the agent was on. Included only when the context defines steps.
    - `step_index` integer — The step's index. Included only when the context defines steps.
    - `key` string — The key the answer would have filled. Omitted when none was set.
    - `question_index` integer, required — The question's position in the gather, starting at 0.
    - `attempt` integer, required — Which attempt was rejected, counting from 0.
    - `reason` 'missing_answer' | 'confirmation_required' — Why it was rejected. `missing_answer` when no answer came back, `confirmation_required` when the answer arrived without the confirmation the question demands.
  - `gather_complete` object — A `gather` finished.
    - `context` string, required — The context the agent was in. `default` when you define no contexts.
    - `step` string — The step the agent was on. Included only when the context defines steps.
    - `step_index` integer — The step's index. Included only when the context defines steps.
    - `output_key` string — The key the collected answers were stored under. Omitted when none was set.
    - `answered` integer, required — How many questions were answered.
    - `completion_action` string — What the gather did on completion. Omitted when nothing recorded it.
  - `conversation_add` WebhooksAIAIDebugConversationAdd — One message as it is added to the conversation. The exact fields depend on which role produced it, so unlisted keys can appear.
    - `role` string, required — Who produced the message: `system`, `user`, `assistant`, or `tool`.
    - `content` string, required — The message text. Redacted when you enable `redact_prompt`.
    - `lang` string — The language the message was in. Omitted on tool messages.
    - `tokens` integer — Tokens the message consumed. Omitted on tool messages.
    - `timestamp` integer — When the message was added, as a Unix timestamp in microseconds.
    - `tool_call_id` string — Links a tool result back to the call that produced it. Present on tool messages.
    - `metadata` object — Per-turn detail. On a caller turn this carries `confidence`, `content_type`, and the speaking-to-final timings. Omitted on turns that have none.
  - `llm_request` object — The agent is about to call the model. Sent only at `debug_webhook_level` `2` and above.
    - `model` string, required — The model being called.
    - `prompt_tokens` integer, required — Tokens in the prompt.
    - `conversation_tokens` integer, required — Tokens in the conversation so far.
  - `llm_response` object — The model answered. Sent only at `debug_webhook_level` `2` and above.
    - `model` string, required — The model that was called.
    - `output_tokens` integer, required — Tokens in the answer.
    - `duration_ms` integer, required — How long the call took, in milliseconds.
    - `success` boolean, required — Whether the model returned anything.
    - `error` string — A description of the failure. Included only when the call failed.
  - `llm_error` object — A model call failed or had to be retried. Read `event` for which: `token_exhaustion` and `llm_fatal` end the session, `llm_max_retries` gives up after repeated failures, and `llm_retry`, `reasoning_only_retry`, `empty_response_nudge_retry`, and `empty_response_effort_bump_retry` recover silently.
    - `event` 'token_exhaustion' | 'llm_fatal' | 'llm_max_retries' | 'reasoning_only_retry' | 'empty_response_nudge_retry' | 'empty_response_effort_bump_retry' | 'llm_retry', required — Which failure this is.
    - `model` string — The model that was called. Omitted on `token_exhaustion`.
    - `token_count` integer — Tokens in the conversation. Included only on `token_exhaustion`.
    - `limit` integer — The token ceiling that was hit. Included only on `token_exhaustion`.
    - `errors` integer — How many failures have accumulated. Included only on `llm_max_retries`.
    - `reasoning_effort` string — The effort level being retried at. Included only on `empty_response_effort_bump_retry`.
  - `consolidation` object — The conversation passed its token ceiling and was summarized to make room.
    - `event` string, required — Always `consolidation`.
    - `token_count` integer, required — Tokens in the conversation when it tripped.
    - `limit` integer, required — The ceiling that was hit.
  - `summarize_start` object — The post-prompt summary is about to be generated.
    - `mode` string, required — How the summary is being produced.
    - `model` string, required — The model producing it. `default` when none was configured.
  - `post_prompt` object — The post-prompt report was delivered.
    - `url` string, required — The URL the report was sent to.
  - `text_normalize` object — Text was rewritten between spoken and written form, for recognition or speech.
    - `direction` 'tn' | 'itn', required — `tn` rewrites text for speaking, `itn` rewrites recognized speech for reading.
    - `language` string, required — The language the rewrite ran in.
    - `original` string, required — The text before the rewrite.
    - `normalized` string, required — The text after it.
  - `voice_error` object — The configured voice could not be used and the agent fell back to another.
    - `event` 'voice_config_error' | 'voice_runtime_error', required — `voice_config_error` when the voice was invalid, `voice_runtime_error` when it failed mid-call.
    - `engine` string, required — The engine that failed.
    - `voice` string, required — The voice that failed.
    - `fallback_engine` string, required — The engine used instead.
    - `fallback_voice` string, required — The voice used instead.
  - `warning` object — Something about the configuration is likely to cause trouble.
    - `event` string, required — Which warning this is.
    - `tokens` integer, required — Tokens in the prompt that triggered it.
  - `oart_user_transcript` object — The caller's speech was transcribed. Speech-to-speech sessions only.
    - `text` string, required — The transcribed text.
  - `oart_assistant_transcript` object — The agent's speech was transcribed. Speech-to-speech sessions only.
    - `text` string, required — The transcribed text.
  - `oart_response_done` object — The agent finished a reply, with its timings. Speech-to-speech sessions only.
    - `latency` integer, required — Time from the end of the caller's turn to the start of the reply, in milliseconds.
    - `utterance_latency` integer, required — Time to the first word of the reply, in milliseconds.
    - `audio_latency` integer, required — Time to the first audio of the reply, in milliseconds.
    - `acoustic_latency` integer, required — Time to the first sound leaving the platform, in milliseconds.
    - `status` string — How the reply finished. Omitted when nothing recorded it.
  - `inner_dialog` object — The agent's private reasoning, when you enable `enable_inner_dialog`. Speech-to-speech sessions only.
    - `text` string, required — The reasoning text. The caller never hears this.

## Acknowledgement `200`

Webhook received

---

[API](https://skmtc.net/signalwire/apis/signalwire-rest-api.md) · [All operations](https://skmtc.net/signalwire/apis/signalwire-rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/signalwire/signalwire-rest-api/revisions/a884f7dcbfc3/schema)
