Compliance: TCPA, CAN-SPAM, GDPR, CASL
Marketing compliance is one of the few places where "good enough" can mean class-action lawsuits, regulatory fines, or your sender domain getting black-holed. Engage was built with compliance enforced at queue time and dispatch time so you cannot ship a non-compliant send by accident.
Not legal advice
This doc explains how Engage implements compliance controls. It is not legal advice. For your specific jurisdiction and use case, consult a compliance attorney.
TCPA (US SMS)
The Telephone Consumer Protection Act regulates SMS marketing in the US. Engage implements:
STOP-Keyword Handling
The Telnyx webhook handler runs synchronously on every inbound SMS. If the message body matches any of:
STOPSTOPALLCANCELUNSUBSCRIBEENDQUIT
(case-insensitive, trimmed), Engage immediately:
- Inserts a global SMS suppression for the sender's phone number.
- Writes an
engage_compliance_audit_logrow. - Returns the carrier-required acknowledgment SMS ("You have been unsubscribed. Reply START to resubscribe.").
The suppression is global - meaning no operator on the platform can SMS that number again - because TCPA requires honoring STOP across the sending number, not just the sending campaign.
Quiet Hours
The dispatcher enforces 9 PM - 9 AM recipient-local quiet hours on SMS. If customers.timezone is set, that timezone is used; otherwise the subaccount default applies.
Sends that would land inside quiet hours are held in the queue until the 9 AM boundary opens. This is enforced at dequeue, not at send schedule - so a campaign scheduled for 8 PM that takes 3 hours to queue still respects quiet hours.
Double Opt-In States
Some US states require double opt-in for marketing SMS (CA, MA, FL, WA, OK, and a growing list). Engage records the opt-in method on every subscription_preferences row:
| Method | Meaning |
|---|---|
single | Rider checked a box at signup |
double | Rider confirmed via a second SMS or email link |
imported | Rider was in an imported list - use with caution, requires prior consent paper trail |
transactional_inferred | Rider is on operational SMS but never explicitly opted into marketing |
For operators in double-opt-in states, configure your signup flow to send the confirmation SMS and only mark opt_in_method = "double" after the rider clicks the confirmation link. Engage will refuse marketing SMS sends to anyone whose opt_in_method does not meet the state's bar.
10DLC
US carriers require SMS senders to register their brand and use cases under the 10DLC framework. Levy sponsors the brand registration centrally - your subaccount is covered. Contact support if your subaccount is brand new and you don't see SMS sending enabled.
CAN-SPAM (US Email)
CAN-SPAM is the US email marketing law. It is less aggressive than TCPA but still mandatory.
Required Footer Elements
Every marketing email must include:
- Your legal address. Rendered from
subaccounts.legal_address. If this field is empty, you cannot publish a campaign - Engage blocks the publish action and tells you what's missing. - An unsubscribe link. Rendered from
{{unsubscribe.url}}. Pre-built templates include this automatically; custom templates that strip it fail validation.
List-Unsubscribe Headers
Every email dispatched by Engage includes:
List-Unsubscribe: <https://[your-domain]/api/engage/u/[token]>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
These headers enable the "Unsubscribe" button at the top of Gmail and other modern mail clients. When a rider clicks that button, Gmail POSTs to your URL, and Engage processes the unsubscribe within seconds. See Preference Center for how the unsubscribe flow works end-to-end.
The List-Unsubscribe-Post: List-Unsubscribe=One-Click header is the RFC 8058 marker that tells Gmail your endpoint is one-click safe (no confirmation page required).
Subject Line Truth
CAN-SPAM requires subjects that "accurately reflect the content of the message." Engage does not enforce this programmatically - you have to write honest subjects. Misleading subjects ("RE: your account" when it's a promo) are how you end up in front of the FTC.
GDPR (EU)
The General Data Protection Regulation governs personal data of EU residents.
Consent Records
Every consent decision is recorded immutably. When a rider:
- Checks a marketing-consent box at signup
- Toggles a channel in the preference center
- Unsubscribes from a one-click link
- Asks support to opt them out
...Engage writes a row to engage_compliance_audit_log with:
- Customer ID
- The change (channel, old value, new value)
- Timestamp
- IP address (if available)
- User agent (if available)
These rows are append-only - they cannot be edited or deleted.
Right to Be Forgotten
When a rider exercises GDPR Article 17 (RTBF):
- The
customersrow is markedis_deleted = true(or hard-deleted, depending on your subaccount's retention policy). - All active
journey_runsfor that customer getexited_atset immediately - no more sends will fire. - PII fields in
engagement_eventsare nulled out (the event timestamps remain to preserve aggregate analytics). - The audit log entry for the RTBF action itself is retained (Article 17 explicitly permits this).
The customer ID becomes inert. No future sends are possible.
Lawful Basis
The lawful basis for marketing sends is consent - which means you need an opt-in, not just a "they signed up so they implicitly consented" interpretation. Engage's default flow requires explicit consent capture at signup. If you import an external list and mark them imported without explicit consent, you are taking on GDPR risk that Engage cannot mitigate.
Data Residency
EU rider data is stored in EU Postgres regions if your subaccount is configured for EU residency. Contact support if your fleet is EU-based and you have not confirmed residency.
CASL (Canada)
The Canadian Anti-Spam Legislation is stricter than CAN-SPAM and requires express consent.
Express Consent
You need a positive, documented consent action - "they checked a box" is the minimum. Implied consent (e.g., "they did business with us in the last two years") is permitted in narrow cases but should not be your default.
Engage records opt_in_method on every subscription_preferences row. For Canadian riders, that value should be single or double, never imported (without an actual paper trail).
10-Year Audit Retention
CASL requires keeping consent records for 10 years. Engage retains engage_compliance_audit_log rows indefinitely by default. Do not change that without legal review.
Unsubscribe Within 10 Days
CASL requires honoring unsubscribes within 10 business days. Engage honors them immediately (within seconds), so this is satisfied by default.
Other Frameworks
| Framework | Where it applies | Engage support |
|---|---|---|
| PECR | UK email/SMS | Inherited from GDPR controls; UK riders treated the same as EU |
| LGPD | Brazil | Same controls as GDPR; consent records sufficient |
| CPRA | California | RTBF + opt-out of sale; opt-out signal honored automatically |
| VCDPA | Virginia | Same opt-out path as CPRA |
| CTDPA | Connecticut | Same as VCDPA |
How Engage Enforces Compliance
Several layers, each non-overrideable:
At Publish Time
Cannot publish a campaign if:
- The template is missing
{{unsubscribe.url}}(CAN-SPAM) - The template is missing
{{subaccount.legal_address}}(CAN-SPAM) subaccounts.legal_addressis empty- The audience segment includes riders without channel consent and you forgot to filter them out
At Queue Time
For every send:
- Suppression list lookup
- Channel consent check
- Quiet-hours check (SMS only)
At Dispatch Time
For every send:
- One last suppression-list check (handles "unsubscribed while in queue" edge case)
- List-Unsubscribe headers attached
- DKIM signature applied via Postmark
At Webhook Time
For every webhook:
- STOP keyword detection
- Bounce / complaint processing
- Audit log row written
Audit Trail
The engage_compliance_audit_log table is your compliance evidence. Export it via:
- Engage > Settings > Compliance > Export Audit Log (CSV)
- The same data is queryable via the API
If you get a regulatory request, this log is what you produce. Keep at least 10 years of history.
Best Practices
- Capture consent at signup explicitly. A checkbox that says "Send me promotions and updates" is fine. A pre-checked box is not (under most jurisdictions).
- Don't backfill consent. If you don't have a paper trail that a rider opted in, treat them as not-opted-in until they tell you otherwise.
- Audit your imported lists. If you migrated from another tool, the rider's prior consent record matters. Engage marks imports as
importedfor visibility - filter those out of segments by default. - Test the unsubscribe flow. Once a quarter, send yourself a test email and click the Gmail "Unsubscribe" header button. Confirm you get suppressed within 5 seconds. If not, there's a webhook or DNS issue to fix.
Need Help?
For compliance help, contact support@levyelectric.com. For legal questions specific to your jurisdiction, consult a compliance attorney.