WhatsApp verification in PHP — plain or Laravel — is two REST calls: POST /v1/send and POST /v1/verify. The cURL example below runs with no dependencies; a Laravel HTTP client version follows it.
10 free OTPs on signup — no credit card required.
Generate an API key, then POST the destination number to /v1/send. OTP Space returns 202 Accepted once the message is queued for WhatsApp delivery.
<?php
// Plain cURL — no Composer packages required (PHP 7.4+).
// The key comes from https://app.otpspace.com/dashboard/api-keys.
// Keep it server-side; never expose it in front-end code.
const OTPSPACE_KEY = 'sk_live_xxx';
const OTPSPACE_BASE = 'https://api.otpspace.com/v1';
function otpspace_post(string $path, array $payload): array {
$ch = curl_init(OTPSPACE_BASE . $path);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . OTPSPACE_KEY,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return ['status' => $status, 'body' => json_decode($body, true)];
}
// Send a WhatsApp OTP to an Indonesian number (E.164, e.g. "+6281234567890").
// OTP Space returns 202 Accepted once the message is queued.
function send_otp(string $phone): bool {
$res = otpspace_post('/send', ['phone' => $phone]);
return $res['status'] === 202;
}
// Verify the code the user typed — 200 means it is correct.
function verify_otp(string $phone, string $code): bool {
$res = otpspace_post('/verify', ['phone' => $phone, 'code' => $code]);
return $res['status'] === 200;
}
POST the same number plus the code the user entered to /v1/verify. A 200 OK means the code is correct; every number gets up to 5 attempts before the OTP locks.
<?php
// Laravel: use the built-in HTTP client (Illuminate\Support\Facades\Http).
// Put OTPSPACE_KEY in your .env and read it via config/services.php.
namespace App\Services;
use Illuminate\Support\Facades\Http;
class OtpService
{
private string $base = 'https://api.otpspace.com/v1';
private function client()
{
return Http::withToken(config('services.otpspace.key'))
->acceptJson();
}
// Send a WhatsApp OTP; true once OTP Space returns 202 Accepted.
public function send(string $phone): bool
{
return $this->client()
->post($this->base . '/send', ['phone' => $phone])
->status() === 202;
}
// Verify the user's code; true on 200 OK.
public function verify(string $phone, string $code): bool
{
return $this->client()
->post($this->base . '/verify', ['phone' => $phone, 'code' => $code])
->status() === 200;
}
}
A successful send responds immediately with the masked destination, an otp_id you can track, and your remaining credits.
{
"success": true,
"data": {
"otp_id": "otp_abc123def456",
"destination": "6281234***90",
"channel": "whatsapp",
"status": "queued",
"expires_at": "2026-07-17T10:05:00Z"
},
"credits_remaining": 994
}
OTP Space delivers one-time passwords over WhatsApp to every Indonesian carrier through two REST calls — no WhatsApp Business API setup, no template approvals, no SDK to install. It works the same from any language: sign up, generate a key, and send. The examples here use only the standard library so you can drop them straight into an existing service.
Sign up free, generate your API key, and integrate in two REST calls — no credit card, no sales call, no WhatsApp Business verification.