Buyer Blast Process Hub

This hub covers the engine-level mechanics of the 4-channel buyer blast system. It is the technical deep-dive companion to dispo-lifecycle, which covers the lifecycle orchestration. Read this hub when you need to understand per-channel scripts, InvestorBase scoring details, dedup logic, or failure recovery for the blast system. Skill wrapper: dispo-blast.

⚠️ NEVER bypass —dry-run

All blast commands MUST include --dry-run unless Henry has given explicit blast authorization for that deal in this session. Live blasts are irreversible.

Quick reference

FieldValue
StagesPre-blast preview → 4 history checks → Channel coordination → Per-channel send → Post-blast audit
Primary agent_summary
Supporting agents_summary (IB scoring), _summary (reply routing)
Agent handoff chaindispo (blast coordinator) → atlas (IB score) → dispo-send.js → SalesMsg/OpenPhone → aurora (inbound replies)
Compliance gates listdefer to compliance-gates
Skills invokeddispo-blast
Success metricsBlast delivery rate; reply rate per channel; IB score distribution; days-to-offer
Cost per stagePreview: ~0.01 × count; Channel 2 CRMLS: same; Channel 4 PropStream: same
ThroughputUp to 200 recipients per channel per blast; w4-broadcast hits all active deals weekly
Last run resultQuery: SELECT * FROM ib_blast_history ORDER BY created_at DESC LIMIT 20
Failure modes0 matched (threshold), 429 from carrier, CRMLS auth fail, PropStream quota, suppression miss

Architecture

HubSpot dispo deal (status: dispositioning) OR scheduled showing
        │
        ▼
[blast-preview.js] — estimated count, cost, dedup hits (always run first)
        │
        ▼
[dispo-blast-engine.js] — unified 4-channel coordinator
        │
        ├─ Channel 1: Showing-day blast
        │     └─ [showing-blast-generic.js] / [showing-blast-compiled.js]
        │     └─ Cohort: ALL prior buyers + watchlist tagged 'buyer' in HubSpot
        │
        ├─ Channel 2: CRMLS agents
        │     └─ [dispo-crmls-agent-blast.js]
        │     └─ Targets: agents who sold in same zip + price band recently
        │
        ├─ Channel 3: InvestorBase end-buyers
        │     └─ [dispo-investorbase-blast.js]
        │     └─ [ib-blast-scorer.js] — fit score per buyer (threshold ≥60)
        │     └─ [ib-blast-history.js] — 4-check dedup
        │     └─ [ib-blast-message.js] — channel-specific message builder
        │
        ├─ Channel 4: PropStream flippers (cold)
        │     └─ [dispo-propstream-blast.js]
        │     └─ Targets: flippers in market with ≥3 recent purchases
        │
        ▼
[dispo-send.js] — shared send chokepoint (same as acquisitions-outreach)
        │
        ▼
SalesMsg (port 18793) / OpenPhone (port 18792)

Channel details

Channel 1 — Showing-day blast

Cohort: all HubSpot contacts tagged 'buyer' + watchlist. Dedup: 24h window before showing date.

# Single deal showing announcement
node /home/opsadmin/.openclaw/workspace/scripts/showing-blast-generic.js --deal-id=X --dry-run
 
# Multi-deal weekly compiled blast
node /home/opsadmin/.openclaw/workspace/scripts/showing-blast-compiled.js --week=2026-W17 --dry-run

Channel 2 — CRMLS agents

Cohort: LA-area agents with recent sales in same zip + price band. Dedup: 30d per agent. Auth: CRMLS API token → op://Aurora/crmls/api-token

node /home/opsadmin/.openclaw/workspace/scripts/dispo-crmls-agent-blast.js \
  --deal-id=X --dry-run

Failure mode: CRMLS API auth fail → refresh token from 1Password, check master.env CRMLS section.

Channel 3 — InvestorBase end-buyers

Cohort: InvestorBase platform buyers with fit score ≥60. Dedup: 7d per (deal, buyer) pair.

node /home/opsadmin/.openclaw/workspace/scripts/dispo-investorbase-blast.js \
  --deal-id=X --min-score=60 --dry-run

