For developers

SMS API integration — working examples in five languages

BrookTel is a plain REST API over HTTPS with JSON bodies and bearer-token auth. There is no proprietary SDK to install and no XML. If your language can make an HTTP request, you are already done. Here is the same send in five of them.

Before your first call

  1. Sign in and generate an API key from the API Keys page. Treat it as a secret — server-side only, never in browser or mobile code.
  2. Note your approved DLT sender header (sender ID) and the template ID you want to send against.
  3. Confirm the variable count in your payload matches the approved template exactly.
  4. Set up a webhook endpoint if you want delivery receipts pushed to you rather than polling.

Node.js

Node.js 18+ (native fetch)
async function sendSms(to, variables) {
  const res = await fetch('https://api.brooktel.in/v1/sms/send', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.BROOKTEL_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      to,
      senderId: 'BRKTEL',
      templateId: process.env.BROOKTEL_TEMPLATE_ID,
      variables,
    }),
  });

  if (!res.ok) {
    throw new Error(`BrookTel ${res.status}: ${await res.text()}`);
  }
  return res.json();
}

Python

Python 3 (requests)
import os
import requests

def send_sms(to: str, variables: dict) -> dict:
    response = requests.post(
        "https://api.brooktel.in/v1/sms/send",
        headers={
            "Authorization": f"Bearer {os.environ['BROOKTEL_API_KEY']}",
            "Content-Type": "application/json",
        },
        json={
            "to": to,
            "senderId": "BRKTEL",
            "templateId": os.environ["BROOKTEL_TEMPLATE_ID"],
            "variables": variables,
        },
        timeout=10,
    )
    response.raise_for_status()
    return response.json()

PHP

PHP 8 (cURL)
<?php
function sendSms(string $to, array $variables): array
{
    $ch = curl_init('https://api.brooktel.in/v1/sms/send');

    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . getenv('BROOKTEL_API_KEY'),
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode([
            'to' => $to,
            'senderId' => 'BRKTEL',
            'templateId' => getenv('BROOKTEL_TEMPLATE_ID'),
            'variables' => $variables,
        ]),
    ]);

    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($status >= 400) {
        throw new RuntimeException("BrookTel $status: $body");
    }

    return json_decode($body, true);
}

Java

Java 11+ (HttpClient)
var payload = """
    {"to":"%s","senderId":"BRKTEL","templateId":"%s","variables":{"otp":"%s"}}
    """.formatted(to, templateId, otp);

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.brooktel.in/v1/sms/send"))
    .header("Authorization", "Bearer " + System.getenv("BROOKTEL_API_KEY"))
    .header("Content-Type", "application/json")
    .timeout(Duration.ofSeconds(10))
    .POST(HttpRequest.BodyPublishers.ofString(payload))
    .build();

var response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());

if (response.statusCode() >= 400) {
    throw new IllegalStateException("BrookTel " + response.statusCode() + ": " + response.body());
}

Laravel

Laravel (Http facade)
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.brooktel.key'))
    ->timeout(10)
    ->retry(3, 200)
    ->post('https://api.brooktel.in/v1/sms/send', [
        'to' => $user->phone,
        'senderId' => 'BRKTEL',
        'templateId' => config('services.brooktel.template'),
        'variables' => ['otp' => $otp],
    ]);

$response->throw();

return $response->json('messageId');

Patterns worth getting right

  • Keep the API key server-side. A key in a mobile app or frontend bundle is a key that will be extracted and abused.
  • Set a request timeout. Never let an SMS call block a user-facing request indefinitely — 10 seconds is generous.
  • Retry on 5xx and network errors with exponential backoff. Do not retry on 4xx: a template mismatch will fail identically every time.
  • Store the returned messageId. It is how you correlate the delivery webhook back to the user it was for.
  • Acknowledge webhooks with a 200 immediately, then process asynchronously. Slow webhook handlers cause retries and duplicate processing.
  • Log the failure reason, not just the failed status. The reason is what tells you whether it was your payload or the recipient's handset.

Frequently asked questions

Do you have an official SDK?

There is no SDK to install, by design. The API is REST over HTTPS with JSON, so your language's standard HTTP client is all you need — and you are not blocked waiting for us to ship a version bump.

How do I authenticate?

A bearer API key in the Authorization header, generated by you from the API Keys page in the dashboard. You can create and revoke keys independently, so rotating a leaked key does not require a support ticket.

Where is the full API reference?

The API documentation is public at /api-docs — you can read the endpoints, payloads and error codes before creating an account.

How do I test without sending real messages?

Send to your own verified number on the Free Launch plan. Because DLT template matching is validated before submission, most integration mistakes surface as a clear 4xx error rather than a wasted message.

Keep reading