> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.telekesher.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.telekesher.dev/_mcp/server.

# Send DTMF sequence

POST https://api.telekesher.dev/v1/sessions/{uuid}/dtmf/send
Content-Type: application/json

**Rate limit: Per command** · **Burst:** 20 · **Refill:** 20 req/s

Send ordered DTMF keys and waits to the remote party on an answered phone session. Each action controls its own key duration or delay.

Only one sequence can be active per session.

Ringing calls and standalone WebSocket sessions created with `POST /v1/sessions:connectWebsocket` are not supported.

`wait.duration_ms` is a minimum delay before the next action; dispatch may occur later. Action order is preserved.

The acceptance webhook omits the sequence to protect secrets and confirms acceptance only, not remote handling.

**Triggered webhook:** `command.dtmf.send.accepted`

Reference: https://docs.telekesher.dev/api/keypad-input/send

## Authentication

- `Authorization` header (bearer token, required) — Application auth. Send `Authorization: Bearer <app_uuid>:<api_key>`. See [Authentication](https://voice-platform.docs.buildwithfern.com/api/authentication) for details.

## Request

### Path parameters

- `uuid` (string, required) — [Session](/api/sessions) UUID (format `{5-char-prefix}-{uuid}`).

### Headers

- `Idempotency-Key` (string, optional) — Optional client-generated key for a mutating endpoint. It identifies one method, route, query, content type, and exact raw body within the authenticated app. Reusing it for a different request returns 422. While its record exists, a retry replays the original accepted response when available. Keys are valid for 1 hour. Allowed characters: letters, digits, dot, hyphen, underscore; max 128 characters. See the Idempotency guide.

### Body (application/json)

- `sequence` (list of object or object, required) — Ordered key and wait actions. Waits may appear anywhere and consecutive waits are allowed. The total nominal duration may not exceed ten minutes, and the sequence must include at least one key action.
  - object
    - `digit` (string, required) — The DTMF key to send: `0`-`9`, `A`-`D`, `*`, or `#`.
    - `type` ("key", required) — Send one DTMF key press.
    - `duration_ms` (integer, optional, default: 250) — Duration of this key press in milliseconds.
  - object
    - `duration_ms` (integer, required) — Requested wait in whole milliseconds; arbitrary values such as `1375` are accepted.
    - `type` ("wait", required) — Wait before executing the next sequence action.
- `operation_uuid` (string, optional) — Optional caller-supplied per-command correlation id, a bare lowercase RFC-4122 v4 UUID (no prefix). Echoed back as `operation_uuid` in the 202 ack. A later lifecycle webhook carries it only when the gateway can unambiguously associate that event with this command; the field is correlation, not proof of causation. When omitted, the gateway mints one. Not an idempotency key — request deduplication is the `Idempotency-Key` header. Invalid input (not a v4 UUID) is rejected with `400 invalid_request`.

## Response

### 202

Command accepted for async execution

- `operation_uuid` (string, required)
- `status` (enum, required)
  - Allowed values: `in_progress`, `completed`
- `already_ended` (true, optional) — Optional. Set to `true` on idempotent terminal commands when the session was already in a terminal state at the time the request was received. Absent otherwise.

## Examples

**Request**

```json
{
  "sequence": [
    {
      "digit": "1",
      "duration_ms": 250,
      "type": "key"
    },
    {
      "duration_ms": 1375,
      "type": "wait"
    },
    {
      "digit": "#",
      "duration_ms": 400,
      "type": "key"
    }
  ]
}
```

**Response**

```json
{
  "operation_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "in_progress"
}
```

**SDK Code**

```python Keypad Input_sendDTMFDigits_example
import requests

url = "https://api.telekesher.dev/v1/sessions/uuid/dtmf/send"

payload = { "sequence": [
        {
            "digit": "1",
            "duration_ms": 250,
            "type": "key"
        },
        {
            "duration_ms": 1375,
            "type": "wait"
        },
        {
            "digit": "#",
            "duration_ms": 400,
            "type": "key"
        }
    ] }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Keypad Input_sendDTMFDigits_example
const url = 'https://api.telekesher.dev/v1/sessions/uuid/dtmf/send';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"sequence":[{"digit":"1","duration_ms":250,"type":"key"},{"duration_ms":1375,"type":"wait"},{"digit":"#","duration_ms":400,"type":"key"}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Keypad Input_sendDTMFDigits_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.telekesher.dev/v1/sessions/uuid/dtmf/send"

	payload := strings.NewReader("{\n  \"sequence\": [\n    {\n      \"digit\": \"1\",\n      \"duration_ms\": 250,\n      \"type\": \"key\"\n    },\n    {\n      \"duration_ms\": 1375,\n      \"type\": \"wait\"\n    },\n    {\n      \"digit\": \"#\",\n      \"duration_ms\": 400,\n      \"type\": \"key\"\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Keypad Input_sendDTMFDigits_example
require 'uri'
require 'net/http'

url = URI("https://api.telekesher.dev/v1/sessions/uuid/dtmf/send")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"sequence\": [\n    {\n      \"digit\": \"1\",\n      \"duration_ms\": 250,\n      \"type\": \"key\"\n    },\n    {\n      \"duration_ms\": 1375,\n      \"type\": \"wait\"\n    },\n    {\n      \"digit\": \"#\",\n      \"duration_ms\": 400,\n      \"type\": \"key\"\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Keypad Input_sendDTMFDigits_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.telekesher.dev/v1/sessions/uuid/dtmf/send")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"sequence\": [\n    {\n      \"digit\": \"1\",\n      \"duration_ms\": 250,\n      \"type\": \"key\"\n    },\n    {\n      \"duration_ms\": 1375,\n      \"type\": \"wait\"\n    },\n    {\n      \"digit\": \"#\",\n      \"duration_ms\": 400,\n      \"type\": \"key\"\n    }\n  ]\n}")
  .asString();
```

```php Keypad Input_sendDTMFDigits_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.telekesher.dev/v1/sessions/uuid/dtmf/send', [
  'body' => '{
  "sequence": [
    {
      "digit": "1",
      "duration_ms": 250,
      "type": "key"
    },
    {
      "duration_ms": 1375,
      "type": "wait"
    },
    {
      "digit": "#",
      "duration_ms": 400,
      "type": "key"
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Keypad Input_sendDTMFDigits_example
using RestSharp;

var client = new RestClient("https://api.telekesher.dev/v1/sessions/uuid/dtmf/send");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"sequence\": [\n    {\n      \"digit\": \"1\",\n      \"duration_ms\": 250,\n      \"type\": \"key\"\n    },\n    {\n      \"duration_ms\": 1375,\n      \"type\": \"wait\"\n    },\n    {\n      \"digit\": \"#\",\n      \"duration_ms\": 400,\n      \"type\": \"key\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Keypad Input_sendDTMFDigits_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["sequence": [
    [
      "digit": "1",
      "duration_ms": 250,
      "type": "key"
    ],
    [
      "duration_ms": 1375,
      "type": "wait"
    ],
    [
      "digit": "#",
      "duration_ms": 400,
      "type": "key"
    ]
  ]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.telekesher.dev/v1/sessions/uuid/dtmf/send")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```