πŸš€ Send FREE WhatsApp OTP Messages

Learn how to send unlimited OTP messages without paying a single penny using WhatsApp Business API

πŸ“± Understanding WhatsApp Message Categories

WhatsApp Business API offers 4 message categories for different use cases:

Utility

PKR 1.6

Per message

βœ… Available in Pakistan

Service

FREE

When user initiates

βœ… Available in Pakistan

Marketing

Varies

Per message

❌ Not for OTP

⚠️ The Challenge

In Pakistan, the Authentication category (designed for OTP) costs PKR 25 per message - which is unaffordable for most businesses. The Utility category at PKR 1.6 is cheaper, but cannot be used for authentication messages.

✨ The Solution

We'll use the SERVICE category which is completely FREE when the customer initiates the conversation! This is 100% legal and compliant with WhatsApp's policies.

πŸ” How Does This Work?

1
Customer clicks your WhatsApp link
They're redirected to WhatsApp with pre-filled text
↓
2
Customer sends "OTP" message
They simply press the send button (text is pre-filled)
↓
3
Your webhook receives the message
Your system detects the OTP request keyword
↓
4
Generate and send OTP for FREE
Reply with OTP code using Service category (FREE!)

πŸ’‘ Why This Works

When a customer initiates the conversation (by sending the first message), WhatsApp allows you to respond within a 24-hour window using the Service category at no cost. This is exactly how banks and other services already operate!

πŸ“‹ Step-by-Step Implementation Guide

Create WhatsApp Redirect Link

When your customer fills out a form (name, email, mobile), create a special WhatsApp link that:

  • Opens WhatsApp application automatically
  • Pre-fills the message with "otp" keyword
  • Directs to your WhatsApp Business number
πŸ“± WhatsApp Link Format
https://wa.me/92313XXXXXXX?text=otp
Breakdown:
  • 92313XXXXXXX = Your WhatsApp Business number (with country code)
  • ?text=otp = Pre-filled message text

Setup Webhook to Receive Messages

Configure your webhook to receive incoming WhatsApp messages:

  1. Login to wa.sendpk.com
  2. Navigate to: Settings β†’ Webhook Configuration
  3. Add your webhook URL: https://yourdomain.com/webhook.php

πŸ”— Direct Link

Go directly to: https://wa.sendpk.com/dashboard/profile_webhook.php

Understand Webhook Response Format

When a customer sends a message, WhatsApp sends a JSON payload to your webhook:

πŸ“¦ Webhook JSON Response
{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "40752625244XXX",
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "display_phone_number": "92313XXXXX",
          "phone_number_id": "43001968685XXX"
        },
        "contacts": [{
          "profile": {
            "name": "Mubashar Shahzad"
          },
          "wa_id": "92300XXXXX"
        }],
        "messages": [{
          "from": "92300XXXX",
          "id": "wamid.HBgMOTIzMDAxNjU0MzIxwA==",
          "timestamp": "1769151710",
          "text": {
            "body": "otp"
          },
          "type": "text"
        }]
      },
      "field": "messages"
    }]
  }]
}

πŸ”‘ Key Fields Explained

  • from: Customer's WhatsApp number
  • text.body: Message content ("otp")
  • timestamp: When message was sent
  • contacts.profile.name: Customer's name

Create Webhook Handler (PHP)

Create a webhook.php file to process incoming messages and send OTP:

πŸ”§ webhook.php - Complete Implementation
<?php

// ===================================================
// STEP 1: Read incoming WhatsApp webhook data
// ===================================================
$input = file_get_contents("php://input");
$data  = json_decode($input, true);

// Optional: Log all incoming webhooks for debugging
file_put_contents(
    "webhook_log.txt", 
    date('Y-m-d H:i:s') . " " . $input . PHP_EOL, 
    FILE_APPEND
);

