# How to make Stripe Checkout auto-renewal compliant

> What Stripe Checkout shows by default for a subscription, what ROSCA and state automatic-renewal laws additionally require, and the exact Checkout Session parameters, page changes, emails and portal settings that close each gap.

Stripe Checkout is the fastest way to sell a subscription, but its default subscription page was not designed around
automatic-renewal law. This guide maps each legal requirement to what Stripe shows and to the change that closes the
gap. Every requirement is from Checkbox's [legal catalog](https://checkbox.site/docs/concepts/requirements), with its citation.

## What Stripe shows by default {#defaults}

For a `mode: "subscription"` session, Stripe's hosted page shows the product, the recurring price and interval in the
order summary, a trial line when there is a trial, and a short authorization statement near the button. It does not, by
default:

- state that the subscription **continues until cancelled** and **how to cancel**;
- ask for **consent to the renewal terms** with a checkbox the customer must tick;
- make the terms **conspicuous** — Stripe's custom text is small and grey and you cannot restyle it.

## The gaps and the fixes {#gaps}

| Requirement | Citation (examples) | Stripe default | Fix |
|---|---|---|---|
| Disclose that it renews until cancelled, the price, frequency, term, trial terms and how to cancel, before billing information | 15 U.S.C. § 8403(1); Cal. Bus. & Prof. Code § 17602(a)(1); N.Y. Gen. Bus. Law § 527-a(1)(a) | Price and interval only | `custom_text.submit.message` with the full disclosure |
| Affirmative (express) consent to the renewal terms before charging | 15 U.S.C. § 8403(2); Cal. Bus. & Prof. Code § 17602(a)(2), (a)(4); N.Y. Gen. Bus. Law § 527-a(1)(b) | None | `consent_collection.terms_of_service: "required"` and `custom_text.terms_of_service_acceptance.message` stating the terms |
| Clear and conspicuous, in visual proximity to the consent | Cal. Bus. & Prof. Code § 17601(c), § 17602(a)(1) | Small grey text | Also show the set-off disclosure on your own page before the redirect |
| Acknowledgment the consumer can keep, with terms and how to cancel | Cal. Bus. & Prof. Code § 17602(a)(3); N.Y. Gen. Bus. Law § 527-a(1)(c) | Stripe's receipt (no renewal terms or cancellation instructions) | Send an acknowledgment from your `checkout.session.completed` handler |
| Trial-ending and renewal notices inside each state's window | Cal. Bus. & Prof. Code § 17602(b); N.Y. Gen. Bus. Law § 527-a(1)(f), (h) | Optional trial reminder 7 days before | Send them on the dates from `checkNoticeSchedule` |
| Simple online cancellation | 15 U.S.C. § 8403(3); Cal. Bus. & Prof. Code § 17602(d); N.Y. Gen. Bus. Law § 527-a(1)(d) | Customer portal, if enabled | Enable cancellation in the portal and link it from the account page |

## The Checkout Session params {#params}

Checkbox generates the wording from your real terms and verifies it with the rules engine. Ask for it with your own
params (here a 14-day trial at $19.99 a month):

```bash
cat > session.json <<'EOF'
{
  "mode": "subscription",
  "line_items": [{ "price_data": { "currency": "usd", "unit_amount": 1999, "recurring": { "interval": "month" }, "product_data": { "name": "Joybox Pro" } }, "quantity": 1 }],
  "subscription_data": { "trial_period_days": 14 },
  "success_url": "https://joybox.example/welcome"
}
EOF
checkbox check stripe-session --file session.json --merchant-name Joybox \
  --cancel-url https://joybox.example/account/cancel --offline
```

The correction adds:

```json title="correction.patch (abridged)"
[
  { "op": "add", "path": "/consent_collection", "value": { "terms_of_service": "required" } },
  {
    "op": "add",
    "path": "/custom_text",
    "value": {
      "submit": { "message": "Your free trial lasts 14 days, then $19.99 every month. Cancel before the trial ends and you won't be charged. Your Joybox subscription automatically renews every month at $19.99 (plus applicable taxes) until you cancel. You can cancel anytime online at https://joybox.example/account/cancel; …" },
      "terms_of_service_acceptance": { "message": "I agree that after my 14-day free trial, my Joybox subscription renews automatically every month at $19.99 (plus applicable taxes) until I cancel, and I understand I can cancel anytime online at https://joybox.example/account/cancel." }
    }
  }
]
```

`consent_collection.terms_of_service` requires a Terms of Service URL in your Stripe settings (Dashboard → Settings →
Public details).

## Why one check stays "needs review" {#conspicuous}

Even with the params above, Checkbox reports `signup.disclosure.conspicuous` as `needs_review` on any Stripe-hosted
page: whether text is clear and conspicuous depends on its size, contrast and setting-off, and Stripe renders custom
text in its own small grey style. California defines "clear and conspicuous" as larger type, contrasting type, font or
color, or text set off by symbols — legible is not enough (Cal. Bus. & Prof. Code § 17601(c)). The robust fix is to
show the same disclosure on your own page, next to the button that starts checkout, set off in a box at body size or
larger. [Checkbox Elements](https://checkbox.site/docs/elements) renders exactly that.

## After checkout {#after-checkout}

- **Acknowledgment:** Stripe's receipt does not restate the renewal terms or how to cancel. Send your own from the
  `checkout.session.completed` webhook; check the template with [`checkEmail`](https://checkbox.site/docs/api/checks#checkEmail)
  (`kind: "acknowledgment"`).
- **Reminders:** get the dates for your plan from [`checkNoticeSchedule`](https://checkbox.site/docs/api/checks#checkNoticeSchedule).
- **Cancellation:** enable cancellation in the [customer portal](https://checkbox.site/docs/guides/stripe-customer-portal) or use the
  [hosted cancellation page](https://checkbox.site/docs/guides/cancellation#hosted).
- **Prove it end to end:** a [test subscription](https://checkbox.site/docs/guides/test-runs) runs the whole lifecycle in Stripe test mode
  with a test clock.

## Do it with your coding agent {#with-ai}

```text title="Prompt"
Make our Stripe Checkout subscription flow compliant with automatic-renewal laws using Checkbox
(https://checkbox.site/docs/learn/stripe-checkout-auto-renewal-compliance.md). Preflight the exact params we pass to
stripe.checkout.sessions.create with `checkbox check stripe-session --json`, apply correction.patch, add the
disclosure on our pricing page with <checkbox-disclosure>, and send an acknowledgment email from our
checkout.session.completed handler. Re-check until everything passes or only needs_review items remain.
```

> **Not legal advice**
>
> A practical guide, not legal advice. Requirements are drafted from the cited statutes and pending attorney review.
