curl --request POST \
--url https://api.orbit.devotel.io/api/v1/numbers/tfv-lint \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sample_messages": [
"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.",
"Acme: reply HELP for help or STOP to opt out."
],
"use_case": "Customer Care",
"business_name": "Acme"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/numbers/tfv-lint"
payload = {
"sample_messages": ["Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.", "Acme: reply HELP for help or STOP to opt out."],
"use_case": "Customer Care",
"business_name": "Acme"
}
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({
sample_messages: [
'Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.',
'Acme: reply HELP for help or STOP to opt out.'
],
use_case: 'Customer Care',
business_name: 'Acme'
})
};
fetch('https://api.orbit.devotel.io/api/v1/numbers/tfv-lint', 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/numbers/tfv-lint",
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([
'sample_messages' => [
'Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.',
'Acme: reply HELP for help or STOP to opt out.'
],
'use_case' => 'Customer Care',
'business_name' => 'Acme'
]),
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/numbers/tfv-lint"
payload := strings.NewReader("{\n \"sample_messages\": [\n \"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.\",\n \"Acme: reply HELP for help or STOP to opt out.\"\n ],\n \"use_case\": \"Customer Care\",\n \"business_name\": \"Acme\"\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/numbers/tfv-lint")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sample_messages\": [\n \"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.\",\n \"Acme: reply HELP for help or STOP to opt out.\"\n ],\n \"use_case\": \"Customer Care\",\n \"business_name\": \"Acme\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/numbers/tfv-lint")
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 \"sample_messages\": [\n \"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.\",\n \"Acme: reply HELP for help or STOP to opt out.\"\n ],\n \"use_case\": \"Customer Care\",\n \"business_name\": \"Acme\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"ok": false,
"findings": [
{
"severity": "error",
"category": "missing_optout_keyword",
"sample_index": 0,
"evidence": "No STOP instruction found in this sample.",
"suggestion": "Add an opt-out instruction such as \"Reply STOP to unsubscribe.\" to every recurring-message sample."
},
{
"severity": "warn",
"category": "missing_brand_identifier",
"sample_index": 1,
"evidence": "Sample does not mention Acme.",
"suggestion": "Start the message with the brand name so recipients can identify the sender."
}
],
"summary": {
"error": 1,
"warn": 1,
"info": 0
}
},
"meta": {
"request_id": "req_01J9Z8ABCDEF",
"timestamp": "2026-08-20T09:00:00.000Z"
}
}{
"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": "RATE_LIMITED",
"message": "<string>",
"status": 429,
"retry_after": 2
},
"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>"
}
}Lint toll-free sample messages before TFV submission
Check draft toll-free sample messages against the carrier disallowed-vertical list (SHAFT, high-risk loans, gambling, cryptocurrency, debt collection, lead-gen, get-rich-quick, phishing) plus required opt-out and brand-identifier language, before you submit the Toll-Free Verification form. Use it to fix structural rejections up front instead of waiting days for the carrier review queue to bounce the submission and eat into the amend window. Returns findings with a severity (error blocks, warn / info advise), the offending sample index, matched evidence, and a remediation suggestion; ok is true only when there are zero errors. Pure content check — no DID is changed. Requires the numbers:read scope.
curl --request POST \
--url https://api.orbit.devotel.io/api/v1/numbers/tfv-lint \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sample_messages": [
"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.",
"Acme: reply HELP for help or STOP to opt out."
],
"use_case": "Customer Care",
"business_name": "Acme"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/numbers/tfv-lint"
payload = {
"sample_messages": ["Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.", "Acme: reply HELP for help or STOP to opt out."],
"use_case": "Customer Care",
"business_name": "Acme"
}
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({
sample_messages: [
'Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.',
'Acme: reply HELP for help or STOP to opt out.'
],
use_case: 'Customer Care',
business_name: 'Acme'
})
};
fetch('https://api.orbit.devotel.io/api/v1/numbers/tfv-lint', 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/numbers/tfv-lint",
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([
'sample_messages' => [
'Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.',
'Acme: reply HELP for help or STOP to opt out.'
],
'use_case' => 'Customer Care',
'business_name' => 'Acme'
]),
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/numbers/tfv-lint"
payload := strings.NewReader("{\n \"sample_messages\": [\n \"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.\",\n \"Acme: reply HELP for help or STOP to opt out.\"\n ],\n \"use_case\": \"Customer Care\",\n \"business_name\": \"Acme\"\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/numbers/tfv-lint")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sample_messages\": [\n \"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.\",\n \"Acme: reply HELP for help or STOP to opt out.\"\n ],\n \"use_case\": \"Customer Care\",\n \"business_name\": \"Acme\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/numbers/tfv-lint")
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 \"sample_messages\": [\n \"Acme: your appointment is confirmed for Tue 3pm. Reply STOP to unsubscribe.\",\n \"Acme: reply HELP for help or STOP to opt out.\"\n ],\n \"use_case\": \"Customer Care\",\n \"business_name\": \"Acme\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"ok": false,
"findings": [
{
"severity": "error",
"category": "missing_optout_keyword",
"sample_index": 0,
"evidence": "No STOP instruction found in this sample.",
"suggestion": "Add an opt-out instruction such as \"Reply STOP to unsubscribe.\" to every recurring-message sample."
},
{
"severity": "warn",
"category": "missing_brand_identifier",
"sample_index": 1,
"evidence": "Sample does not mention Acme.",
"suggestion": "Start the message with the brand name so recipients can identify the sender."
}
],
"summary": {
"error": 1,
"warn": 1,
"info": 0
}
},
"meta": {
"request_id": "req_01J9Z8ABCDEF",
"timestamp": "2026-08-20T09:00:00.000Z"
}
}{
"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": "RATE_LIMITED",
"message": "<string>",
"status": 429,
"retry_after": 2
},
"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 — see Test mode explained for the full credential-header matrix and worked samples. 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
The sample messages (and optional context) to lint.
The sample messages (and optional context) to lint.