getProviderName() === $providerHint) { return $adapter; } } } // Auto-detect adapter by payload shape foreach (self::getAdapters() as $adapter) { if ($adapter->canHandle($payload)) { return $adapter; } } return null; } /** * Main webhook handler */ public static function handleWebhook(): void { ray('Missed Call Webhook handleWebhook'); $payload = self::getPayload(); // Check for webhook verification from any adapter foreach (self::getAdapters() as $adapter) { $verification = $adapter->handleVerification(); if ($verification !== null) { echo $verification; wp_die(); } } // Resolve adapter $adapter = self::resolveAdapter($payload); if (!$adapter) { self::logError('No adapter found for payload', $payload); status_header(400); wp_die('Bad Request: unknown payload format'); } // Normalize payload $data = $adapter->normalize($payload); ray($data); self::logWebhook($adapter->getProviderName(), $data); // Only process missed calls if (!$data['is_missed']) { status_header(200); wp_die('ok'); } // Process the missed call try { $service = new MissedCallService(); $service->handle( $data['caller_phone'], $data['destination_phone'], $data['call_id'], $adapter->getProviderName() ); } catch (\Throwable $e) { self::logError('Error processing missed call: ' . $e->getMessage(), $data); } status_header(200); wp_die('ok'); } /** * Get the webhook payload from POST data * * @return array */ protected static function getPayload(): array { // Try JSON body first $rawBody = file_get_contents('php://input'); if ($rawBody) { $json = json_decode($rawBody, true); if (is_array($json) && !empty($json)) { return $json; } } // Fall back to POST params return $_POST ?: []; } /** * Log webhook for debugging */ protected static function logWebhook(string $provider, array $data): void { if (!defined('ALEXR_WHATSAPP_DEBUG') || !ALEXR_WHATSAPP_DEBUG) { return; } $logData = [ 'type' => 'missed_call_webhook', 'provider' => $provider, 'caller' => $data['caller_phone'] ?? null, 'destination' => $data['destination_phone'] ?? null, 'call_id' => $data['call_id'] ?? null, 'is_missed' => $data['is_missed'] ?? false, 'timestamp' => current_time('mysql'), ]; if (function_exists('ray')) { ray('Missed Call Webhook', $logData); } do_action('alexr_missed_call_webhook_log', $logData); } /** * Log errors */ protected static function logError(string $message, array $context = []): void { if (function_exists('ray')) { ray('MissedCallWebhook ERROR', ['error' => $message, 'context' => $context]); } error_log('[MissedCallWebhookHandler] ' . $message . ' | ' . json_encode($context)); } } MissedCallWebhookHandler::register();