> For complete lifecycle-event payload schemas and examples, use the canonical overview: Session /api/sessions; Room lifecycle, members, and room playback /api/rooms; Session playback /api/playback; Recording /api/recording; DTMF /api/keypad-input; Messages /api/messages; WebSocket Session /api/web-socket. Use /api/event-delivery for transport behavior. Endpoint pages name relevant events, but these overviews are the canonical references.

# Keypad (DTMF)

> Complete keypad-input command and event reference for individual DTMF presses and collected digits.

Keypad input lets your application receive keypad presses from a caller or send
them to a remote party on a Session. These key presses use
[dual-tone multi-frequency (DTMF)](https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling)
signals.

## When to use

Use keypad input to collect menu choices or digits from callers, or to send
DTMF tones to another IVR system.

For inbound input, handle [`dtmf.received`](#dtmfreceived) events when each key
press matters. Use [Play prompt and collect DTMF
digits](/api/keypad-input/collect) when you need a complete response, and
[cancel the collection](/api/keypad-input/cancel) if it should end early. The
completed response is delivered as a [`digits.collected`](#digitscollected)
event.

For outbound input, use [Send DTMF sequence](/api/keypad-input/send) to send
keys and timed waits to the remote party, such as when navigating an automated
phone menu.

## Lifecycle events

The platform emits DTMF (keypad tone) events when callers press keys on their phone keypad. `dtmf.received` reports individual key presses, and `digits.collected` reports aggregated results from the DTMF collection command.

Every payload schema below also includes the required `aud` string, which
identifies the application that should receive the signed event.

## dtmf.received

Fired when the caller presses a DTMF key during the call. This event fires independently of any command — individual key presses are reported as they occur during playback, recording, or any other call state.

### Payload schema

| Field          | Type    | Description                                                                                                                                        |
| -------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event`        | string  | Always `"dtmf.received"`. **Required**                                                                                                             |
| `session_uuid` | string  | Unique session identifier. **Required**                                                                                                            |
| `digit`        | string  | Single DTMF character: `0`-`9`, `A`-`D`, `*`, or `#`. **Required**                                                                                 |
| `duration_ms`  | integer | Key press duration in milliseconds. **Required**                                                                                                   |
| `timestamp`    | string  | RFC 3339 / ISO 8601 UTC timestamp at which the event was emitted (e.g. `"2025-06-06T08:53:24.123Z"`). Present on every webhook event. **Required** |

For example, a `dtmf.received` event has this payload:

```json
{
  "aud": "app_3f9c0b2a-7d41-4e8b-9f12-2a6c5d0e7b34",
  "event": "dtmf.received",
  "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "digit": "5",
  "duration_ms": 120,
  "timestamp": "2025-06-06T08:53:24.123Z"
}
```

Valid `digit` values are `0`–`9`, `A`–`D`, `*`, and `#`. A letter-digit example:

```json
{
  "aud": "app_3f9c0b2a-7d41-4e8b-9f12-2a6c5d0e7b34",
  "event": "dtmf.received",
  "session_uuid": "acW68-...",
  "digit": "A",
  "duration_ms": 100,
  "timestamp": "2025-06-06T08:53:24.500Z"
}
```

## digits.collected

Fired once when a DTMF collection command finishes its single prompt-and-collect cycle. It aggregates the key presses into a single result with a `status` describing the outcome. The command never retries on its own — your app inspects `status` and decides whether to re-prompt. See [Play prompt and collect DTMF digits](/api/keypad-input/collect).

**Event filtering.** [`dtmf.received`](#dtmfreceived) and
[`digits.collected`](#digitscollected) are independent webhook events, and by
default both are delivered. Individual [`dtmf.received`](#dtmfreceived) events
also fire during digit collection. Use [`digits.collected`](#digitscollected)
for the final aggregated result and [`dtmf.received`](#dtmfreceived) events if
you need per-key feedback as each digit arrives.

### Payload schema

| Field            | Type   | Description                                                                                                                                                |
| ---------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event`          | string | Always `"digits.collected"`. **Required**                                                                                                                  |
| `session_uuid`   | string | Unique session identifier. **Required**                                                                                                                    |
| `operation_uuid` | string | The `operation_uuid` echoed from the 202 acknowledgement of the DTMF collection request. **Required**                                                      |
| `digits`         | string | The collected DTMF digit string. May be empty on timeout. **Required**                                                                                     |
| `terminator`     | string | The DTMF key that terminated collection (`0`-`9`, `A`-`D`, `*`, `#`) or empty on timeout. **Required**                                                     |
| `status`         | string | Outcome of the prompt-and-collect cycle. One of: `success`, `no_input`, `partial_then_timeout`, `invalid`, `failure`, `cancelled`, `unknown`. **Required** |
| `timestamp`      | string | RFC 3339 / ISO 8601 UTC timestamp at which the event was emitted (e.g. `"2025-06-06T08:53:24.123Z"`). Present on every webhook event. **Required**         |

### Collection statuses

| Status                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `success`              | At least `min_digits` digits were collected and any configured validation passed. Collection may have ended by a terminator key, by reaching `max_digits`, or by the `between_digits_timeout_ms` timer expiring once at least `min_digits` digits had already been entered — all are successes; the digits are delivered either way. With `min_digits: 0`, a caller who presses only a terminator key submits an empty entry: `status` is `success`, `digits` is empty, and `terminator` carries the key that ended collection. |
| `no_input`             | The caller entered no digits at all. `digits` is empty.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `partial_then_timeout` | The caller entered some digits but fewer than `min_digits`, then stopped pressing keys and the inter-digit timer (`between_digits_timeout_ms`) expired before reaching `min_digits`. `digits` holds the partial input.                                                                                                                                                                                                                                                                                                          |
| `invalid`              | Digits were collected but failed the configured `validation.regex`. `digits` holds what was entered.                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `failure`              | The collection failed before any outcome could be classified — the caller hung up before or during the prompt or collection, the call had not yet been answered, or the prompt file could not be played. The `digits` field is usually empty, but may contain partial input that was collected before the failure.                                                                                                                                                                                                              |
| `cancelled`            | The collection was cancelled by the [DTMF collection cancellation endpoint](/api/keypad-input/cancel). If the command was already running when the `DELETE` arrived, `digits` holds whatever partial input had been collected so far (which may be empty if the caller had not yet pressed a key). If the command was still queued behind another command and had not started, `digits` is always empty.                                                                                                                        |
| `unknown`              | An unexpected outcome. Log it and investigate; do not retry the command.                                                                                                                                                                                                                                                                                                                                                                                                                                                        |

Example — success:

```json
{
  "aud": "app_3f9c0b2a-7d41-4e8b-9f12-2a6c5d0e7b34",
  "event": "digits.collected",
  "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "operation_uuid": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
  "digits": "1234",
  "terminator": "#",
  "status": "success",
  "timestamp": "2025-06-06T08:53:24.123Z"
}
```

Example — no input:

```json
{
  "aud": "app_3f9c0b2a-7d41-4e8b-9f12-2a6c5d0e7b34",
  "event": "digits.collected",
  "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "operation_uuid": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
  "digits": "",
  "terminator": "",
  "status": "no_input",
  "timestamp": "2025-06-06T08:53:24.123Z"
}
```

Example — failure with partial digits:

```json
{
  "aud": "app_3f9c0b2a-7d41-4e8b-9f12-2a6c5d0e7b34",
  "event": "digits.collected",
  "session_uuid": "acW68-...",
  "operation_uuid": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
  "digits": "12",
  "terminator": "",
  "status": "failure",
  "timestamp": "2025-06-06T08:53:24.123Z"
}
```

Example — cancelled:

```json
{
  "aud": "app_3f9c0b2a-7d41-4e8b-9f12-2a6c5d0e7b34",
  "event": "digits.collected",
  "session_uuid": "acW68-...",
  "operation_uuid": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
  "digits": "",
  "terminator": "",
  "status": "cancelled",
  "timestamp": "2025-06-06T08:53:24.123Z"
}
```

## Triggered by

These events are produced by the following triggers:

* [`dtmf.received`](#dtmfreceived) — automatic: fires on every DTMF key press during active calls.
* [`digits.collected`](#digitscollected) — [DTMF collection](/api/keypad-input/collect) command.