'whatsapp', 'recipient_type' => 'individual', 'to' => $to, 'type' => 'text', 'text' => ['body' => $text], ]); } public static function sendTemplate(string $to, string $templateName, string $phoneNumberId, array $components = []): array { $payload = [ 'messaging_product' => 'whatsapp', 'recipient_type' => 'individual', 'to' => $to, 'type' => 'template', 'template' => [ 'name' => $templateName, 'language' => ['code' => 'es'], ], ]; if (!empty($components)) { $payload['template']['components'] = $components; } return self::callApi($phoneNumberId, $payload); } public static function sendImage(string $to, string $mediaIdOrUrl, string $phoneNumberId, ?string $caption = null): array { $payload = [ 'messaging_product' => 'whatsapp', 'recipient_type' => 'individual', 'to' => $to, 'type' => 'image', 'image' => [ (str_starts_with($mediaIdOrUrl, 'http') ? 'link' : 'id') => $mediaIdOrUrl, ], ]; if ($caption !== null) { $payload['image']['caption'] = $caption; } return self::callApi($phoneNumberId, $payload); } public static function sendInteractive(string $to, array $interactive, string $phoneNumberId): array { return self::callApi($phoneNumberId, [ 'messaging_product' => 'whatsapp', 'recipient_type' => 'individual', 'to' => $to, 'type' => 'interactive', 'interactive' => $interactive, ]); } public static function uploadMedia(string $filePath, string $mimeType, string $phoneNumberId): array { $url = self::BASE_URL . '/' . self::API_VERSION . '/' . $phoneNumberId . '/media'; $token = env('WHATSAPP_ACCESS_TOKEN', ''); if ($token === '') { return ['success' => false, 'error' => 'WHATSAPP_ACCESS_TOKEN no configurado']; } $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => [ 'messaging_product' => 'whatsapp', 'file' => new \CURLFile($filePath, $mimeType, basename($filePath)), ], CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $token, ], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 60, ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); $decoded = $response ? json_decode($response, true) : null; unlink($filePath); return [ 'success' => $httpCode >= 200 && $httpCode < 300, 'http_code' => $httpCode, 'media_id' => $decoded['id'] ?? null, 'response' => $decoded ?? $response, 'error' => $error ?: null, ]; } public static function sendDocument(string $to, string $mediaId, string $phoneNumberId, ?string $caption = null, ?string $filename = null): array { $document = ['id' => $mediaId]; if ($filename !== null) { $document['filename'] = $filename; } if ($caption !== null) { $document['caption'] = $caption; } return self::callApi($phoneNumberId, [ 'messaging_product' => 'whatsapp', 'recipient_type' => 'individual', 'to' => $to, 'type' => 'document', 'document' => $document, ]); } private static function callApi(string $phoneNumberId, array $payload): array { $url = self::BASE_URL . '/' . self::API_VERSION . '/' . $phoneNumberId . '/messages'; $token = env('WHATSAPP_ACCESS_TOKEN', ''); if ($token === '') { return ['success' => false, 'error' => 'WHATSAPP_ACCESS_TOKEN no configurado']; } $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $token, 'Content-Type: application/json', ], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); $decoded = $response ? json_decode($response, true) : null; return [ 'success' => $httpCode >= 200 && $httpCode < 300, 'http_code' => $httpCode, 'response' => $decoded ?? $response, 'error' => $error ?: ($decoded['error']['message'] ?? null), 'wam_id' => $decoded['messages'][0]['id'] ?? null, ]; } }