Cold SMS Engine — Iron Automations Build
Architecture
Lead Source (Iron ACQ / CSV / scraper)
→ Postgres/Supabase (leads table, dedupe, status)
→ Python Dispatcher (cron every 5 min)
→ Slot check: morning | midday | evening window active?
→ Pull N leads due for next touch
→ Signal House API (send SMS)
→ Log to `sms_events` table
→ Push to GHL sub-account as contact+conversation (native threading)
→ Inbound reply webhook (Signal House → FastAPI)
→ Classify: positive | negative | stop | neutral
→ Positive → create GHL opportunity, notify rep
→ Stop → blacklist, opt-out table
Why Python (not n8n)
n8n hit the wall at ~5K sends/day — visual nodes choke on batch logic, error recovery is painful, version control is JSON-in-Git hell. Python sequencer:
- Cron-driven, not webhook-driven → deterministic
- Slot windows prevent TCPA violations (no sends before 9am / after 8pm local)
- Retries + dead-letter queue native
- Git-diffable, testable
Slot Logic
SLOTS = {
"morning": (9, 11),
"midday": (12, 14),
"evening": (16, 19),
}
# Each lead gets rotated across slots to avoid same-hour sends
# Leads bucketed by timezone from area code lookup
Touchpoint Sequence (proven)
- T+0: Permission ask ("mind if I send info?")
- T+3min: Human-mimicking followup (Eugene Katsen gem — 3x reply boost)
- T+1d: Value drop
- T+3d: Soft CTA
- T+7d: Hard CTA
- T+14d: Breakup message
Telephony: Signal House
- Cheaper than Twilio at volume
- Pre-registered numbers with warm reputation
- Native A2P submission from portal
- Python SDK works; raw REST also fine
GHL Threading
Every SMS event POSTs to GHL via public API to create:
- Contact (if new)
- Conversation message (inbound/outbound)
- Opportunity (when positive classifier fires)
This makes the GHL sub-account the source of truth for reps, while Python remains the source of truth for sending logic.
Numbers
- Cost-per-interested-lead: $3.31
- CPA (booked call): $29
- CAC (closed deal): $234
- Show rate: 12.5%
- Throughput: 1000 new leads/day
- Avg 5 SMS segments per conversation before decision