SMS statistics
Copy page
Three endpoints cover reporting: totals, time series and country breakdown.
All require the sms.read permission and accept the same period filters.
Common parameters
Section titled “Common parameters”| Parameter | Default | Description |
|---|---|---|
period | 7d | today, yesterday, 7d, 30d, this_month, last_month |
from / to | — | Custom range YYYY-MM-DD. Use only when period is omitted; the to day is included |
source | api | api, broadcasts, all |
country | — | ISO code filter: US, GB, … |
sender | — | Filter by sender ID |
phone | — | Search by phone number (substring) |
status | — | delivered, undelivered, pending, expired |
Aggregate statistics
Section titled “Aggregate statistics” GET
/api/v1/sms/stats
· Permission: sms.read
curl "https://restlink23telecom.com/api/v1/sms/stats?period=30d" \ -H "X-API-Key: $API_KEY"const res = await fetch('https://restlink23telecom.com/api/v1/sms/stats?period=30d', { method: 'GET', headers: { 'X-API-Key': process.env.API_KEY },});
if (!res.ok) { const err = await res.json(); throw new Error(`${err.error_code}: ${err.description}`);}const data = await res.json();console.log(data);import osimport requests
res = requests.get( "https://restlink23telecom.com/api/v1/sms/stats", headers={"X-API-Key": os.environ["API_KEY"]}, params={ "period": "30d" },)res.raise_for_status()print(res.json())<?php$ch = curl_init('https://restlink23telecom.com/api/v1/sms/stats?period=30d');curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('API_KEY')],]);
$response = curl_exec($ch);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);
if ($status !== 200) { throw new Exception("HTTP $status: $response");}$data = json_decode($response, true);print_r($data);require "net/http"require "json"
uri = URI("https://restlink23telecom.com/api/v1/sms/stats?period=30d")req = Net::HTTP::Get.new(uri)req["X-API-Key"] = ENV.fetch("API_KEY")
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }raise "HTTP #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
puts JSON.parse(res.body)import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://restlink23telecom.com/api/v1/sms/stats?period=30d")) .header("X-API-Key", System.getenv("API_KEY")) .GET() .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());package main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("GET", "https://restlink23telecom.com/api/v1/sms/stats?period=30d", nil) if err != nil { panic(err) } req.Header.Set("X-API-Key", os.Getenv("API_KEY"))
res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close()
data, _ := io.ReadAll(res.Body) fmt.Println(string(data))}using System.Text;
using var client = new HttpClient();client.DefaultRequestHeaders.Add("X-API-Key", Environment.GetEnvironmentVariable("API_KEY"));
var response = await client.GetAsync("https://restlink23telecom.com/api/v1/sms/stats?period=30d");
response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());{ "status": true, "stats": { "total_sent": 1250, "sent": 1200, "delivered": 1150, "undelivered": 30, "pending": 15, "expired": 5, "not_billed": 50, "failed": 30, "click_count": 42, "unique_click_count": 38, "action_count": 12, "sent_rate": 96.00, "delivery_rate": 95.83, "total_cost": 10.63, "avg_cost_per_msg": 0.0085, "currency": "EUR" }, "period": {"from": "2026-01-14", "to": "2026-02-13"}}How the numbers relate:
Sent = Delivered + Undelivered + Pending + ExpiredTotalSent = Sent + NotBilled| Field | Description |
|---|---|
total_sent | All messages attempted |
sent | Accepted by carrier (total_sent − not_billed) |
delivered | Delivered to handset (DELIVRD) |
undelivered | Failed: UNDELIV, REJECTD, DELETED, UNKNOWN |
pending | Still in transit |
expired | Delivery timed out — counted separately from undelivered |
not_billed | Always 0 for API traffic; for broadcasts: messages never submitted to carrier |
failed | Alias of undelivered |
click_count / unique_click_count | Link clicks (broadcast traffic) |
action_count | Recorded conversions |
sent_rate | (sent / total_sent) × 100 |
delivery_rate | (delivered / sent) × 100 |
total_cost / avg_cost_per_msg | Cost in account currency |
Daily statistics
Section titled “Daily statistics” GET
/api/v1/sms/stats/daily
· Permission: sms.read
Day-by-day breakdown for charts, sorted by date ascending.
curl "https://restlink23telecom.com/api/v1/sms/stats/daily?period=7d" \ -H "X-API-Key: $API_KEY"const res = await fetch('https://restlink23telecom.com/api/v1/sms/stats/daily?period=7d', { method: 'GET', headers: { 'X-API-Key': process.env.API_KEY },});
if (!res.ok) { const err = await res.json(); throw new Error(`${err.error_code}: ${err.description}`);}const data = await res.json();console.log(data);import osimport requests
res = requests.get( "https://restlink23telecom.com/api/v1/sms/stats/daily", headers={"X-API-Key": os.environ["API_KEY"]}, params={ "period": "7d" },)res.raise_for_status()print(res.json())<?php$ch = curl_init('https://restlink23telecom.com/api/v1/sms/stats/daily?period=7d');curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('API_KEY')],]);
$response = curl_exec($ch);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);
if ($status !== 200) { throw new Exception("HTTP $status: $response");}$data = json_decode($response, true);print_r($data);require "net/http"require "json"
uri = URI("https://restlink23telecom.com/api/v1/sms/stats/daily?period=7d")req = Net::HTTP::Get.new(uri)req["X-API-Key"] = ENV.fetch("API_KEY")
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }raise "HTTP #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
puts JSON.parse(res.body)import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://restlink23telecom.com/api/v1/sms/stats/daily?period=7d")) .header("X-API-Key", System.getenv("API_KEY")) .GET() .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());package main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("GET", "https://restlink23telecom.com/api/v1/sms/stats/daily?period=7d", nil) if err != nil { panic(err) } req.Header.Set("X-API-Key", os.Getenv("API_KEY"))
res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close()
data, _ := io.ReadAll(res.Body) fmt.Println(string(data))}using System.Text;
using var client = new HttpClient();client.DefaultRequestHeaders.Add("X-API-Key", Environment.GetEnvironmentVariable("API_KEY"));
var response = await client.GetAsync("https://restlink23telecom.com/api/v1/sms/stats/daily?period=7d");
response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());Extra parameters:
| Parameter | Description |
|---|---|
granularity | auto switches to hourly buckets on a single-day range (dates become 2026-02-13T09:00) |
countries | Comma-separated ISO codes US,GB,DE — also flips sorting to descending |
{ "status": true, "daily_stats": [ { "date": "2026-02-13", "sent": 195, "delivered": 188, "undelivered": 4, "pending": 1, "expired": 2, "not_billed": 3, "failed": 4, "click_count": 12, "cost": 1.66, "currency": "EUR" } ], "period": {"from": "2026-02-07", "to": "2026-02-13"}}Country statistics
Section titled “Country statistics” GET
/api/v1/sms/stats/by-country
· Permission: sms.read
Grouped by destination country, sorted by total_sent descending.
curl "https://restlink23telecom.com/api/v1/sms/stats/by-country?period=30d" \ -H "X-API-Key: $API_KEY"const res = await fetch('https://restlink23telecom.com/api/v1/sms/stats/by-country?period=30d', { method: 'GET', headers: { 'X-API-Key': process.env.API_KEY },});
if (!res.ok) { const err = await res.json(); throw new Error(`${err.error_code}: ${err.description}`);}const data = await res.json();console.log(data);import osimport requests
res = requests.get( "https://restlink23telecom.com/api/v1/sms/stats/by-country", headers={"X-API-Key": os.environ["API_KEY"]}, params={ "period": "30d" },)res.raise_for_status()print(res.json())<?php$ch = curl_init('https://restlink23telecom.com/api/v1/sms/stats/by-country?period=30d');curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('API_KEY')],]);
$response = curl_exec($ch);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);
if ($status !== 200) { throw new Exception("HTTP $status: $response");}$data = json_decode($response, true);print_r($data);require "net/http"require "json"
uri = URI("https://restlink23telecom.com/api/v1/sms/stats/by-country?period=30d")req = Net::HTTP::Get.new(uri)req["X-API-Key"] = ENV.fetch("API_KEY")
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }raise "HTTP #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
puts JSON.parse(res.body)import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://restlink23telecom.com/api/v1/sms/stats/by-country?period=30d")) .header("X-API-Key", System.getenv("API_KEY")) .GET() .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());package main
import ( "fmt" "io" "net/http" "os")
func main() { req, err := http.NewRequest("GET", "https://restlink23telecom.com/api/v1/sms/stats/by-country?period=30d", nil) if err != nil { panic(err) } req.Header.Set("X-API-Key", os.Getenv("API_KEY"))
res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close()
data, _ := io.ReadAll(res.Body) fmt.Println(string(data))}using System.Text;
using var client = new HttpClient();client.DefaultRequestHeaders.Add("X-API-Key", Environment.GetEnvironmentVariable("API_KEY"));
var response = await client.GetAsync("https://restlink23telecom.com/api/v1/sms/stats/by-country?period=30d");
response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());{ "status": true, "countries": [ { "country": "United States", "country_code": "US", "country_flag": "🇺🇸", "total_sent": 520, "sent": 500, "delivered": 485, "undelivered": 10, "pending": 3, "expired": 2, "not_billed": 20, "failed": 10, "click_count": 25, "delivery_rate": 97.00, "cost": 4.25, "currency": "EUR" } ]}