Charging a consumer at a higher price than they originally authorized — with no advance notice — violates the FTC Negative Option Rule (2025) requirement that material changes to subscription terms be communicated before they take effect. California ARL and EU Consumer Rights Directive 2011/83/EU both require that price increases be disclosed with sufficient advance notice for the consumer to cancel before the new rate applies. Silent price increases processed through Stripe Subscription Schedules without customer notification are the most common way well-intentioned teams inadvertently create regulatory exposure during pricing strategy updates.
Info because the violation requires a price change event to occur — no prior price change means no current violation — but the absence of a notification mechanism means any future price change immediately creates regulatory liability.
Handle customer.subscription.updated to detect price changes and trigger a 30-day-advance notification email. In app/api/webhooks/stripe/route.ts:
const priceChanged = prevSub?.items &&
newSub.items.data[0]?.price.id !== prevSub.items.data?.[0]?.price?.id
if (priceChanged && email) {
await sendEmail({
to: email,
subject: 'Important: Your subscription price is changing',
template: 'price-change-notification',
data: {
oldPrice: (prevSub.items.data?.[0]?.price?.unit_amount ?? 0) / 100,
newPrice: (newSub.items.data[0]?.price.unit_amount ?? 0) / 100,
effectiveDate: formatDate(newSub.current_period_end),
cancelUrl: `${process.env.NEXT_PUBLIC_APP_URL}/settings/billing`,
},
})
}
For planned increases, use Stripe Subscription Schedules with a future-dated phase so the notification goes out before the phase activates — not simultaneously with the price change.
ID: subscription-compliance.renewal.price-change-notification
Severity: info
What to look for: Check the application's handling of Stripe price changes. Look for webhook handlers for customer.subscription.updated that check whether items.data[0].price changed, and whether a price-change notification email is triggered. Also check Stripe's built-in price change notification: when you update a price in Stripe, you can optionally notify affected customers — verify whether this is configured. Look for any price migration logic in the codebase: if the application has ever changed prices, how was the customer communication handled? Check for phase objects in stripe.subscriptions.list — subscription schedules with multiple phases indicate a planned price change. If phases are set up, verify that affected customers receive advance notice. Count all instances found and enumerate each.
Pass criteria: When a subscription price increases, affected customers are notified before the new rate takes effect. Notification includes the old price, the new price, the effective date, and the option to cancel before the new rate applies. At least 1 implementation must be confirmed.
Fail criteria: No mechanism exists to notify customers of price changes before they are charged at the new rate. Price changes are applied silently on the next billing cycle.
Skip (N/A) when: The application has no paid subscription features whatsoever (entirely free or one-time purchase only). Do NOT skip simply because no price change has occurred yet or there is no Stripe Subscription Schedule configured — any paid subscription product that lacks a price-change notification mechanism should fail this check, not skip it. Absence of prior price increases is not grounds to skip; the question is whether a mechanism exists for when prices do change.
Detail on fail: Example: "No customer.subscription.updated handler for price changes. Stripe subscription schedules are in use for a planned price increase but no customer notification email is configured." or "Price change notification is not implemented. Stripe's built-in price change email is not enabled in Dashboard settings.".
Remediation: Notify customers of price changes at least 30 days in advance:
// app/api/webhooks/stripe/route.ts
if (event.type === 'customer.subscription.updated') {
const newSub = event.data.object
const prevSub = event.data.previous_attributes
// Check if the price changed
const priceChanged = prevSub?.items &&
newSub.items.data[0]?.price.id !== prevSub.items.data?.[0]?.price?.id
if (priceChanged) {
const customer = await stripe.customers.retrieve(newSub.customer as string)
const email = 'email' in customer ? customer.email : null
if (email) {
await sendEmail({
to: email,
subject: 'Important: Your subscription price is changing',
template: 'price-change-notification',
data: {
oldPrice: (prevSub.items.data?.[0]?.price?.unit_amount ?? 0) / 100,
newPrice: (newSub.items.data[0]?.price.unit_amount ?? 0) / 100,
effectiveDate: formatDate(newSub.current_period_end),
cancelUrl: `${process.env.NEXT_PUBLIC_APP_URL}/settings/billing`,
},
})
}
}
}
For planned price increases, send the notification well in advance (30+ days) using Stripe Subscription Schedules rather than immediate price updates.