curl --request POST \
--url https://api.orbit.devotel.io/api/v1/verify/send \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "<string>",
"channels": [],
"fallback_config": {
"channel_timeout_seconds": 60,
"max_attempts_per_channel": 1
},
"max_attempts": 3,
"profile_id": "<string>",
"country": "<string>",
"code_length": 6,
"custom_code": "<string>",
"device_token": "<string>"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/verify/send"
payload = {
"to": "<string>",
"channels": [],
"fallback_config": {
"channel_timeout_seconds": 60,
"max_attempts_per_channel": 1
},
"max_attempts": 3,
"profile_id": "<string>",
"country": "<string>",
"code_length": 6,
"custom_code": "<string>",
"device_token": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '<string>',
channels: [],
fallback_config: {channel_timeout_seconds: 60, max_attempts_per_channel: 1},
max_attempts: 3,
profile_id: '<string>',
country: '<string>',
code_length: 6,
custom_code: '<string>',
device_token: '<string>'
})
};
fetch('https://api.orbit.devotel.io/api/v1/verify/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orbit.devotel.io/api/v1/verify/send",
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>',
'channels' => [
],
'fallback_config' => [
'channel_timeout_seconds' => 60,
'max_attempts_per_channel' => 1
],
'max_attempts' => 3,
'profile_id' => '<string>',
'country' => '<string>',
'code_length' => 6,
'custom_code' => '<string>',
'device_token' => '<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;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/verify/send"
payload := strings.NewReader("{\n \"to\": \"<string>\",\n \"channels\": [],\n \"fallback_config\": {\n \"channel_timeout_seconds\": 60,\n \"max_attempts_per_channel\": 1\n },\n \"max_attempts\": 3,\n \"profile_id\": \"<string>\",\n \"country\": \"<string>\",\n \"code_length\": 6,\n \"custom_code\": \"<string>\",\n \"device_token\": \"<string>\"\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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.orbit.devotel.io/api/v1/verify/send")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"<string>\",\n \"channels\": [],\n \"fallback_config\": {\n \"channel_timeout_seconds\": 60,\n \"max_attempts_per_channel\": 1\n },\n \"max_attempts\": 3,\n \"profile_id\": \"<string>\",\n \"country\": \"<string>\",\n \"code_length\": 6,\n \"custom_code\": \"<string>\",\n \"device_token\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/verify/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 \"to\": \"<string>\",\n \"channels\": [],\n \"fallback_config\": {\n \"channel_timeout_seconds\": 60,\n \"max_attempts_per_channel\": 1\n },\n \"max_attempts\": 3,\n \"profile_id\": \"<string>\",\n \"country\": \"<string>\",\n \"code_length\": 6,\n \"custom_code\": \"<string>\",\n \"device_token\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"verification_id": "<string>",
"status": "pending",
"channel": "<string>",
"expires_at": "2023-11-07T05:31:56Z"
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}Send a verification code
Generate and deliver a one-time verification code via the specified channel.
curl --request POST \
--url https://api.orbit.devotel.io/api/v1/verify/send \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "<string>",
"channels": [],
"fallback_config": {
"channel_timeout_seconds": 60,
"max_attempts_per_channel": 1
},
"max_attempts": 3,
"profile_id": "<string>",
"country": "<string>",
"code_length": 6,
"custom_code": "<string>",
"device_token": "<string>"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/verify/send"
payload = {
"to": "<string>",
"channels": [],
"fallback_config": {
"channel_timeout_seconds": 60,
"max_attempts_per_channel": 1
},
"max_attempts": 3,
"profile_id": "<string>",
"country": "<string>",
"code_length": 6,
"custom_code": "<string>",
"device_token": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '<string>',
channels: [],
fallback_config: {channel_timeout_seconds: 60, max_attempts_per_channel: 1},
max_attempts: 3,
profile_id: '<string>',
country: '<string>',
code_length: 6,
custom_code: '<string>',
device_token: '<string>'
})
};
fetch('https://api.orbit.devotel.io/api/v1/verify/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orbit.devotel.io/api/v1/verify/send",
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>',
'channels' => [
],
'fallback_config' => [
'channel_timeout_seconds' => 60,
'max_attempts_per_channel' => 1
],
'max_attempts' => 3,
'profile_id' => '<string>',
'country' => '<string>',
'code_length' => 6,
'custom_code' => '<string>',
'device_token' => '<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;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/verify/send"
payload := strings.NewReader("{\n \"to\": \"<string>\",\n \"channels\": [],\n \"fallback_config\": {\n \"channel_timeout_seconds\": 60,\n \"max_attempts_per_channel\": 1\n },\n \"max_attempts\": 3,\n \"profile_id\": \"<string>\",\n \"country\": \"<string>\",\n \"code_length\": 6,\n \"custom_code\": \"<string>\",\n \"device_token\": \"<string>\"\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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.orbit.devotel.io/api/v1/verify/send")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"<string>\",\n \"channels\": [],\n \"fallback_config\": {\n \"channel_timeout_seconds\": 60,\n \"max_attempts_per_channel\": 1\n },\n \"max_attempts\": 3,\n \"profile_id\": \"<string>\",\n \"country\": \"<string>\",\n \"code_length\": 6,\n \"custom_code\": \"<string>\",\n \"device_token\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/verify/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 \"to\": \"<string>\",\n \"channels\": [],\n \"fallback_config\": {\n \"channel_timeout_seconds\": 60,\n \"max_attempts_per_channel\": 1\n },\n \"max_attempts\": 3,\n \"profile_id\": \"<string>\",\n \"country\": \"<string>\",\n \"code_length\": 6,\n \"custom_code\": \"<string>\",\n \"device_token\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"verification_id": "<string>",
"status": "pending",
"channel": "<string>",
"expires_at": "2023-11-07T05:31:56Z"
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}Authorizations
Dashboard JWT token from Clerk
Headers
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the Idempotency-Replay: true response header.
1 - 255Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
true, false Body
Recipient (E.164 phone or email)
Delivery channel for the OTP (defaults to sms)
sms, whatsapp, email, viber, voice, telegram, silent, rcs, flashcall, sna, totp, push, magic_link, backup_code Optional ad-hoc fallback channel chain (overlays the send when no profile_id is set)
1 - 4 elementssms, whatsapp, email, voice, viber, telegram, silent, rcs Optional async fallback engine config (pairs with channels)
Show child attributes
Show child attributes
Max verification attempts
1 <= x <= 10Optional verification profile ID. Format is vprof_<hex> (per generateId("vprof")); NOT a bare UUID — the prior format: uuid constraint here was the root cause of DEVOTEL-ORBIT-28 (27 events in 11 days) where every FE call with a real profile id 422'd before reaching the Zod parse.
1 - 64Optional ISO 3166-1 alpha-2 country hint (e.g. TR) so national-format phone numbers normalise to the E.164 form OTP providers require. Not needed for clean E.164 input.
2Number of digits in the generated OTP (defaults to 6). Must equal custom_code length when a custom code is supplied.
4 <= x <= 8Optional PSD2 SCA dynamic-linking binding. Replay the SAME object on POST /verify/check; a mismatch rejects with BINDING_MISMATCH. Omit for non-PSD2 flows.
Show child attributes
Show child attributes
Optional 2-letter language code selecting the localized voice TTS and SMS body for the built-in fallback message. Profile-defined templates override it. Region tags (e.g. es-MX) are rejected — use es.
en, es, fr, de, it, pt, nl, tr, ar, ja, zh, ko, ru, pl, sv, da, nb, fi, cs, el, he, hi, id, th, vi Optional caller-supplied OTP (4–8 digits, digits only) for sandbox / test-mode QA. Rejected on live keys. Its length must equal code_length.
^\d{4,8}$Device-bound network access token for the sna channel (Silent Network Authentication), obtained via the GSMA Open Gateway / CAMARA flow. When present on an sna send, verification completes via a network possession-proof and no OTP is minted.
1