v1.0
● Live
WhatsApp OTP API
Send and verify one-time passwords via WhatsApp using a simple REST API. Supports multiple languages and instant delivery.
📌 Overview
Base URL
https://api.my-otp-way.com
Auth Method
X-API-Key Header
Format
JSON (application/json)
Supported Languages: en, ar, ru, de, fr, pt_BR, tr, es — Contact us to enable more.
🔐 Authentication
All API requests must include your API key in the X-API-Key header.
curl https://api.my-otp-way.com/api/v1/otp/send \
-H "X-API-Key: sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json"
sk_live_
Live key — charges real balance, sends real messages.
sk_test_
Test key — simulates sending without real delivery.
POST
Send OTP
/api/v1/otp/send
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| to | string | ✅ | Recipient phone number in E.164 format (+9647XXXXXXXXX) |
| template | string | ✅ | Template name (e.g. myotp_default) |
| length | integer | ❌ | OTP length: 4–8 digits (default: 6) |
| lang | string | ❌ | Message language: en, ar, de, fr... (default: en) |
Response 202 Accepted
{
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "OTP queued for delivery.",
"expires_in": 300
}
Error Responses
401
Invalid or missing API key
402
Insufficient wallet balance
404
Template not found or not approved
422
Validation error (invalid phone number, etc.)
429
Rate limit exceeded (3 per 15 min per number)
POST
Verify OTP
/api/v1/otp/verify
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string (UUID) | ✅ | The request_id returned from Send OTP |
| code | string | ✅ | The OTP code entered by the user |
Response
✅ Success (200)
{ "verified": true }
❌ Failed (400)
{
"verified": false,
"reason": "Invalid OTP code.",
"attempts_remaining": 4
}
Code Examples
Copy and paste — ready to use in your project.
Send OTP
curl -X POST https://api.my-otp-way.com/api/v1/otp/send \
-H "X-API-Key: sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"to": "+9647812345678",
"template": "myotp_default",
"length": 6,
"lang": "en"
}'
Verify OTP
curl -X POST https://api.my-otp-way.com/api/v1/otp/verify \
-H "X-API-Key: sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"code": "123456"
}'
Send OTP
<?php
$apiKey = 'sk_live_YOUR_API_KEY';
// Send OTP
$ch = curl_init('https://api.my-otp-way.com/api/v1/otp/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+9647812345678',
'template' => 'myotp_default',
'length' => 6,
'lang' => 'ar',
]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
$requestId = $response['request_id'];
// Verify OTP
$ch = curl_init('https://api.my-otp-way.com/api/v1/otp/verify');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'request_id' => $requestId,
'code' => $_POST['otp_code'],
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($result['verified']) {
echo "Phone number verified!";
} else {
echo "Invalid code: " . $result['reason'];
}
Send OTP + Verify OTP
const API_KEY = 'sk_live_YOUR_API_KEY';
const BASE_URL = 'https://api.my-otp-way.com/api/v1';
async function sendOtp(phoneNumber) {
const response = await fetch(`${BASE_URL}/otp/send`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
to: phoneNumber,
template: 'myotp_default',
length: 6,
lang: 'en',
}),
});
const data = await response.json();
return data.request_id;
}
async function verifyOtp(requestId, code) {
const response = await fetch(`${BASE_URL}/otp/verify`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({ request_id: requestId, code }),
});
const data = await response.json();
return data.verified;
}
const requestId = await sendOtp('+9647812345678');
await verifyOtp(requestId, '123456');
import requests
API_KEY = 'sk_live_YOUR_API_KEY'
BASE_URL = 'https://api.my-otp-way.com/api/v1'
headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
'Accept': 'application/json',
}
def send_otp(phone_number: str, lang: str = 'en') -> str:
response = requests.post(
f'{BASE_URL}/otp/send',
headers=headers,
json={
'to': phone_number,
'template': 'myotp_default',
'length': 6,
'lang': lang,
}
)
response.raise_for_status()
return response.json()['request_id']
def verify_otp(request_id: str, code: str) -> bool:
response = requests.post(
f'{BASE_URL}/otp/verify',
headers=headers,
json={'request_id': request_id, 'code': code}
)
response.raise_for_status()
return response.json()['verified']
request_id = send_otp('+9647812345678', lang='ar')
verified = verify_otp(request_id, '123456')
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
const (
apiKey = "sk_live_YOUR_API_KEY"
baseURL = "https://api.my-otp-way.com/api/v1"
)
func sendOtp(phone string) (string, error) {
body, _ := json.Marshal(map[string]interface{}{
"to": phone,
"template": "myotp_default",
"length": 6,
"lang": "en",
})
req, _ := http.NewRequest("POST", baseURL+"/otp/send", bytes.NewBuffer(body))
req.Header.Set("X-API-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result["request_id"].(string), nil
}
func verifyOtp(requestID, code string) bool {
body, _ := json.Marshal(map[string]string{
"request_id": requestID,
"code": code,
})
req, _ := http.NewRequest("POST", baseURL+"/otp/verify", bytes.NewBuffer(body))
req.Header.Set("X-API-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result["verified"].(bool)
}
func main() {
requestID, _ := sendOtp("+9647812345678")
fmt.Println("Request ID:", requestID)
if verifyOtp(requestID, "123456") {
fmt.Println("Verified!")
}
}
using System.Net.Http;
using System.Text;
using System.Text.Json;
public class OtpWayClient
{
private readonly HttpClient _http;
private const string BaseUrl = "https://api.my-otp-way.com/api/v1";
public OtpWayClient(string apiKey)
{
_http = new HttpClient();
_http.DefaultRequestHeaders.Add("X-API-Key", apiKey);
_http.DefaultRequestHeaders.Add("Accept", "application/json");
}
public async Task<string> SendOtpAsync(string phoneNumber, string lang = "en")
{
var payload = new { to = phoneNumber, template = "myotp_default", length = 6, lang };
var content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await _http.PostAsync($"{BaseUrl}/otp/send", content);
var body = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<JsonElement>(body);
return result.GetProperty("request_id").GetString()!;
}
public async Task<bool> VerifyOtpAsync(string requestId, string code)
{
var payload = new { request_id = requestId, code };
var content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await _http.PostAsync($"{BaseUrl}/otp/verify", content);
var body = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<JsonElement>(body);
return result.GetProperty("verified").GetBoolean();
}
}
var client = new OtpWayClient("sk_live_YOUR_API_KEY");
string requestId = await client.SendOtpAsync("+9647812345678", "ar");
bool ok = await client.VerifyOtpAsync(requestId, "123456");
⚡ Rate Limits
3 / 15 min
Per recipient number
Prevents OTP spam per user
10 / day
Per recipient number
Daily cap per phone number
Unlimited
Per API key
No global limit on your key
Need Help?
Our support team is available 24/7 to help you integrate.