Start the conversation

Outbound SMS that knows when to stop.

Six steps between receiving a message and sending one back. The AI reads the full conversation, decides what to say, and decides when to end. The code doesn't second-guess it.

6 stepsreceive → compliance → context → AI → save → send
320 charshard limit enforced in code, not left to the AI
2 providersTwilio primary, Guni secondary — switchable per campaign
0 double sendsidempotent pipeline — MessageSid checked before every send
How it works

Every message runs the same six-step pipeline.

Inbound webhooks validate, enqueue, and return 200 OK immediately. The pipeline runs asynchronously — so burst traffic from a large campaign doesn't stack up behind slow AI calls.

  • Twilio webhook validates the request and writes to the message queue
  • Worker picks up the job and runs compliance before touching the AI
  • Context assembled fresh on every turn — full conversation history included
  • AI reads everything and returns a typed response with directive and reasoning
  • Turn persisted to the database before the outbound send fires
  • Send failure triggers automatic retry — 60s, then 300s, then flags for review
Message pipeline
  1. 1
    Receive
    Twilio webhook → message queue → 200 OK
  2. 2
    Compliance check
    Opt-out, time windows, frequency — before any AI call
  3. 3
    Assemble context
    Campaign config + full conversation history injected
  4. 4
    AI call
    Claude returns directive, message, reasoning, confidence
  5. 5
    Persist turn
    Written to DB before send — idempotent by MessageSid
  6. 6
    Send
    Outbound via Twilio or Guni — retry on failure
Built-in compliance

Compliance runs before the AI. Every time.

Opt-outs, time windows, and frequency limits are enforced in code — not left to the AI's judgment. The AI never receives a message that compliance has already handled.

Zero false negatives on opt-outs.

Hard opt-out keywords — STOP, UNSUBSCRIBE, CANCEL, and common variants — are matched using word-boundary-aware logic to avoid false positives on words like "stopping by".

  • Opt-out flag set permanently — never overwritten by reimport
  • 7-day silence window and 30-day opt-out window enforced automatically
  • Every compliance check — pass or intercept — written to the audit log
  • Opted-out contacts cannot be re-added without explicit operator action
Compliance checks per message
  • Opt-out keyword scanSTOP, UNSUBSCRIBE, CANCEL + variants

  • Contact opt-out flagpermanent record checked before every message

  • 7-day silence windowcloses conversations with no activity

  • 30-day messaging windowblocks non-opt-out messages after expiry

  • Frequency capbump intervals enforced per campaign config

  • Audit rowevery check logged with outcome and timestamp

Bump scheduling

Follow-ups that know when to give up.

Bump intervals are configured per campaign as an array of minimum hours between touches. The scheduler derives the maximum number of bumps from the array length — no separate cap to manage.

Configurable intervals

Each campaign defines its own bump_intervals array — for example [24, 48, 96] means bump after 1 day, then 2 days, then 4 days. The platform enforces minimum hours between each touch.

How it works: How it works: max_bumps is derived from array length. A 3-item array means 3 bumps maximum — no separate field to keep in sync.

Business hours enforcement

Bumps only fire within configured business hours and timezone. The scheduler checks eligibility before enqueuing — contacts are never messaged at 2am because a job happened to run then.

How it works: Timezone-aware: multi-segment hour strings supported. Configure different windows for weekdays and weekends per campaign.

Burst traffic handling

All scheduler eligibility queries use FOR UPDATE SKIP LOCKED — multiple workers can run simultaneously without processing the same conversation twice, even under heavy load.

How it works: Queue-backed: Redis + RQ absorbs burst traffic. Worker restarts don't lose queued jobs — all state is persisted in PostgreSQL.

Automatic retry on failure

If an outbound send fails, the platform retries at 60 seconds, then 300 seconds. After three failed attempts, the turn is flagged for operator review — no silent failures.

How it works: Idempotent by design: MessageSid is checked before every send. A recovered worker can never send the same message twice.

Ready to run your first
outbound campaign?

One campaign. One contact list. We'll have you sending in days, not weeks.