Authentication
Copy page
The API supports three authentication methods. For production integrations, use an API key — optionally with HMAC request signing.
| Method | Best for | Header(s) |
|---|---|---|
| API key | Production integrations | X-API-Key |
| API key + HMAC | High-security environments | X-API-Key, X-Timestamp, X-Signature |
| JWT token | Testing, portal-only endpoints | Authorization: Bearer … |
API key (recommended)
Section titled “API key (recommended)”Create keys in the portal under
Settings → API Keys (see API keys & permissions).
Pass the key in the X-API-Key header with every request:
X-API-Key: sk_prod_a1b2c3d4e5f6g7h8i9j0...curl "https://restlink23telecom.com/api/v1/sms/stats?period=7d" \ -H "X-API-Key: $API_KEY"const res = await fetch('https://restlink23telecom.com/api/v1/sms/stats?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", 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?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?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?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?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?period=7d");
response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());API key with HMAC signature
Section titled “API key with HMAC signature”For enhanced security, enable signature verification when creating the key. Every request must then carry three headers:
| Header | Description |
|---|---|
X-API-Key | Your API key |
X-Timestamp | Current Unix timestamp in seconds |
X-Signature | HMAC-SHA256 signature (hex) |
Signature computation:
message = "{METHOD}|{path}|{timestamp}|{body}"signature = HMAC-SHA256(api_secret, message)Three rules to get it right:
pathis the URL path without the query string —/api/v1/sms/stats, not/api/v1/sms/stats?period=7d.bodyis the raw request body string; use an empty string""for GET.- Timestamps must be within 5 minutes of server time, and each timestamp + signature pair is accepted once (replay protection).
import crypto from 'node:crypto';
const apiKey = process.env.API_KEY;const apiSecret = process.env.API_SECRET;
const timestamp = Math.floor(Date.now() / 1000).toString();const method = 'POST';const path = '/api/v1/sms/send';const body = JSON.stringify({ to: ['+14155551234'], message: 'Hello!', sender_id: 'MyApp',});
const signature = crypto .createHmac('sha256', apiSecret) .update(`${method}|${path}|${timestamp}|${body}`) .digest('hex');
const res = await fetch('https://restlink23telecom.com' + path, { method, headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey, 'X-Timestamp': timestamp, 'X-Signature': signature, }, body,});console.log(await res.json());import hmac, hashlib, time, os, requests
api_key = os.environ["API_KEY"]api_secret = os.environ["API_SECRET"]
timestamp = str(int(time.time()))method = "POST"path = "/api/v1/sms/send"body = '{"to":["+14155551234"],"message":"Hello!","sender_id":"MyApp"}'
message = f"{method}|{path}|{timestamp}|{body}"signature = hmac.new(api_secret.encode(), message.encode(), hashlib.sha256).hexdigest()
res = requests.post( "https://restlink23telecom.com" + path, headers={ "Content-Type": "application/json", "X-API-Key": api_key, "X-Timestamp": timestamp, "X-Signature": signature, }, data=body,)print(res.json())<?php$apiKey = getenv('API_KEY');$apiSecret = getenv('API_SECRET');
$timestamp = (string) time();$method = 'POST';$path = '/api/v1/sms/send';$body = json_encode(['to' => ['+14155551234'], 'message' => 'Hello!', 'sender_id' => 'MyApp']);
$signature = hash_hmac('sha256', "$method|$path|$timestamp|$body", $apiSecret);
$ch = curl_init("https://restlink23telecom.com$path");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', "X-API-Key: $apiKey", "X-Timestamp: $timestamp", "X-Signature: $signature", ],]);echo curl_exec($ch);package main
import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "net/http" "os" "strconv" "strings" "time")
func main() { apiKey, apiSecret := os.Getenv("API_KEY"), os.Getenv("API_SECRET")
timestamp := strconv.FormatInt(time.Now().Unix(), 10) method, path := "POST", "/api/v1/sms/send" body := `{"to":["+14155551234"],"message":"Hello!","sender_id":"MyApp"}`
mac := hmac.New(sha256.New, []byte(apiSecret)) mac.Write([]byte(method + "|" + path + "|" + timestamp + "|" + body)) signature := hex.EncodeToString(mac.Sum(nil))
req, _ := http.NewRequest(method, "https://restlink23telecom.com"+path, strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", apiKey) req.Header.Set("X-Timestamp", timestamp) req.Header.Set("X-Signature", signature)
res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() fmt.Println(res.Status)}Signature failures return 401 SIGNATURE_REQUIRED (headers missing) or
401 INVALID_SIGNATURE (verification failed) — see errors.
JWT token
Section titled “JWT token”You can also authenticate by logging in with portal credentials. This is mainly useful for testing and for the few endpoints that are JWT-only (for example listing workspaces). For production integrations use API keys.
curl -X POST https://restlink23telecom.com/api/v1/user/auth \ -H "Content-Type: application/json" \ -d '{"login": "your_username", "password": "your_password"}'{ "status": true, "token": "eyJhbGciOiJIUzI1NiIs..."}Pass the token in subsequent requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...