AISENSY_API_KEY, 'campaignName' => AISENSY_TEMPLATE, 'destination' => $phone, 'userName' => 'Relevant Reflex Consulting', 'templateParams' => [$verifyUrl], 'source' => 'new-landing-page form', 'media' => (object)[], 'buttons' => [], 'carouselCards' => [], 'location' => (object)[] ]; $ch = curl_init(AISENSY_API_URL); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json' ], CURLOPT_TIMEOUT => 30, CURLOPT_SSL_VERIFYPEER => true, ]); $response = curl_exec($ch); $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($curlError) { logMsg("CURL error for $phone: $curlError"); return false; } $data = json_decode($response, true); // AiSensy returns 200 with success or error message if ($statusCode === 200) { logMsg("Sent to $phone — Response: $response"); return true; } logMsg("Failed for $phone — HTTP $statusCode — $response"); return false; } // ── MAIN ───────────────────────────────────────────────────────── logMsg("Cron started"); try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4", DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); // Find eligible members: // - signed up 5 to 10 minutes ago // - email not verified // - has a whatsapp number // - whatsapp_msg_sent = 0 $stmt = $pdo->query(" SELECT u.id, u.whatsapp_number, ev.token as verify_token FROM users u LEFT JOIN email_verifications ev ON ev.id = ( SELECT id FROM email_verifications WHERE user_id = u.id ORDER BY created_at DESC LIMIT 1 ) WHERE u.email_verified = 0 AND u.whatsapp_msg_sent = 0 AND u.whatsapp_number IS NOT NULL AND u.whatsapp_number != '' AND u.created_at BETWEEN DATE_SUB(NOW(), INTERVAL 10 MINUTE) AND DATE_SUB(NOW(), INTERVAL 5 MINUTE) "); $members = $stmt->fetchAll(); if (empty($members)) { logMsg("No eligible members found — exiting"); exit; } logMsg("Found " . count($members) . " eligible member(s)"); foreach ($members as $member) { $userId = $member['id']; $mobile = $member['whatsapp_number']; $token = $member['verify_token']; if (empty($token)) { logMsg("User $userId — no verify token found, skipping"); // Mark as sent anyway so we don't retry endlessly $pdo->prepare("UPDATE users SET whatsapp_msg_sent = 1 WHERE id = ?") ->execute([$userId]); continue; } $verifyUrl = 'https://relevantreflex.com/verify.php?token=' . $token . '&via=whatsapp'; $sent = sendWhatsApp($mobile, $verifyUrl); // Always mark as sent (success or not) to prevent duplicate sends $pdo->prepare("UPDATE users SET whatsapp_msg_sent = 1 WHERE id = ?") ->execute([$userId]); if ($sent) { logMsg("User $userId ($mobile) — WhatsApp sent successfully"); } else { logMsg("User $userId ($mobile) — WhatsApp send FAILED (marked as sent to avoid retry loop)"); } } } catch (Exception $e) { logMsg("ERROR: " . $e->getMessage()); } logMsg("Cron finished");