From cf89243fa551def1209bcb31ce8b33cad6b04ccc Mon Sep 17 00:00:00 2001 From: Jean-Louis Queguiner Date: Wed, 9 Sep 2026 12:21:58 -0400 Subject: [PATCH 1/3] docs(ML-93): document the answering_machine message for live STT Tells you whether a human or a voicemail picked up, before the first transcript. - chapters/live-stt/features/answering-machine-detection.mdx : feature page - api-reference/v2/live/callback/answering-machine.mdx : payload reference - asyncapi.yaml : AnsweringMachineMessage schema, channel message, operation - docs.json : both pages in the navigation Three points made explicit, since each would otherwise become a support ticket: confidence is a ranking score and not a probability, silence is reported as human rather than machine, and time is an audio position rather than wall clock so created_at is the field to correlate with application logs. --- .../v2/live/callback/answering-machine.mdx | 5 ++ asyncapi.yaml | 72 +++++++++++++++++++ .../features/answering-machine-detection.mdx | 62 ++++++++++++++++ docs.json | 2 + 4 files changed, 141 insertions(+) create mode 100644 api-reference/v2/live/callback/answering-machine.mdx create mode 100644 chapters/live-stt/features/answering-machine-detection.mdx diff --git a/api-reference/v2/live/callback/answering-machine.mdx b/api-reference/v2/live/callback/answering-machine.mdx new file mode 100644 index 0000000..e310aba --- /dev/null +++ b/api-reference/v2/live/callback/answering-machine.mdx @@ -0,0 +1,5 @@ +--- +title: Answering Machine +description: Payload definition for the callback event `live.answering_machine`. +openapi-schema: CallbackLiveAnsweringMachineMessage +--- diff --git a/asyncapi.yaml b/asyncapi.yaml index 91fbcbd..d8165a3 100644 --- a/asyncapi.yaml +++ b/asyncapi.yaml @@ -32,6 +32,8 @@ channels: $ref: "#/components/messages/speechStart" speechEnd: $ref: "#/components/messages/speechEnd" + answeringMachine: + $ref: "#/components/messages/answeringMachine" translation: $ref: "#/components/messages/translation" namedEntityRecognition: @@ -103,6 +105,12 @@ operations: $ref: "#/channels/liveTranscription" messages: - $ref: "#/channels/liveTranscription/messages/speechEnd" + onAnsweringMachine: + action: send + channel: + $ref: "#/channels/liveTranscription" + messages: + - $ref: "#/channels/liveTranscription/messages/answeringMachine" onTranslation: action: send channel: @@ -259,6 +267,13 @@ components: summary: Indicates the end of detected speech activity. payload: $ref: "#/components/schemas/SpeechEventMessageEnd" + answeringMachine: + name: answering_machine + title: Answering Machine + contentType: application/json + summary: Reports whether the callee is a human or an answering machine. + payload: + $ref: "#/components/schemas/AnsweringMachineMessage" translation: name: translation title: Translation @@ -595,6 +610,63 @@ components: time: 1.24 channel: 0 + AnsweringMachineMessage: + title: Answering Machine + type: object + required: [session_id, created_at, type, data] + properties: + session_id: { $ref: "#/components/schemas/UUID" } + created_at: { $ref: "#/components/schemas/ISODateTime" } + type: { type: string, const: answering_machine } + data: + type: object + required: [kind, confidence, time] + properties: + kind: + type: string + enum: [human, machine] + description: Whether a person picked up or the call reached an answering machine. + confidence: + type: number + minimum: 0 + maximum: 1 + description: >- + How machine-like the call opening was, between 0 and 1. This is a ranking + score, not a calibrated probability: compare it against a threshold tuned on + your own traffic rather than reading it as a likelihood. + time: + type: number + description: >- + Position in the audio stream, in seconds from the start of the session, at + which the decision was taken. Measured on the audio timeline and sharing the + same reference as speech_start, speech_end and transcript, so all messages can + be ordered against each other. Use created_at to correlate with wall-clock logs. + channel: + type: integer + description: Audio channel index (0-based) for which the decision applies. + description: Outcome of answering machine detection for the session. + description: >- + Reports whether the callee is a human or an answering machine. Emitted at most once + per session, before the first transcript, and never revised. Does not require + transcription, so it behaves the same across languages. + examples: + - session_id: "550e8400-e29b-41d4-a716-446655440000" + created_at: "2026-09-09T12:34:11Z" + type: answering_machine + data: + kind: machine + confidence: 0.78 + time: 5.24 + channel: 0 + - session_id: "550e8400-e29b-41d4-a716-446655440000" + created_at: "2026-09-09T12:34:11Z" + type: answering_machine + data: + kind: human + confidence: 0.12 + time: 5.31 + channel: 0 + TranslationMessage: type: object required: [session_id, created_at, type, data] diff --git a/chapters/live-stt/features/answering-machine-detection.mdx b/chapters/live-stt/features/answering-machine-detection.mdx new file mode 100644 index 0000000..39ced63 --- /dev/null +++ b/chapters/live-stt/features/answering-machine-detection.mdx @@ -0,0 +1,62 @@ +--- +title: "Answering Machine Detection" +description: "Know within seconds whether a human or a voicemail picked up" +--- + +Answering machine detection tells you whether the person you called picked up, or whether you reached a voicemail greeting. + +The decision arrives in the first seconds of the call, before the first transcript, so an outbound agent can act on it immediately. + +### The message + +You receive an `answering_machine` message once per session: + +```json +{ + "session_id": "550e8400-e29b-41d4-a716-446655440000", + "created_at": "2026-09-09T12:34:11Z", + "type": "answering_machine", + "data": { + "kind": "machine", + "confidence": 0.78, + "time": 5.24, + "channel": 0 + } +} +``` + +| Field | Meaning | +|---|---| +| `kind` | `human` or `machine` | +| `confidence` | Score between 0 and 1 indicating how machine-like the call opening was | +| `time` | Position in the audio stream, in seconds from the start of the session, at which the decision was taken | +| `channel` | Audio channel index the decision applies to | + + +`time` is measured on the **audio timeline**, not the clock. It uses the same reference as `speech_start`, `speech_end` and `transcript`, so you can order all of them against each other. If you push audio faster than real time, `time` still refers to the audio position, so use `created_at` when you need to correlate with your own logs. + + + +`confidence` is a **ranking score, not a probability**. A value of `0.7` does not mean "70% chance this is a machine". Use it to compare against a threshold you tune on your own traffic, not as a calibrated likelihood. + + +### Acting on it + +Most callers act on `kind` directly: + +- **`machine`** — hang up and requeue the number, or stay silent and let the greeting finish before leaving a recorded message. +- **`human`** — start the conversation. + +If you want to be more conservative than the default, read `confidence` and require a high score before treating a call as a machine. Hanging up on a real person usually costs more than a few wasted seconds on a voicemail, so a threshold above the default is a common choice. + +### Timing and edge cases + +The decision fires **once per session** and is never revised. Later audio does not change it. + +- **The callee says nothing at all.** You still receive a message, reported as `human` with a low confidence. Silence is not evidence of a machine, and staying on the line is the safer default. +- **Very short calls.** If the session ends before a decision can be taken, no message is emitted. +- **No transcription required.** The detection does not depend on what was said, so it behaves the same across languages and adds no transcription latency. + +### Limits + +Detection is tuned for the opening of an outbound call. It is not designed to detect an answering machine that picks up mid-conversation, and it does not attempt to identify IVR menus or hold music. diff --git a/docs.json b/docs.json index 4f6e194..a409986 100644 --- a/docs.json +++ b/docs.json @@ -63,6 +63,7 @@ "chapters/live-stt/quickstart", "chapters/live-stt/audio-intelligence", "chapters/live-stt/features/endpointing", + "chapters/live-stt/features/answering-machine-detection", "chapters/live-stt/features/partial-transcripts", "chapters/live-stt/recommended-parameters" ] @@ -184,6 +185,7 @@ "api-reference/v2/live/callback/transcript", "api-reference/v2/live/callback/speech-start", "api-reference/v2/live/callback/speech-end", + "api-reference/v2/live/callback/answering-machine", "api-reference/v2/live/callback/translation", "api-reference/v2/live/callback/named-entity-recognition", "api-reference/v2/live/callback/sentiment-analysis" From d3fdebd990d19d102bd595e0b14ad7e29e9d7aa3 Mon Sep 17 00:00:00 2001 From: Jean-Louis Queguiner Date: Wed, 9 Sep 2026 17:34:19 -0400 Subject: [PATCH 2/3] docs(ML-93): window starts at first speech, no message on silence --- asyncapi.yaml | 6 ++++-- .../features/answering-machine-detection.mdx | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/asyncapi.yaml b/asyncapi.yaml index d8165a3..b7d63f3 100644 --- a/asyncapi.yaml +++ b/asyncapi.yaml @@ -647,8 +647,10 @@ components: description: Outcome of answering machine detection for the session. description: >- Reports whether the callee is a human or an answering machine. Emitted at most once - per session, before the first transcript, and never revised. Does not require - transcription, so it behaves the same across languages. + per session, about five seconds after the callee first speaks, and never revised. + Not emitted if the callee never speaks or if the session ends before the decision. + Does not require transcription, so it behaves the same across languages; partial + or final transcripts may arrive before it. examples: - session_id: "550e8400-e29b-41d4-a716-446655440000" created_at: "2026-09-09T12:34:11Z" diff --git a/chapters/live-stt/features/answering-machine-detection.mdx b/chapters/live-stt/features/answering-machine-detection.mdx index 39ced63..abacaac 100644 --- a/chapters/live-stt/features/answering-machine-detection.mdx +++ b/chapters/live-stt/features/answering-machine-detection.mdx @@ -5,11 +5,11 @@ description: "Know within seconds whether a human or a voicemail picked up" Answering machine detection tells you whether the person you called picked up, or whether you reached a voicemail greeting. -The decision arrives in the first seconds of the call, before the first transcript, so an outbound agent can act on it immediately. +The decision arrives about five seconds after the callee starts speaking, without waiting for a transcript, so an outbound agent can act on it immediately. ### The message -You receive an `answering_machine` message once per session: +You receive an `answering_machine` message at most once per session: ```json { @@ -51,10 +51,12 @@ If you want to be more conservative than the default, read `confidence` and requ ### Timing and edge cases -The decision fires **once per session** and is never revised. Later audio does not change it. +The decision fires **at most once per session** and is never revised. Later audio does not change it. -- **The callee says nothing at all.** You still receive a message, reported as `human` with a low confidence. Silence is not evidence of a machine, and staying on the line is the safer default. -- **Very short calls.** If the session ends before a decision can be taken, no message is emitted. +- **The window starts when the callee first speaks.** Ringing, connection delay and any leading silence do not count. The decision is taken once five seconds of audio have been heard after that first speech. +- **The callee says nothing at all.** No message is emitted: silence never starts the window and is not evidence of a machine. Apply your own timeout if you need to give up on a silent line. +- **Very short calls.** If the session ends before the five seconds have elapsed, no message is emitted. +- **Transcripts are not ordered against it.** Partial or final transcripts may arrive before the decision. - **No transcription required.** The detection does not depend on what was said, so it behaves the same across languages and adds no transcription latency. ### Limits From 7de7ba7df8a7c9853711b1a53f144511482b7b88 Mon Sep 17 00:00:00 2001 From: Jean-Louis Queguiner Date: Wed, 9 Sep 2026 17:48:39 -0400 Subject: [PATCH 3/3] docs(ML-93): reword terms flagged by the Vale spellcheck --- asyncapi.yaml | 8 ++++---- .../live-stt/features/answering-machine-detection.mdx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/asyncapi.yaml b/asyncapi.yaml index b7d63f3..01584d4 100644 --- a/asyncapi.yaml +++ b/asyncapi.yaml @@ -271,7 +271,7 @@ components: name: answering_machine title: Answering Machine contentType: application/json - summary: Reports whether the callee is a human or an answering machine. + summary: Reports whether a human or an answering machine picked up. payload: $ref: "#/components/schemas/AnsweringMachineMessage" translation: @@ -646,9 +646,9 @@ components: description: Audio channel index (0-based) for which the decision applies. description: Outcome of answering machine detection for the session. description: >- - Reports whether the callee is a human or an answering machine. Emitted at most once - per session, about five seconds after the callee first speaks, and never revised. - Not emitted if the callee never speaks or if the session ends before the decision. + Reports whether a human or an answering machine picked up. Emitted at most once + per session, about five seconds after the first speech, and never revised. + Not emitted if nobody speaks or if the session ends before the decision. Does not require transcription, so it behaves the same across languages; partial or final transcripts may arrive before it. examples: diff --git a/chapters/live-stt/features/answering-machine-detection.mdx b/chapters/live-stt/features/answering-machine-detection.mdx index abacaac..b979d5f 100644 --- a/chapters/live-stt/features/answering-machine-detection.mdx +++ b/chapters/live-stt/features/answering-machine-detection.mdx @@ -5,7 +5,7 @@ description: "Know within seconds whether a human or a voicemail picked up" Answering machine detection tells you whether the person you called picked up, or whether you reached a voicemail greeting. -The decision arrives about five seconds after the callee starts speaking, without waiting for a transcript, so an outbound agent can act on it immediately. +The decision arrives about five seconds after the person you called starts speaking, without waiting for a transcript, so an outbound agent can act on it immediately. ### The message @@ -44,7 +44,7 @@ You receive an `answering_machine` message at most once per session: Most callers act on `kind` directly: -- **`machine`** — hang up and requeue the number, or stay silent and let the greeting finish before leaving a recorded message. +- **`machine`** — hang up and queue the number for a later attempt, or stay silent and let the greeting finish before leaving a recorded message. - **`human`** — start the conversation. If you want to be more conservative than the default, read `confidence` and require a high score before treating a call as a machine. Hanging up on a real person usually costs more than a few wasted seconds on a voicemail, so a threshold above the default is a common choice. @@ -53,8 +53,8 @@ If you want to be more conservative than the default, read `confidence` and requ The decision fires **at most once per session** and is never revised. Later audio does not change it. -- **The window starts when the callee first speaks.** Ringing, connection delay and any leading silence do not count. The decision is taken once five seconds of audio have been heard after that first speech. -- **The callee says nothing at all.** No message is emitted: silence never starts the window and is not evidence of a machine. Apply your own timeout if you need to give up on a silent line. +- **The window starts at the first speech.** Ringing, connection delay and any leading silence do not count. The decision is taken once five seconds of audio have been heard after that first speech. +- **Nobody speaks at all.** No message is emitted: silence never starts the window and is not evidence of a machine. Apply your own timeout if you need to give up on a silent line. - **Very short calls.** If the session ends before the five seconds have elapsed, no message is emitted. - **Transcripts are not ordered against it.** Partial or final transcripts may arrive before the decision. - **No transcription required.** The detection does not depend on what was said, so it behaves the same across languages and adds no transcription latency.