ensureCustomer($email, $userId); $baseUrl = (dbnToolsIsHttps() ? 'https://' : 'http://') . ($_SERVER['HTTP_HOST'] ?? 'tools.dobetternorge.no'); $successUrl = $baseUrl . '/billing.php?status=success&session_id={CHECKOUT_SESSION_ID}'; $cancelUrl = $baseUrl . '/pricing.php?status=canceled'; $isSub = StripeClient::isSubscriptionSku($sku); $credits = $isSub ? 0 : StripeClient::topupCredits($sku); $metadata = [ 'user_id' => (string)$userId, 'sku' => $sku, 'catalog_version' => PricingCatalog::VERSION, ]; if ($isSub) { $metadata['tier'] = $sku; } else { $metadata['credits'] = (string)$credits; } $params = [ 'mode' => $isSub ? 'subscription' : 'payment', 'customer' => $customerId, 'success_url' => $successUrl, 'cancel_url' => $cancelUrl, 'line_items' => [[ 'price' => StripeClient::priceId($sku), 'quantity' => 1, ]], 'metadata' => $metadata, 'allow_promotion_codes' => true, 'billing_address_collection' => 'auto', 'locale' => 'auto', 'automatic_tax' => ['enabled' => false], ]; if ($isSub) { FreeTier::ensureRow($userId); $detail = FreeTier::balanceDetail($userId); $params['subscription_data'] = [ 'metadata' => $metadata, ]; $trialDays = PricingCatalog::planTrialDays($sku); if ($trialDays > 0 && empty($detail['trial_started_at'])) { $params['subscription_data']['trial_period_days'] = $trialDays; $params['subscription_data']['trial_settings'] = [ 'end_behavior' => ['missing_payment_method' => 'cancel'], ]; } $params['payment_method_collection'] = 'always'; } else { $params['payment_intent_data'] = [ 'metadata' => $metadata, ]; } $session = $stripe->createCheckoutSession($params); $url = (string)($session['url'] ?? ''); if ($url === '') { dbnToolsError('Stripe did not return a checkout URL.', 502, 'stripe_no_url'); } dbnToolsRespond(['ok' => true, 'url' => $url, 'session_id' => (string)($session['id'] ?? '')]); } catch (Throwable $e) { error_log('[stripe-checkout] ' . $e->getMessage()); dbnToolsError('Could not start checkout: ' . $e->getMessage(), 500, 'stripe_failed'); }