OTP API

OTP API Documentation

A simple REST API to send OTPs via SMS and check delivery status. One endpoint to send, one to check status. Works with any language or framework.

✦ No credit card required · Free plan available · Setup in 5 minutes

Authentication

All API requests require an API key in the X-API-Key header. Create API keys from your dashboard.

X-API-Key: sm_live_your_api_key_here

Base URL

https://api.startmessaging.com
API Reference

REST API Endpoints

  • POST /otp/send

    Send a one-time password to a phone number. Fields: phoneNumber (E.164 format), templateId (optional), and variables (Must contain "otp" — a 4-6 digit code you generate, plus optional custom placeholders like "appName").

  • GET /messages/:id

    Fetch the real-time delivery status of an OTP request. Statuses include: initiated, queued, sent, delivered, and failed.

Send an OTP in One API Call

Works with every language. Just a single POST request.

curl -X POST https://api.startmessaging.com/otp/send \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sm_live_your_api_key_here" \
  -d '{
    "phoneNumber": "+919876543210",
    "templateId": "YOUR_TEMPLATE_ID",
    "variables": {
      "otp": "123456",
      "appName": "YourApp"
    }
  }'
const response = await fetch("https://api.startmessaging.com/otp/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "sm_live_your_api_key_here",
  },
  body: JSON.stringify({
    phoneNumber: "+919876543210",
    templateId: "YOUR_TEMPLATE_ID",
    variables: {
      otp: "123456",
      appName: "YourApp",
    },
  }),
});

const data = await response.json();
console.log(data);
import requests

response = requests.post(
    "https://api.startmessaging.com/otp/send",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "sm_live_your_api_key_here",
    },
    json={
        "phoneNumber": "+919876543210",
        "templateId": "YOUR_TEMPLATE_ID",
        "variables": {
            "otp": "123456",
            "appName": "YourApp"
        },
    },
)

data = response.json()
print(data)
$ch = curl_init("https://api.startmessaging.com/otp/send");

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        "Content-Type: application/json",
        "X-API-Key: sm_live_your_api_key_here",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "phoneNumber" => "+919876543210",
        "templateId" => "YOUR_TEMPLATE_ID",
        "variables" => [
            "otp" => "123456",
            "appName" => "YourApp"
        ]
    ]),
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
import java.net.http.*;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();

String body = """
    {
      "phoneNumber": "+919876543210",
      "templateId": "YOUR_TEMPLATE_ID",
      "variables": {
        "otp": "123456",
        "appName": "YourApp"
      }
    }
    """;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.startmessaging.com/otp/send"))
    .header("Content-Type", "application/json")
    .header("X-API-Key", "sm_live_your_api_key_here")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
package main

import (
  "bytes"
  "encoding/json"
  "fmt"
  "net/http"
  "io"
)

func main() {
  payload, _ := json.Marshal(map[string]interface{}{
    "phoneNumber": "+919876543210",
    "templateId":  "YOUR_TEMPLATE_ID",
    "variables": map[string]string{
      "otp":     "123456",
      "appName": "YourApp",
    },
  })

  req, _ := http.NewRequest("POST", "https://api.startmessaging.com/otp/send", bytes.NewBuffer(payload))
  req.Header.Set("Content-Type", "application/json")
  req.Header.Set("X-API-Key", "sm_live_your_api_key_here")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  body, _ := io.ReadAll(resp.Body)
  fmt.Println(string(body))
}

Response Format

All responses follow a consistent JSON envelope:

{
  "success": true,
  "statusCode": 201,
  "requestId": "req_abc123",
  "timestamp": "2026-02-15T10:30:00.000Z",
  "data": {
    "otpRequestId": "uuid-of-otp-request",
    "messageId": "uuid-of-message",
    "status": "queued"
  }
}
FAQ

API FAQ

What authentication does the API use?

All requests require an API key passed in the X-API-Key header. API keys start with sm_live_ and can be created from the dashboard.

What format should phone numbers be in?

Phone numbers must be in E.164 format: +{country code}{number}. For Indian numbers: +919876543210.

What is the rate limit?

We support a high throughput of 20 OTPs per second globally per account. Additionally, there is a security limit of 3 OTPs per 5 minutes per mobile number to prevent abuse.

Do you support webhooks for delivery status?

Delivery status is available via the messages API endpoint. You can poll for status updates using the message ID returned from the send endpoint.

SMS & Auth API

Start Building with the OTP API

Get your API key and send your first OTP in under 5 minutes.