diff --git a/src/client/features/onboarding/OnboardingChatConversation.tsx b/src/client/features/onboarding/OnboardingChatConversation.tsx index 04eb04f..248fa0f 100644 --- a/src/client/features/onboarding/OnboardingChatConversation.tsx +++ b/src/client/features/onboarding/OnboardingChatConversation.tsx @@ -11,7 +11,10 @@ import { useStickToBottom } from "@/client/components/chat/useStickToBottom"; import { captureClientEvent } from "@/client/lib/posthog"; import { getStandardErrorMessage } from "@/client/lib/error-messages"; import { buildCheckoutSuccessUrl } from "@/client/features/billing/checkout-url"; -import { AUTUMN_PAID_PLAN_ID } from "@/shared/billing"; +import { + AUTUMN_CHECKOUT_SESSION_PARAMS, + AUTUMN_PAID_PLAN_ID, +} from "@/shared/billing"; import { FREE_ONBOARDING_QUESTION_LIMIT } from "@/shared/onboardingChat"; import { ChatComposer, @@ -131,6 +134,7 @@ export function OnboardingChatConversation({ planId: AUTUMN_PAID_PLAN_ID, redirectMode: "always", successUrl: buildCheckoutSuccessUrl("/onboarding?step=3"), + checkoutSessionParams: AUTUMN_CHECKOUT_SESSION_PARAMS, }); } catch (checkoutErr) { setCheckoutError( diff --git a/src/routes/_app/billing.tsx b/src/routes/_app/billing.tsx index 2b3699f..d64c0d4 100644 --- a/src/routes/_app/billing.tsx +++ b/src/routes/_app/billing.tsx @@ -13,6 +13,7 @@ import { parseTopUpAmount } from "@/client/features/billing/HostedBillingContent import { getBillingRouteState } from "@/client/features/billing/route-state"; import { getCustomerPlanStatus } from "@/client/features/billing/plan-detection"; import { + AUTUMN_CHECKOUT_SESSION_PARAMS, AUTUMN_PAID_PLAN_ID, BILLING_ROUTE, AUTUMN_SEO_DATA_BALANCE_FEATURE_ID, @@ -103,6 +104,7 @@ function BillingPage() { planId: AUTUMN_PAID_PLAN_ID, redirectMode: "always", successUrl: buildCheckoutSuccessUrl(BILLING_ROUTE), + checkoutSessionParams: AUTUMN_CHECKOUT_SESSION_PARAMS, }); } @@ -282,6 +284,7 @@ function BillingPage() { planId: AUTUMN_SEO_DATA_TOP_UP_PLAN_ID, redirectMode: "always", successUrl: window.location.href, + checkoutSessionParams: AUTUMN_CHECKOUT_SESSION_PARAMS, featureQuantities: [ { featureId: AUTUMN_SEO_DATA_TOPUP_BALANCE_FEATURE_ID, diff --git a/src/routes/_authenticated.subscribe.tsx b/src/routes/_authenticated.subscribe.tsx index 4f12197..37326f0 100644 --- a/src/routes/_authenticated.subscribe.tsx +++ b/src/routes/_authenticated.subscribe.tsx @@ -12,6 +12,7 @@ import { getCustomerPlanStatus } from "@/client/features/billing/plan-detection" import { normalizeAuthRedirect } from "@/lib/auth-redirect"; import { useCanManageBilling } from "@/client/features/team/organizationQueries"; import { + AUTUMN_CHECKOUT_SESSION_PARAMS, AUTUMN_MANAGED_ACCESS_FEATURE_ID, AUTUMN_PAID_PLAN_ID, } from "@/shared/billing"; @@ -200,6 +201,7 @@ function SubscribePage() { planId: AUTUMN_PAID_PLAN_ID, redirectMode: "always", successUrl: successUrl.toString(), + checkoutSessionParams: AUTUMN_CHECKOUT_SESSION_PARAMS, }); } catch (err) { setError( diff --git a/src/shared/billing.ts b/src/shared/billing.ts index a539343..d1bd696 100644 --- a/src/shared/billing.ts +++ b/src/shared/billing.ts @@ -16,6 +16,16 @@ export const AUTUMN_SEO_DATA_CREDITS_PER_USD = 1000; export const SEO_DATA_COST_MARKUP = 1.28; export const LOW_CREDITS_THRESHOLD_USD = 0.25; +// Passed through to Stripe's checkout.sessions.create so checkout collects the +// legal business name, tax ID (EU VAT etc.), and full billing address — makes +// invoices valid for business customers. Display only, no Stripe Tax. Stripe +// requires customer_update.name "auto" to collect tax IDs for an existing customer. +export const AUTUMN_CHECKOUT_SESSION_PARAMS = { + tax_id_collection: { enabled: true }, + billing_address_collection: "required", + customer_update: { name: "auto", address: "auto" }, +} as const; + export function roundUsdForBilling(value: number) { return Math.round(value * 100000) / 100000; }