Compliance & DNC engine
TCPA, GDPR, DMARC, LinkedIn caps, WhatsApp opt-in — all enforced before send.
- ·Cross-channel DNC with wildcard '*' support
- ·Quiet hours in the operator's timezone, not yours
- ·STOP / UNSUBSCRIBE auto-opt-out on every inbound
- ·LinkedIn weekly invite cap enforced per account
- ·WhatsApp template approval gating
The detail.
One gate, every channel
Before any worker dispatches a touch, evaluate_send() checks the account status, quiet hours in the recipient's local time, the DNC list (specific channel + the wildcard '*'), the per-account min-gap, the hourly cap, and the daily cap. Skip the gate? You can't — the dispatcher won't run a worker that doesn't call it.
Auto opt-out, not opt-out-when-someone-remembers
Every inbound message runs through detect_opt_out() with the channel-specific keyword set (STOP, STOPALL, UNSUBSCRIBE for SMS / WhatsApp; phrase matching for email). A match writes a DNC row immediately. The next outbound to that recipient — on any channel — is blocked.
Audit trail, not a black box
Every block logs the reason (dnc_listed, quiet_hours, hourly_limit, …) and the suggested retry-after window. When an operator asks 'why didn't this go?' the answer is one click into the touch detail.
vs. point-tool DNC managers / spreadsheets
The honest comparison — what changes when you switch.
Four things you won’t find elsewhere.
One gate, every worker
evaluate_send() is the single chokepoint. Email worker, call dispatcher, LinkedIn worker, SMS sender, WhatsApp dispatcher — they all call the same function. Skipping the gate is impossible by design.
Wildcard '*' DNC
A DNC entry with channel='*' opts the lead out of every channel simultaneously. STOP on SMS protects email, calls, LinkedIn, and WhatsApp at the same time.
Recipient-timezone quiet hours
We compute quiet hours from the lead's country code (E.164) or stored timezone — not the operator's office hours. A 9 AM call in Berlin doesn't fire at 4 AM in New Delhi.
Reason codes, not 'rejected'
Every block returns dnc_listed · quiet_hours · hourly_limit · daily_limit · channel_paused · template_unapproved with a retry-after hint, so the operator knows what to fix.
How teams actually use this.
TCPA officer audits a 6-month outbound run
Filter /call/cdr by outcome=blocked across the 6-month window. Each row shows the lead, the channel, the block reason, the operator who triggered the dial, and any force-flag overrides. The export goes to the auditor as a CSV; zero gaps, zero spreadsheet reconciliation.
STOP on WhatsApp protects every channel instantly
A lead replies STOP to a Day-3 WhatsApp template. The classifier writes a DNC row with channel='*' before the operator triages the inbox. The Day-5 SMS, Day-7 call, and Day-10 LinkedIn DM scheduled for that lead all skip with reason=dnc_listed. The audit log records it for the compliance review.
DLT-required India SMS attempt with no registration
An operator builds an SMS step targeting Indian numbers but the workspace has no DLT entity registered. evaluate_send() returns reason=dlt_not_registered with a one-click link to /settings/compliance/dlt. The send never hits the carrier API, so there's no carrier-side rejection log to clean up later.
The full story.
Compliance is the most expensive thing to retrofit into an outbound stack. TCPA fines run $500-$1,500 per violating call; GDPR penalties scale to 4% of global revenue; LinkedIn account suspensions take weeks to recover. The economics make it cheaper to enforce compliance at the dispatcher gate, before any carrier API is called, than to clean up after the fact. Autocloz's evaluate_send() function is that gate — every worker on every channel calls it before dispatch, and it returns a structured reason code on any block.
The wildcard DNC pattern (channel='*') is the load-bearing primitive. When a recipient says STOP on SMS, the right behaviour is not 'opt them out of SMS' — it's 'opt them out of everything you might do to them next'. Autocloz's DNC table supports per-channel rows (channel='sms') and wildcard rows (channel='*') simultaneously; the gate checks both. STOP on any channel writes a wildcard row by default. The operator can downgrade to per-channel via Settings if they have a documented business reason.
Quiet hours are usually implemented backwards. Most tools enforce quiet hours in the sender's timezone — fine for a Bay-Area SDR pinging other Bay-Area buyers, useless for a B2B agency selling into APAC. Autocloz computes the recipient's timezone from the E.164 country code (with a per-lead override available from the lead profile), so a 9 AM call in Berlin fires at 9 AM Berlin time — not 9 AM your time, which would be 4 AM theirs.
India-specific compliance is its own surface. DLT (Distributed Ledger Technology) registration is mandatory before any SMS can hit Indian numbers; principal entity, header, and template all need approval. WhatsApp Business templates need Meta approval per market. Autocloz checks both at the gate — a DLT-unregistered SMS step returns dlt_not_registered with a one-click link to register; a WhatsApp template not yet Meta-approved returns whatsapp_template_unapproved with the template review link. No silent failures, no carrier-side rejections to chase.