Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api-reference/v2/live/callback/answering-machine.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: Answering Machine
description: Payload definition for the callback event `live.answering_machine`.
openapi-schema: CallbackLiveAnsweringMachineMessage
---
74 changes: 74 additions & 0 deletions asyncapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 a human or an answering machine picked up.
payload:
$ref: "#/components/schemas/AnsweringMachineMessage"
translation:
name: translation
title: Translation
Expand Down Expand Up @@ -595,6 +610,65 @@ 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 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:
- 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]
Expand Down
64 changes: 64 additions & 0 deletions chapters/live-stt/features/answering-machine-detection.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
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 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

You receive an `answering_machine` message at most 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 |

<Note>
`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.
</Note>

<Warning>
`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.
</Warning>

### Acting on it

Most callers act on `kind` directly:

- **`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.

### Timing and edge cases

The decision fires **at most once per session** and is never revised. Later audio does not change it.

- **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.

### 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.
2 changes: 2 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
Expand Down Expand Up @@ -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"
Expand Down