feat(telecom): integrate verified OTPIQ live API with whatsapp-sms and auto-formatting

This commit is contained in:
Hamza-Ayed
2026-09-18 18:12:45 +03:00
parent 6817ce5ee3
commit 1400f8a014
+23 -16
View File
@@ -7,40 +7,41 @@ namespace App\Services;
class OtpIqService class OtpIqService
{ {
private string $apiKey; private string $apiKey;
private string $senderId;
private string $endpoint; private string $endpoint;
private string $provider;
public function __construct() public function __construct()
{ {
$this->apiKey = getenv('OTPIQ_API_KEY') ?: ''; $this->apiKey = getenv('OTPIQ_API_KEY') ?: 'sk_live_a2b4f0fe539910aee2e44be050e9767bea266607';
$this->senderId = getenv('OTPIQ_SENDER_ID') ?: 'URUK-PRIZE';
$this->endpoint = getenv('OTPIQ_ENDPOINT') ?: 'https://api.otpiq.com/api/sms'; $this->endpoint = getenv('OTPIQ_ENDPOINT') ?: 'https://api.otpiq.com/api/sms';
$this->provider = getenv('OTPIQ_PROVIDER') ?: 'whatsapp-sms';
} }
/** /**
* Sends OTP via OTPIQ with Smart Fallback (WhatsApp first, then SMS). * Sends OTP via OTPIQ with Smart Fallback (WhatsApp first, then SMS).
* Verified with live production API credentials.
*/ */
public function sendOtp(string $phoneNumber, string $otpCode): array public function sendOtp(string $phoneNumber, string $otpCode): array
{ {
$normalizedPhone = PhoneFormatterService::normalize($phoneNumber);
// If API key is not configured, run in Mock / Dev mode // If API key is not configured, run in Mock / Dev mode
if (empty($this->apiKey)) { if (empty($this->apiKey)) {
error_log("[MOCK OTPIQ] Sent OTP {$otpCode} to {$phoneNumber} via WhatsApp/SMS Smart Fallback."); error_log("[MOCK OTPIQ] Sent OTP {$otpCode} to {$normalizedPhone} via whatsapp-sms.");
return [ return [
'success' => true, 'success' => true,
'mode' => 'mock', 'mode' => 'mock',
'phone' => $phoneNumber, 'phone' => $normalizedPhone,
'otp' => $otpCode, 'otp' => $otpCode,
'provider' => 'mock-smart-fallback', 'provider' => $this->provider,
]; ];
} }
$payload = [ $payload = [
'recipient' => $phoneNumber, 'phoneNumber' => $normalizedPhone,
'sender_id' => $this->senderId, 'smsType' => 'verification',
'type' => 'otp', 'provider' => $this->provider,
'code' => $otpCode, 'verificationCode' => (string)$otpCode,
'message' => "رمز التحقق الخاص بك لجائزة أوروك الدولية هو: {$otpCode}. لا تشاركه مع أحد.",
'channels' => ['whatsapp', 'sms'], // Smart fallback pipeline
]; ];
$ch = curl_init($this->endpoint); $ch = curl_init($this->endpoint);
@@ -49,21 +50,23 @@ class OtpIqService
CURLOPT_POST => true, CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => [ CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->apiKey, 'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json',
], ],
CURLOPT_TIMEOUT => 10, CURLOPT_TIMEOUT => 12,
]); ]);
$response = curl_exec($ch); $response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch); $error = curl_error($ch);
curl_close($ch); if (PHP_VERSION_ID < 80500) {
curl_close($ch);
}
if ($error || $httpCode >= 400) { if ($error || $httpCode >= 400) {
return [ return [
'success' => false, 'success' => false,
'error' => $error ?: "HTTP {$httpCode}: " . substr((string)$response, 0, 100), 'error' => $error ?: "HTTP {$httpCode}: " . substr((string)$response, 0, 150),
]; ];
} }
@@ -71,6 +74,10 @@ class OtpIqService
return [ return [
'success' => true, 'success' => true,
'data' => $data, 'data' => $data,
'sms_id' => $data['smsId'] ?? null,
'remaining_credit' => $data['remainingCredit'] ?? null,
'cost' => $data['cost'] ?? 25,
]; ];
} }
} }