> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.getdial.ai/api-reference/rest-api/messages/send-typing/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server. # Set a typing indicator POST https://api.getdial.ai/api/v1/typing Content-Type: application/json Starts or stops a typing indicator shown to the recipient, as if someone were composing a message from your number. **iMessage numbers show it; standard (SMS) numbers ignore it.** SMS has no typing concept, so for a standard from-number the request succeeds and does nothing — the response is identical either way, letting you call this unconditionally before a send. **Groups.** Address a group with `groupId` instead of `toNumber`, exactly as on Send a message — every member of the group sees the indicator. It works on WhatsApp and iMessage groups alike; the group ID is channel-neutral, so the same field addresses either. The indicator is fire-and-forget: nothing is persisted and no event is emitted. Delivering a message or reaction from the same number **clears the indicator natively** on the recipient's device — platform behavior, not Dial's; start again after a send if you're still composing. Dial itself never clears it: send `value: false` when you stop composing without sending. (A stale indicator may also clear on its own device-side.) Free of charge. Reference: https://docs.getdial.ai/api-reference/rest-api/messages/send-typing ## Authentication - `Authorization` header (bearer token, required) — Your Dial API key, sent as `Authorization: Bearer sk_live_...` ## Request ### Body (application/json) This endpoint expects an object. - `value` (boolean, required) — `true` shows the typing indicator; `false` clears it. - `toNumber` (string, optional) — Recipient phone number in E.164 format. Provide exactly one of `toNumber` or `groupId`. - `groupId` (string, optional) — ID of a group conversation on your account (see List groups), instead of a `toNumber`. The line the indicator appears from comes from the group. Provide exactly one of `toNumber` or `groupId`. - `fromNumber` (string, optional) — The Dial number the indicator appears from, referenced flexibly: a phone-number ID, one of your numbers in E.164 format, or a number's nickname. A nickname shared by more than one of your numbers is rejected with `400`; a ref that matches none of your numbers returns `404`. **Required with `toNumber`, optional with `groupId`** — the group already belongs to one of your lines and Dial uses that one. Supplying it anyway is allowed and must agree: a from-number naming a different line is rejected with `400` rather than silently overridden. - `channel` (enum, optional) — Which rail to show the indicator on, for a line that carries more than one. Mirrors `channel` on Send a message: omit to use the number's own default. `whatsapp` requires a line whose WhatsApp channel is `ready`, and returns `503` when the channel can't be driven right now (rather than reporting a "typing…" that never appeared). `imessage` on a number with no iMessage rail is rejected with `400`. Omit `channel` on a `groupId` request: a group belongs to exactly one channel, so the group already names the rail, and a `channel` naming a different one is rejected with `400`. - Allowed values: `imessage`, `whatsapp` ## Response ### 200 Indicator set (or silently ignored for a from-number without typing support). - `ok` (boolean, optional) ## Errors ### 400 Bad Request Error The request body failed validation. - `error` (ErrorError, optional) — An error message, or a validation-error object for 400 responses. ### 401 Unauthorized Error Missing or invalid API key. - `error` (ErrorError, optional) — An error message, or a validation-error object for 400 responses. ### 403 Forbidden Error WhatsApp has limited this number's access, so it can't start a new conversation with this recipient yet. Nothing was sent. Replies to people who have messaged the number still go through, and retrying right away fails the same way. (error code `whatsapp_limited`.) - `error` (ErrorError, optional) — An error message, or a validation-error object for 400 responses. ### 404 Not Found Error The requested resource was not found on this account. - `error` (ErrorError, optional) — An error message, or a validation-error object for 400 responses. ### 503 Service Unavailable Error `channel: "whatsapp"` only — the WhatsApp channel could not be driven for this line right now. Retry. - `any` ## Types ### ErrorError An error message, or a validation-error object for 400 responses. ## Examples **Request** ```json { "value": true } ``` **Response** ```json { "ok": true } ``` **SDK Code** ```python import requests url = "https://api.getdial.ai/api/v1/typing" payload = { "value": True } headers = { "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.getdial.ai/api/v1/typing'; const options = { method: 'POST', headers: {Authorization: 'Bearer ', 'Content-Type': 'application/json'}, body: '{"value":true}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.getdial.ai/api/v1/typing" payload := strings.NewReader("{\n \"value\": true\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Authorization", "Bearer ") 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 require 'uri' require 'net/http' url = URI("https://api.getdial.ai/api/v1/typing") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["Authorization"] = 'Bearer ' request["Content-Type"] = 'application/json' request.body = "{\n \"value\": true\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.getdial.ai/api/v1/typing") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"value\": true\n}") .asString(); ``` ```php request('POST', 'https://api.getdial.ai/api/v1/typing', [ 'body' => '{ "value": true }', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.getdial.ai/api/v1/typing"); var request = new RestRequest(Method.POST); request.AddHeader("Authorization", "Bearer "); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"value\": true\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "Authorization": "Bearer ", "Content-Type": "application/json" ] let parameters = ["value": true] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.getdial.ai/api/v1/typing")! 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() ```