'Invalid signature'], 400); $event = json_decode($payload, true); if (!is_array($event) || empty($event['id']) || empty($event['type'])) jsonResponse(['error' => 'Invalid event'], 400); $db = getDB(); $exists = $db->prepare("SELECT 1 FROM stripe_events WHERE event_id=?"); $exists->execute([$event['id']]); if ($exists->fetchColumn()) jsonResponse(['received' => true, 'duplicate' => true]); $object = $event['data']['object'] ?? []; if ($event['type'] === 'checkout.session.completed') { $userId = (int)($object['metadata']['user_id'] ?? $object['client_reference_id'] ?? 0); if ($userId > 0) { $db->prepare("UPDATE users SET stripe_customer_id=?,stripe_subscription_id=?,subscription_status='active' WHERE id=?") ->execute([$object['customer'] ?? null, $object['subscription'] ?? null, $userId]); } } elseif (str_starts_with($event['type'], 'customer.subscription.')) { syncSubscriptionFromStripe($object); } elseif (in_array($event['type'], ['invoice.payment_failed', 'invoice.paid'], true)) { $customer = $object['customer'] ?? ''; if ($customer !== '') { $status = $event['type'] === 'invoice.paid' ? 'active' : 'past_due'; $db->prepare("UPDATE users SET subscription_status=? WHERE stripe_customer_id=?")->execute([$status, $customer]); $db->prepare("UPDATE subscriptions SET status=?,updated_at=? WHERE stripe_customer_id=?") ->execute([$status, time(), $customer]); } } $db->prepare("INSERT OR IGNORE INTO stripe_events (event_id,event_type,received_at) VALUES (?,?,?)") ->execute([$event['id'], $event['type'], time()]); jsonResponse(['received' => true]);