IB fit scoring — ib-blast-scorer.js {#IB-scoring}

FactorWeightThreshold
Zip match25%exact zip OR adjacent zip
Bed count15%±1 bed
Price band20%within ±20% of asking
Condition pref20%matches buyer’s stated rehab tolerance
Recent activity10%bought in last 90d
Deal velocity10%hot deal (views > 100 in 24h)

Score ≥60 → blast. Below threshold → logged, skipped.

Default --min-score=60. Lower to 50 if 0 buyers matched and deal characteristics are broad.

Channel 4 — PropStream flippers (cold)

Cohort: cold flippers in market with ≥3 recent purchases. Dedup: 90d per flipper.

node /home/opsadmin/.openclaw/workspace/scripts/dispo-propstream-blast.js \
  --deal-id=X --zip=90210 --dry-run

Failure mode: PropStream rate limit → daily quota hit; retry next day. Check quota in master.env PropStream section.

Pre-blast history checks (4 checks per buyer)

All 4 checks run via ib-blast-history.js before every send:

  1. Already-blasted — sent this exact (deal, buyer) in last 7d?
  2. Recent-engagement — buyer replied to ANY blast in last 14d?
  3. Saturation — ≥3 blasts to this buyer in last 7d?
  4. Suppression — buyer in messaging_suppression table?

Any check fails → blast skipped, reason written to ib_blast_history.

Weekly w4 broadcast

Every Wednesday AM: all active dispo deals → all buyer cohorts.

node /home/opsadmin/.openclaw/workspace/scripts/w4-broadcast-blast.js --dry-run

Pre-blast preview (always run first)

node -e "
const p = require('/home/opsadmin/.openclaw/workspace/scripts/lib/blast-preview.js');
p.preview({ dealId: 'DEAL_ID', channels: [1,2,3,4] }).then(r => console.log(JSON.stringify(r, null, 2)));
"

Returns: estimated recipient count, projected cost, dedup hit count per channel.

Post-blast audit

node /home/opsadmin/.openclaw/workspace/scripts/audit-blast-responses.js --deal-id=X

Returns: buyer replies, A-G classification per reply, HubSpot stage transitions triggered.

Failure modes

SymptomCauseRecovery
0 buyers matched for Channel 3IB score threshold too highLower --min-score; check IB buyer database freshness
429 from SalesMsg/OpenPhoneLine saturationLower --limit-per-channel; rotate lines
CRMLS API auth failToken rotatedRefresh from 1Password; check master.env CRMLS section
PropStream rate limitDaily quota hitRetry tomorrow; monitor quota
Blast sent to suppressed buyermessaging_suppression check missedAudit messaging_suppression table; surface for manual review
Inbound replies not routingWebhook handler downCheck acquisitions-followup; systemctl --user status openphone-webhook salesmsg-webhook
Channel 1 showing blast duplicateDedup window too shortVerify 24h dedup in ib_blast_history; check showing date proximity

Components

  • workspace/scripts/dispo-blast-engine.js — unified 4-channel coordinator
  • workspace/scripts/dispo-crmls-agent-blast.js — Channel 2 (CRMLS)
  • workspace/scripts/dispo-investorbase-blast.js — Channel 3 (IB)
  • workspace/scripts/dispo-propstream-blast.js — Channel 4 (PropStream)
  • workspace/scripts/showing-blast-generic.js — Channel 1 (single showing)
  • workspace/scripts/showing-blast-compiled.js — Channel 1 (weekly compiled)
  • workspace/scripts/w4-broadcast-blast.js — weekly inventory broadcast
  • workspace/scripts/audit-blast-responses.js — post-blast audit
  • workspace/scripts/lib/investorbase/ib-blast-scorer.js — fit scoring
  • workspace/scripts/lib/investorbase/ib-blast-history.js — 4-check dedup
  • workspace/scripts/lib/investorbase/ib-blast-message.js — message builder
  • workspace/scripts/lib/blast-preview.js — pre-blast stats
  • workspace/scripts/dispo-send.js — shared send chokepoint

Agents that touch this

Skills that invoke this

  • dispo-blast — canonical skill wrapper for all blast commands

Plans that govern this

Feedback rules

KB / source docs

  • API — InvestorBase buyer API + scoring lib
  • API — CRMLS agent search
  • API — PropStream flipper lookup

System maps

Open issues / TODOs

  • 10DLC A2P repeat-denial is BLOCKING all SMS blast channels. See osil-twilio-10dlc-resubmission-2026-05-03 B14.
  • Channel 4 PropStream daily quota not tracked in monitoring. Add to cost-tracking open issues.
  • CRMLS agent blast result rate needs baseline measurement (no historical data in ib_blast_history).

Recent activity

  • 2026-05-03: hub created by W1-S9
  • 2026-05-03: 4-channel blast mechanics, IB scoring, pre-blast checks, all commands documented