Emails and notices
The acknowledgment, trial, renewal, price-change and cancellation emails automatic-renewal laws require, when each must be sent, how to check your templates, and how Checkbox Notices can send them for you.
Automatic-renewal laws do not stop at the checkout. Depending on the plan and the subscriber's state, you must send:
| When | Check | |
|---|---|---|
| Acknowledgment | Right after sign-up: the terms, the cancellation policy and how to cancel | confirmation.* |
| Trial ending | Before a free trial converts to paid, inside each state's window | reminder.trial_ending |
| Renewal reminder | Before renewals of longer terms (a year or more; shorter in some states) | reminder.annual_renewal |
| Yearly terms | Once a year for monthly or other short-term plans, in some states | reminder.annual_terms_notice |
| Price change | Before a higher price is first charged | reminder.price_change |
| Cancellation confirmation | After a subscriber cancels | cancel.confirmation |
When to send them
Windows differ by state and plan (trial length, term length, payment method). Ask for the exact dates for a subscription; Checkbox intersects every applicable state's window and, where they conflict, returns the fewest sends that satisfy all of them:
curl https://app.checkbox.site/v1/checks/notice_schedule \
-u "$CHECKBOX_SECRET_KEY:" \
-H "Content-Type: application/json" \
-d '{
"terms": {
"merchant_name": "Joybox",
"price": 99,
"interval": "year",
"trial_days": 35,
"cancel_url": "https://joybox.example/account/cancel"
},
"start_date": "2026-11-02",
"jurisdictions": ["US-CA", "US-NY"]
}'import Checkbox from '@checkbox-site/cli';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const schedule = await checkbox.checks.noticeSchedule({
terms: { merchant_name: 'Joybox', price: 99, interval: 'year', trial_days: 35, cancel_url: 'https://joybox.example/account/cancel' },
start_date: '2026-11-02',
jurisdictions: ['US-CA', 'US-NY'],
});
for (const n of schedule.notices) console.log(n.kind, n.send_date, n.citations.join('; '));import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
schedule = checkbox.checks.notice_schedule(
terms={"merchant_name": "Joybox", "price": 99, "interval": "year", "trial_days": 35,
"cancel_url": "https://joybox.example/account/cancel"},
start_date="2026-11-02",
jurisdictions=["US-CA", "US-NY"],
)
for n in schedule["notices"]:
print(n["kind"], n["send_date"], "; ".join(n["citations"]))Each notice has send_date / send_at, the window (window_opens_at … window_closes_at), the jurisdictions and citations it satisfies.
Check a template
curl https://app.checkbox.site/v1/checks/email \
-u "$CHECKBOX_SECRET_KEY:" \
-H "Content-Type: application/json" \
-d '{
"kind": "trial_reminder",
"subject": "Your trial ends soon",
"text": "Hi! Your free trial ends on December 4. Thanks for trying Joybox.",
"terms": {
"merchant_name": "Joybox",
"price": 19.99,
"interval": "month",
"trial_days": 14,
"cancel_url": "https://joybox.example/account/cancel"
}
}'import Checkbox from '@checkbox-site/cli';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const result = await checkbox.checks.email({
kind: 'trial_reminder',
subject: 'Your trial ends soon',
text: 'Hi! Your free trial ends on December 4. Thanks for trying Joybox.',
terms: { merchant_name: 'Joybox', price: 19.99, interval: 'month', trial_days: 14, cancel_url: 'https://joybox.example/account/cancel' },
});
console.log(result.verdict);
console.log(result.template.subject);
console.log(result.template.merge_tags);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
result = checkbox.checks.email(
kind="trial_reminder",
subject="Your trial ends soon",
text="Hi! Your free trial ends on December 4. Thanks for trying Joybox.",
terms={"merchant_name": "Joybox", "price": 19.99, "interval": "month", "trial_days": 14,
"cancel_url": "https://joybox.example/account/cancel"},
)
print(result["verdict"])
print(result["template"]["subject"])
print(result["template"]["merge_tags"])When the email fails, template holds a compliant subject, text and HTML with merge tags (for example {{trial_end_date}}) for you to fill per subscriber. Email checks judge content; real send timing is judged by monitoring.
Let Checkbox see the real emails
- BCC each lifecycle email to the site's inbound address (
install.inbound_emailon the site), labelled with its kind so Checkbox never has to guess: plus-address it (<key>+annual_terms@…) or add the headerX-Checkbox-Kind: annual_terms. Kinds:acknowledgment,trial_reminder,renewal_reminder,price_change,annual_terms,charge_notice,cancellation_confirmation(the same namescheckEmail,verifyTaskand the plan use;trial_endingis accepted as an alias, as in Notices). Unlabelled mail is classified by its content. - Run a test subscription: Checkbox subscribes with its own inbox and moves a test clock through trial end and renewal, so it receives every email your code sends and knows exactly when it was sent.
Checkbox Notices
Checkbox can send the required notices for you, from your brand, timed from the legal catalog, and record each delivery as evidence. Turn it on per site with updateNoticeSettings (live mode needs an activated account). Notices send email only: where New York requires reminders "in the manner the consumer selected", the plan asks you to attest that subscribers chose email; and New York's price-increase consent or refund right cannot be provided by any notice, so it stays a question for you.
Checkbox is compliance software, not a law firm; nothing in these docs is legal advice (details). For AI agents: every page is available as Markdown at the same URL plus .md; the index is /llms.txt.