curl -X POST https://tawked.com/v1/verify/start \
-H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"to": "0551234567",
"channel": "sms",
"lang": "ar"
}'const res = await fetch("https://tawked.com/v1/verify/start", {
method: "POST",
headers: {
Authorization: "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ to: "0551234567", channel: "sms", lang: "ar" }),
});
const data = await res.json();<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://tawked.com/v1/verify/start",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '<string>',
'phone' => '<string>',
'channel' => '<string>',
'lang' => '<string>',
'application' => '<string>',
'reference' => '<string>',
'client_ip' => '<string>',
'autofill' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}import requests
res = requests.post(
"https://tawked.com/v1/verify/start",
headers={"Authorization": "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx"},
json={"to": "0551234567", "channel": "sms", "lang": "ar"},
)
data = res.json(){
"id": "b7e5c2b0-9c1a-4e2f-8f2a-3a6b0e9d1c44",
"status": "pending",
"expires_at": "2026-09-01T12:34:56.789Z"
}{
"error": "service_required"
}{
"error": "unauthorized"
}{
"error": "insufficient_credits"
}{
"error": "account_not_active"
}{
"error": "service_not_found"
}{
"error": "unsupported_channel"
}{
"error": "too_many_requests"
}{
"error": "internal_error"
}{
"error": "send_failed"
}Start a verification
Sends a one-time code to a destination and returns an id to check it against.
curl -X POST https://tawked.com/v1/verify/start \
-H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"to": "0551234567",
"channel": "sms",
"lang": "ar"
}'const res = await fetch("https://tawked.com/v1/verify/start", {
method: "POST",
headers: {
Authorization: "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ to: "0551234567", channel: "sms", lang: "ar" }),
});
const data = await res.json();<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://tawked.com/v1/verify/start",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '<string>',
'phone' => '<string>',
'channel' => '<string>',
'lang' => '<string>',
'application' => '<string>',
'reference' => '<string>',
'client_ip' => '<string>',
'autofill' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}import requests
res = requests.post(
"https://tawked.com/v1/verify/start",
headers={"Authorization": "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx"},
json={"to": "0551234567", "channel": "sms", "lang": "ar"},
)
data = res.json(){
"id": "b7e5c2b0-9c1a-4e2f-8f2a-3a6b0e9d1c44",
"status": "pending",
"expires_at": "2026-09-01T12:34:56.789Z"
}{
"error": "service_required"
}{
"error": "unauthorized"
}{
"error": "insufficient_credits"
}{
"error": "account_not_active"
}{
"error": "service_not_found"
}{
"error": "unsupported_channel"
}{
"error": "too_many_requests"
}{
"error": "internal_error"
}{
"error": "send_failed"
}Authorizations
Authorization: Bearer . An application key (tk_live_, tk_test_) has full access, which covers every product and any product added later, or custom access, chosen when the key is created: one or more of the scopes verify:check, verify:send (includes verify:check), notifications:read, notifications:send (includes notifications:read), email:read, email:send (includes email:read), email:manage (includes email:send), webhooks:manage, email:inbound, notifications:templates (includes notifications:read), chat:menus, chat:attendant. No key made on the API keys page holds notifications:templates, full access included: the three template writes answer such a key 403 insufficient_scope. A connected app's key holds it. Nor chat:menus: the five conversation menu operations answer such a key 403 insufficient_scope, and a connected app's key holds it once the client approved it. Nor chat:attendant: the five auto-attendant operations answer such a key 403 insufficient_scope too, and a connected app's key holds it once the client approved it. email:manage and webhooks:manage are held only by a key someone chose them for: a full-access key, old or new, never holds them. email:inbound, which reads, deletes and forwards received e-mail, is opt-in on every key, full access included: a key holds it only when it was turned on when the key was created. A call outside the key's access answers 403 insufficient_scope and names the scope it needs in the WWW-Authenticate response header. A partner key (tk_partner_) always has full access. Whatever its access, a key is a server-side secret.
Headers
A 1–128 printable-ASCII-character key you generate, scoped to your API key (and, for a partner key, to the named application too). Replaying the same key returns the original 201 response unchanged, with the response header Idempotent-Replayed: true, and nothing is sent or charged again. A send that fails releases the key so a retry can go through.
Body
The destination. Any of the accepted Saudi mobile formats below.
Deprecated alias for to, kept for pre-multichannel integrations. Only used when to is absent or blank; to always wins when both are present. New integrations should use to.
Delivery channel. Defaults to "sms" when absent or blank. "whatsapp" answers unsupported_channel until Tawked opens WhatsApp for codes to every account.
Message language. Only the literal value "en" selects English; anything else (including missing) defaults to Arabic.
Partner keys only: which of your provisioned applications is sending. The legacy field name service is accepted identically.
Your own reference (order id, request id, …), up to 64 printable characters. Echoed back on start and on GET /v1/verify/{id}, and searchable in the dashboard's verifications list.
The end user's IP address. Enables the per-IP protection guard for this application when one is configured. Never inferred from the request, always explicit.
web, android or none: which autofill line(s) to include on this send. web sends only the @domain #code line, android only the app-hash line, none sends neither. Omit it to send every line the application has configured.