// ===================================================
// STEP 2: Extract message from webhook data
// ===================================================
if (isset($data['entry'][0]['changes'][0]['value']['messages'][0])) {
    
    $message = $data['entry'][0]['changes'][0]['value']['messages'][0];
    
    // Only process text messages
    if ($message['type'] === 'text') {
        
        // Get sender's number and message content
        $from = $message['from'];              // e.g., "92300XXXXXXX"
        $text = trim($message['text']['body']); // e.g., "otp"
        
        // ===================================================
        // STEP 3: Check if message is OTP request
        // ===================================================
        if (strtolower($text) === 'otp') {
            
            // Generate random 6-digit OTP code
            $otp_code = rand(100000, 999999);
            
            // ===================================================
            // STEP 4: Store OTP in database (IMPORTANT!)
            // ===================================================
            // Connect to your database
            // $conn = mysqli_connect("localhost", "user", "pass", "db");
            
            // Store OTP with expiry time
            // $expiry = date('Y-m-d H:i:s', strtotime('+5 minutes'));
            // $sql = "INSERT INTO otp_codes (mobile, otp_code, created_at, expires_at) 
            //         VALUES ('$from', '$otp_code', NOW(), '$expiry')";
            // mysqli_query($conn, $sql);
            
            // ===================================================
            // STEP 5: Prepare WhatsApp message payload
            // ===================================================
            $payload = [
                [
                    "mobile" => $from,           // Send to customer's number
                    "type"   => "text",          // Message type
                    "text"   => [
                        "body" => "Your OTP code is: $otp_code\n\nThis code will expire in 5 minutes.\n\nDo not share this code with anyone."
                    ]
                ]
            ];
            
            // ===================================================
            // STEP 6: Send OTP via WhatsApp (FREE!)
            // ===================================================
            $api_url = "https://wa.sendpk.com/api/send.php";
            $api_key = "YOUR_API_KEY_HERE";  // Get from wa.sendpk.com
            
            // Construct final API URL
            $url = $api_url . "?api_key=" . $api_key . 
                   "&free_form=" . urlencode(json_encode($payload));
            
            // Send the request
            $response = file_get_contents($url);
            
            // Optional: Log the response
            file_put_contents(
                "otp_sent_log.txt", 
                date('Y-m-d H:i:s') . " Sent OTP $otp_code to $from - Response: $response" . PHP_EOL, 
                FILE_APPEND
            );
        }
    }
}

// ===================================================
// STEP 7: Always respond with 200 OK
// ===================================================
http_response_code(200);
echo "OK";

?>

Database Storage for OTP Verification

Store generated OTPs in your database so you can verify them later:

πŸ—„οΈ Database Table Structure
CREATE TABLE otp_codes (
    id INT AUTO_INCREMENT PRIMARY KEY,
    mobile VARCHAR(20) NOT NULL,
    otp_code VARCHAR(6) NOT NULL,
    created_at DATETIME NOT NULL,
    expires_at DATETIME NOT NULL,
    verified TINYINT(1) DEFAULT 0,
    INDEX idx_mobile (mobile),
    INDEX idx_otp (otp_code)
);
πŸ’Ύ Store OTP in Database (PHP)
<?php

// Database connection
$conn = mysqli_connect("localhost", "username", "password", "database");

// Store OTP
$mobile = $from; // From webhook
$otp_code = rand(100000, 999999);
$expires_at = date('Y-m-d H:i:s', strtotime('+5 minutes'));

$sql = "INSERT INTO otp_codes (mobile, otp_code, created_at, expires_at) 
        VALUES (?, ?, NOW(), ?)";

$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, "sss", $mobile, $otp_code, $expires_at);
mysqli_stmt_execute($stmt);

?>

Verify OTP When User Submits

When the user enters the OTP code, verify it against your database:

βœ… Verify OTP (PHP)
<?php

// verify_otp.php
$conn = mysqli_connect("localhost", "username", "password", "database");

// Get submitted data
$mobile = $_POST['mobile'];        // e.g., "92300XXXXXXX"
$submitted_otp = $_POST['otp'];    // e.g., "123456"

// Query database for valid OTP
$sql = "SELECT * FROM otp_codes 
        WHERE mobile = ? 
        AND otp_code = ? 
        AND verified = 0 
        AND expires_at > NOW() 
        ORDER BY created_at DESC 
        LIMIT 1";

$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, "ss", $mobile, $submitted_otp);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);

if (mysqli_num_rows($result) > 0) {
    // OTP is valid!
    
    // Mark as verified
    $sql_update = "UPDATE otp_codes SET verified = 1 WHERE mobile = ? AND otp_code = ?";
    $stmt_update = mysqli_prepare($conn, $sql_update);
    mysqli_stmt_bind_param($stmt_update, "ss", $mobile, $submitted_otp);
    mysqli_stmt_execute($stmt_update);
    
    echo json_encode([
        "success" => true,
        "message" => "Mobile number verified successfully!"
    ]);
    
} else {
    // Invalid or expired OTP
    echo json_encode([
        "success" => false,
        "message" => "Invalid or expired OTP code"
    ]);
}

