curl --request POST \
--url https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"label": "US Marketing STOP/HELP",
"stop_keywords": [
"STOP",
"STOPALL",
"UNSUBSCRIBE"
],
"help_keywords": [
"HELP",
"INFO"
],
"start_keywords": [
"START",
"UNSTOP"
],
"stop_response": "You have been unsubscribed. Reply START to rejoin.",
"help_response": "Devotel: reply STOP to opt out. Support: support@example.com",
"start_response": "You are re-subscribed. Reply STOP anytime to leave.",
"default_lang": "en",
"brand": "acme"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists"
payload = {
"label": "US Marketing STOP/HELP",
"stop_keywords": ["STOP", "STOPALL", "UNSUBSCRIBE"],
"help_keywords": ["HELP", "INFO"],
"start_keywords": ["START", "UNSTOP"],
"stop_response": "You have been unsubscribed. Reply START to rejoin.",
"help_response": "Devotel: reply STOP to opt out. Support: support@example.com",
"start_response": "You are re-subscribed. Reply STOP anytime to leave.",
"default_lang": "en",
"brand": "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({
label: 'US Marketing STOP/HELP',
stop_keywords: ['STOP', 'STOPALL', 'UNSUBSCRIBE'],
help_keywords: ['HELP', 'INFO'],
start_keywords: ['START', 'UNSTOP'],
stop_response: 'You have been unsubscribed. Reply START to rejoin.',
help_response: 'Devotel: reply STOP to opt out. Support: support@example.com',
start_response: 'You are re-subscribed. Reply STOP anytime to leave.',
default_lang: 'en',
brand: 'acme'
})
};
fetch('https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists', 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/messaging/opt-out-lists",
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([
'label' => 'US Marketing STOP/HELP',
'stop_keywords' => [
'STOP',
'STOPALL',
'UNSUBSCRIBE'
],
'help_keywords' => [
'HELP',
'INFO'
],
'start_keywords' => [
'START',
'UNSTOP'
],
'stop_response' => 'You have been unsubscribed. Reply START to rejoin.',
'help_response' => 'Devotel: reply STOP to opt out. Support: support@example.com',
'start_response' => 'You are re-subscribed. Reply STOP anytime to leave.',
'default_lang' => 'en',
'brand' => '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/messaging/opt-out-lists"
payload := strings.NewReader("{\n \"label\": \"US Marketing STOP/HELP\",\n \"stop_keywords\": [\n \"STOP\",\n \"STOPALL\",\n \"UNSUBSCRIBE\"\n ],\n \"help_keywords\": [\n \"HELP\",\n \"INFO\"\n ],\n \"start_keywords\": [\n \"START\",\n \"UNSTOP\"\n ],\n \"stop_response\": \"You have been unsubscribed. Reply START to rejoin.\",\n \"help_response\": \"Devotel: reply STOP to opt out. Support: support@example.com\",\n \"start_response\": \"You are re-subscribed. Reply STOP anytime to leave.\",\n \"default_lang\": \"en\",\n \"brand\": \"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/messaging/opt-out-lists")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"US Marketing STOP/HELP\",\n \"stop_keywords\": [\n \"STOP\",\n \"STOPALL\",\n \"UNSUBSCRIBE\"\n ],\n \"help_keywords\": [\n \"HELP\",\n \"INFO\"\n ],\n \"start_keywords\": [\n \"START\",\n \"UNSTOP\"\n ],\n \"stop_response\": \"You have been unsubscribed. Reply START to rejoin.\",\n \"help_response\": \"Devotel: reply STOP to opt out. Support: support@example.com\",\n \"start_response\": \"You are re-subscribed. Reply STOP anytime to leave.\",\n \"default_lang\": \"en\",\n \"brand\": \"acme\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists")
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 \"label\": \"US Marketing STOP/HELP\",\n \"stop_keywords\": [\n \"STOP\",\n \"STOPALL\",\n \"UNSUBSCRIBE\"\n ],\n \"help_keywords\": [\n \"HELP\",\n \"INFO\"\n ],\n \"start_keywords\": [\n \"START\",\n \"UNSTOP\"\n ],\n \"stop_response\": \"You have been unsubscribed. Reply START to rejoin.\",\n \"help_response\": \"Devotel: reply STOP to opt out. Support: support@example.com\",\n \"start_response\": \"You are re-subscribed. Reply STOP anytime to leave.\",\n \"default_lang\": \"en\",\n \"brand\": \"acme\"\n}"
response = http.request(request)
puts response.read_body{}{
"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>"
}
}Create opt-out list
Create an opt-out list — a named bundle of custom STOP / HELP / START keywords plus the auto-reply copy each event answers with — that a messaging service references through opt_out_list_id. The keyword matcher merges these arrays additively into the platform-default, carrier-mandated sets, so lists can only widen the trigger surface, never narrow it (TCPA / CTIA require STOP to stay). Each keyword array is capped at 32 entries of up to 64 chars and each response at 1600 chars; set default_lang (en, tr, de, es, fr, pt, it, ar, nl) and an optional brand tag. Owner / admin only; a duplicate active label returns 409. The returned id is what you store on a messaging service.
curl --request POST \
--url https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"label": "US Marketing STOP/HELP",
"stop_keywords": [
"STOP",
"STOPALL",
"UNSUBSCRIBE"
],
"help_keywords": [
"HELP",
"INFO"
],
"start_keywords": [
"START",
"UNSTOP"
],
"stop_response": "You have been unsubscribed. Reply START to rejoin.",
"help_response": "Devotel: reply STOP to opt out. Support: support@example.com",
"start_response": "You are re-subscribed. Reply STOP anytime to leave.",
"default_lang": "en",
"brand": "acme"
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists"
payload = {
"label": "US Marketing STOP/HELP",
"stop_keywords": ["STOP", "STOPALL", "UNSUBSCRIBE"],
"help_keywords": ["HELP", "INFO"],
"start_keywords": ["START", "UNSTOP"],
"stop_response": "You have been unsubscribed. Reply START to rejoin.",
"help_response": "Devotel: reply STOP to opt out. Support: support@example.com",
"start_response": "You are re-subscribed. Reply STOP anytime to leave.",
"default_lang": "en",
"brand": "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({
label: 'US Marketing STOP/HELP',
stop_keywords: ['STOP', 'STOPALL', 'UNSUBSCRIBE'],
help_keywords: ['HELP', 'INFO'],
start_keywords: ['START', 'UNSTOP'],
stop_response: 'You have been unsubscribed. Reply START to rejoin.',
help_response: 'Devotel: reply STOP to opt out. Support: support@example.com',
start_response: 'You are re-subscribed. Reply STOP anytime to leave.',
default_lang: 'en',
brand: 'acme'
})
};
fetch('https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists', 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/messaging/opt-out-lists",
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([
'label' => 'US Marketing STOP/HELP',
'stop_keywords' => [
'STOP',
'STOPALL',
'UNSUBSCRIBE'
],
'help_keywords' => [
'HELP',
'INFO'
],
'start_keywords' => [
'START',
'UNSTOP'
],
'stop_response' => 'You have been unsubscribed. Reply START to rejoin.',
'help_response' => 'Devotel: reply STOP to opt out. Support: support@example.com',
'start_response' => 'You are re-subscribed. Reply STOP anytime to leave.',
'default_lang' => 'en',
'brand' => '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/messaging/opt-out-lists"
payload := strings.NewReader("{\n \"label\": \"US Marketing STOP/HELP\",\n \"stop_keywords\": [\n \"STOP\",\n \"STOPALL\",\n \"UNSUBSCRIBE\"\n ],\n \"help_keywords\": [\n \"HELP\",\n \"INFO\"\n ],\n \"start_keywords\": [\n \"START\",\n \"UNSTOP\"\n ],\n \"stop_response\": \"You have been unsubscribed. Reply START to rejoin.\",\n \"help_response\": \"Devotel: reply STOP to opt out. Support: support@example.com\",\n \"start_response\": \"You are re-subscribed. Reply STOP anytime to leave.\",\n \"default_lang\": \"en\",\n \"brand\": \"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/messaging/opt-out-lists")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"US Marketing STOP/HELP\",\n \"stop_keywords\": [\n \"STOP\",\n \"STOPALL\",\n \"UNSUBSCRIBE\"\n ],\n \"help_keywords\": [\n \"HELP\",\n \"INFO\"\n ],\n \"start_keywords\": [\n \"START\",\n \"UNSTOP\"\n ],\n \"stop_response\": \"You have been unsubscribed. Reply START to rejoin.\",\n \"help_response\": \"Devotel: reply STOP to opt out. Support: support@example.com\",\n \"start_response\": \"You are re-subscribed. Reply STOP anytime to leave.\",\n \"default_lang\": \"en\",\n \"brand\": \"acme\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/messaging/opt-out-lists")
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 \"label\": \"US Marketing STOP/HELP\",\n \"stop_keywords\": [\n \"STOP\",\n \"STOPALL\",\n \"UNSUBSCRIBE\"\n ],\n \"help_keywords\": [\n \"HELP\",\n \"INFO\"\n ],\n \"start_keywords\": [\n \"START\",\n \"UNSTOP\"\n ],\n \"stop_response\": \"You have been unsubscribed. Reply START to rejoin.\",\n \"help_response\": \"Devotel: reply STOP to opt out. Support: support@example.com\",\n \"start_response\": \"You are re-subscribed. Reply STOP anytime to leave.\",\n \"default_lang\": \"en\",\n \"brand\": \"acme\"\n}"
response = http.request(request)
puts response.read_body{}{
"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. 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
Display name for the list (1–200 chars, required; unique among active lists).
Extra keywords that trigger an opt-out (0–32 entries, 1–64 chars each).
Extra keywords that trigger a help response.
Extra keywords that opt a contact back in.
Auto-reply copy sent when STOP matches (up to 1600 chars / 10 SMS segments).
Auto-reply copy sent when HELP matches.
Auto-reply copy sent when START matches.
Default response language for keyword matching.
en, tr, de, es, fr, pt, it, ar, nl Optional brand tag (1–64 chars) stamped into the default response copy.
Response
The created opt-out list (with its assigned id and timestamps) wrapped in the standard { data, meta } envelope. Returns 409 when the label is already used by an active list and 422 when the body is invalid.
The created opt-out list (with its assigned id and timestamps) wrapped in the standard { data, meta } envelope. Returns 409 when the label is already used by an active list and 422 when the body is invalid.