curl --request GET \
--url https://api.orbit.devotel.io/api/v1/messages \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.orbit.devotel.io/api/v1/messages"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.orbit.devotel.io/api/v1/messages', 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/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/messages"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.orbit.devotel.io/api/v1/messages")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "<string>",
"channel": "<string>",
"direction": "<string>",
"from": "<string>",
"to": "<string>",
"body": "<string>",
"media_url": "<string>",
"status": "<string>",
"segments": 123,
"price": "<string>",
"currency": "<string>",
"provider": "<string>",
"external_id": "<string>",
"error_code": "<string>",
"error_message": "<string>",
"contact_id": "<string>",
"metadata": {},
"mccmnc": "<string>",
"sent_at": "2023-11-07T05:31:56Z",
"delivered_at": "2023-11-07T05:31:56Z",
"read_at": "2023-11-07T05:31:56Z",
"failed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}
],
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"pagination": {
"cursor": "<string>",
"has_more": true,
"total": 123
}
}
}{
"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>"
}
}List messages
Retrieve messages with cursor-based pagination and optional channel/status filters.
curl --request GET \
--url https://api.orbit.devotel.io/api/v1/messages \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.orbit.devotel.io/api/v1/messages"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.orbit.devotel.io/api/v1/messages', 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/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/messages"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.orbit.devotel.io/api/v1/messages")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "<string>",
"channel": "<string>",
"direction": "<string>",
"from": "<string>",
"to": "<string>",
"body": "<string>",
"media_url": "<string>",
"status": "<string>",
"segments": 123,
"price": "<string>",
"currency": "<string>",
"provider": "<string>",
"external_id": "<string>",
"error_code": "<string>",
"error_message": "<string>",
"contact_id": "<string>",
"metadata": {},
"mccmnc": "<string>",
"sent_at": "2023-11-07T05:31:56Z",
"delivered_at": "2023-11-07T05:31:56Z",
"read_at": "2023-11-07T05:31:56Z",
"failed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}
],
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"pagination": {
"cursor": "<string>",
"has_more": true,
"total": 123
}
}
}{
"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
Sandbox 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 Query Parameters
Opaque cursor for the next page (from previous response meta.pagination.cursor)
Number of items per page (default 25). Values above the page-size cap are silently clamped; negative, fractional, or unparseable values fall back to the default. Never 422s.
x >= 1Filter by channel
32Filter by delivery status. Accepts every status the messages.status column can hold across all channels — DAG states (pending/queued/scheduled/accepted/sending/sent), terminal successes (delivered/submitted_no_receipt/read), failure modes (failed/rejected/undelivered/bounced/expired), and operational sentinels (suppressed/test_sent/deleted/unknown). Email spam complaints are not a distinct status — a complaint DLR is recorded as status=failed with metadata.complaint_type set to "spam_report". To isolate complaint-driven failures, filter on status=failed and inspect metadata.complaint_type. An empty or unknown value clears the filter.
36Filter by recipient
100Filter by direction. Accepted values: inbound, outbound, internal. An empty or unknown value clears the filter.
32Filter by contact
100Date range filter (e.g. 7d, 30d, 90d)
10Custom date range start. Accepts an ISO-8601 date (2026-05-25) or date-time (2026-05-25T00:00:00Z); any unparseable value is ignored (no date filter applied) rather than rejected.
40Custom date range end. Accepts an ISO-8601 date (2026-05-25) or date-time (2026-05-25T23:59:59Z); any unparseable value is ignored (no date filter applied) rather than rejected.
40Filter by conversation
100Free-text inbox search across message content and participant addresses.
200Comma-separated list of message ids to look up directly (correlated cross-channel delivery log search). Each id is OR-matched against the internal id OR the provider-assigned external_id. Combine with the standard channel/from_date/to_date filters to narrow further.
4096Scope results to a single WhatsApp WABA by its phone_number_id (multi-WABA inbox filter).
64Group results. Accepted values: conversation, contact, channel. An empty or unknown value clears the grouping.
32