?>

🎯 Complete Real-World Example

Here's how everything works together in a user registration form:

πŸ“ HTML Registration Form with WhatsApp OTP
<!DOCTYPE html>
<html>
<head>
    <title>Registration with WhatsApp OTP</title>
</head>
<body>
    <h2>User Registration</h2>
    
    <form id="registrationForm">
        <label>Name:</label>
        <input type="text" name="name" required><br><br>
        
        <label>Email:</label>
        <input type="email" name="email" required><br><br>
        
        <label>Mobile (with country code):</label>
        <input type="text" name="mobile" id="mobile" placeholder="92300XXXXXXX" required><br><br>
        
        <!-- Button to request OTP via WhatsApp -->
        <button type="button" onclick="requestOTP()">
            πŸ“± Verify via WhatsApp
        </button>
    </form>
    
    <!-- OTP Verification Section (shown after requesting OTP) -->
    <div id="otpSection" style="display:none; margin-top: 20px;">
        <h3>Enter OTP Code</h3>
        <input type="text" id="otpCode" placeholder="Enter 6-digit code" maxlength="6">
        <button onclick="verifyOTP()">Verify OTP</button>
    </div>
    
    <script>
        function requestOTP() {
            var mobile = document.getElementById('mobile').value;
            
            if (!mobile) {
                alert('Please enter your mobile number');
                return;
            }
            
            // Redirect to WhatsApp with pre-filled "otp" text
            var whatsappURL = 'https://wa.me/92313XXXXXXX?text=otp';
            window.open(whatsappURL, '_blank');
            
            // Show OTP input section
            document.getElementById('otpSection').style.display = 'block';
            
            alert('Please send the message in WhatsApp. You will receive your OTP code shortly!');
        }
        
        function verifyOTP() {
            var mobile = document.getElementById('mobile').value;
            var otp = document.getElementById('otpCode').value;
            
            // Send AJAX request to verify OTP
            fetch('verify_otp.php', {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: 'mobile=' + mobile + '&otp=' + otp
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    alert('βœ… ' + data.message);
                    // Continue with registration...
                } else {
                    alert('❌ ' + data.message);
                }
            });
        }
    </script>
</body>
</html>

✨ Key Benefits

♾️ Unlimited

Send unlimited OTP messages without worrying about costs

βœ… Compliant

100% compliant with WhatsApp's terms of service

⚑ Fast

Instant delivery through WhatsApp's infrastructure

⚠️ Important Considerations

πŸ” Security Best Practices

  • Always set OTP expiry time (recommended: 5 minutes)
  • Store OTPs securely in your database with encryption
  • Limit OTP generation attempts to prevent abuse
  • Mark OTP as used after successful verification
  • Never log OTP codes in plain text

πŸ’‘ Pro Tips

  • Add rate limiting to prevent spam (max 3 OTPs per number per hour)
  • Include your brand name in the OTP message
  • Provide clear expiry information to users
  • Test with multiple numbers before going live
  • Monitor webhook logs regularly

πŸ• 24-Hour Window

Remember that the FREE service window lasts for 24 hours from when the customer sends the first message. You can send multiple messages within this window at no cost!

πŸ”§ Troubleshooting Common Issues

❌ Webhook Not Receiving Messages

  • Verify webhook URL is publicly accessible (test with tools like webhook.site)
  • Check if URL is correctly configured in wa.sendpk.com dashboard
  • Ensure your server accepts POST requests
  • Check webhook logs for any errors

❌ OTP Not Sending

  • Verify your API key is correct
  • Check if WhatsApp number is properly configured
  • Ensure customer initiated the conversation first
  • Check API response for error messages

❌ OTP Verification Fails

  • Check if OTP has expired (default: 5 minutes)
  • Verify mobile number format matches exactly
  • Ensure OTP hasn't been used already
  • Check database connection and query

πŸŽ‰ Conclusion

By using the Service category approach, you can send FREE WhatsApp OTP messages to your customers without any cost per message. This method is:

  • Completely free - Save PKR 25 per OTP
  • WhatsApp compliant - Uses official API correctly
  • User-friendly - Customers just click and send
  • Scalable - Handle unlimited OTP requests
  • Battle-tested - Same method used by banks
πŸš€ Get Started Now

Questions or need help? Feel free to reach out for technical support and implementation assistance.