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_hereBase URL
https://api.startmessaging.comREST 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.
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"
}
}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.
Related Pages
Start Building with the OTP API
Get your API key and send your first OTP in under 5 minutes.