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.