<?php
 namespace App\Services\Tracking\Providers; use App\Services\Tracking\Contracts\TrackingProvider; use App\Services\Tracking\TrackingEvent; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; class MetaConversionsApiProvider implements TrackingProvider { private const API_VERSION = 'v18.0'; public function isEnabled(): bool { return !empty(setting('meta_pixel_id')) && !empty(setting('meta_capi_access_token')); } public function send(TrackingEvent $event): void { $pixelId = setting('meta_pixel_id'); $accessToken = setting('meta_capi_access_token'); $testCode = setting('meta_capi_test_event_code'); $endpoint = "https://graph.facebook.com/" . self::API_VERSION . "/{$pixelId}/events"; $payload = [ 'data' => [$this->buildEventData($event)], ]; if (!empty($testCode)) { $payload['test_event_code'] = $testCode; } $response = Http::timeout(5) ->withQueryParameters(['access_token' => $accessToken]) ->post($endpoint, $payload); if ($response->failed()) { Log::channel('tracking')->error('Meta CAPI send failed', [ 'status' => $response->status(), 'body' => $response->body(), 'event' => $event->name, 'event_id' => $event->eventId, ]); throw new \RuntimeException("Meta CAPI responded {$response->status()}"); } Log::channel('tracking')->info('Meta CAPI sent', [ 'event' => $event->name, 'event_id' => $event->eventId, 'status' => $response->status(), ]); } private function buildEventData(TrackingEvent $event): array { $data = [ 'event_name' => $event->name, 'event_time' => $event->timestamp, 'action_source' => 'website', 'user_data' => $this->buildUserData($event), 'custom_data' => $this->buildCustomData($event), ]; if ($event->eventId) $data['event_id'] = $event->eventId; if ($event->sourceUrl) $data['event_source_url'] = $event->sourceUrl; return $data; } private function buildUserData(TrackingEvent $event): array { $user = $event->user; $ud = []; if (!$user) return $ud; if ($user->emailSha256) $ud['em'] = [$user->emailSha256]; if ($user->phoneSha256) $ud['ph'] = [$user->phoneSha256]; if ($user->firstNameSha256) $ud['fn'] = [$user->firstNameSha256]; if ($user->lastNameSha256) $ud['ln'] = [$user->lastNameSha256]; if ($user->countrySha256) $ud['country'] = [$user->countrySha256]; if ($user->ipAddress) $ud['client_ip_address'] = $user->ipAddress; if ($user->userAgent) $ud['client_user_agent'] = $user->userAgent; if ($user->fbc) $ud['fbc'] = $user->fbc; if ($user->fbp) $ud['fbp'] = $user->fbp; return $ud; } private function buildCustomData(TrackingEvent $event): array { $cd = []; if (isset($event->params['value'])) $cd['value'] = (float) $event->params['value']; if (isset($event->params['currency'])) $cd['currency'] = $event->params['currency']; if (isset($event->params['transaction_id'])) $cd['order_id'] = $event->params['transaction_id']; if (isset($event->params['contents']) && is_array($event->params['contents'])) { $cd['content_ids'] = array_map(fn ($c) => (string) ($c['id'] ?? ''), $event->params['contents']); $cd['content_type'] = 'product'; $cd['contents'] = array_map(fn ($c) => [ 'id' => (string) ($c['id'] ?? ''), 'quantity' => (int) ($c['quantity'] ?? 1), 'item_price' => (float) ($c['item_price'] ?? 0), ], $event->params['contents']); } return $cd; } } 