26 KiB
CloseBot SMS — Definitive Build Plan
Unified app: Twilio native SMS + CloseBot AI bots. One dashboard to rule them all.
1. TECH STACK
| Layer | Technology | Why |
|---|---|---|
| Frontend | Next.js 14 (App Router) + Tailwind CSS + shadcn/ui | Dark-mode-first, server components, fast |
| Backend | Next.js API routes (Edge-compatible) | Same deployment, zero CORS |
| Database | SQLite via better-sqlite3 (dev) → Turso/LibSQL (prod) | State tracking, conversation history, routing config |
| Real-time | Server-Sent Events (SSE) | Live conversation updates on dashboard |
| SMS | Twilio Node SDK (twilio) |
Send/receive SMS, delivery status |
| AI Bots | CloseBot API (direct HTTP) | Webhook Source for inbound, API for bots/leads/metrics |
| Auth | NextAuth.js with credentials provider | Simple login, protect all routes |
| Deploy | Railway / Fly.io / Vercel | Needs persistent process for webhooks |
2. SYSTEM ARCHITECTURE
┌─────────────┐ ┌──────────────────────────┐ ┌─────────────┐
│ Customer │────>│ Twilio (SMS) │────>│ CloseBot │
│ Phone │<────│ │<────│ SMS App │
└─────────────┘ └──────────────────────────┘ └──────┬──────┘
│
┌──────────────────────────┐ │
│ CloseBot API │<───────────┘
│ (Webhook Source) │────────────┐
└──────────────────────────┘ │
v
┌──────────────┐
│ SQLite DB │
│ (state/logs) │
└──────────────┘
Message Flow — Inbound:
- Customer sends SMS to Twilio number
- Twilio POSTs to
POST /api/webhooks/twilio/inbound - App looks up routing: which Twilio number → which CloseBot bot/source
- App sends inbound event to CloseBot via
POST /webhook/event/{sourceId}with:type: "message"contactId(phone number as unique identifier)message(SMS body)state(JSON:{ twilioNumber, phoneFrom, messageSid })
- CloseBot processes through bot flow
- CloseBot POSTs response to our webhook retrieval URL:
POST /api/webhooks/closebot/response - App receives response, extracts
stateto get the Twilio number + customer phone - App sends SMS via Twilio API
- App logs everything to SQLite + broadcasts via SSE for live dashboard
Message Flow — Manual Override (from Conversations view):
- User types message in the conversation UI
- App sends SMS directly via Twilio (bypassing CloseBot)
- Logs to SQLite with
source: "manual"flag
3. DATABASE SCHEMA
-- Routes: Twilio number → CloseBot bot mapping
CREATE TABLE routes (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
twilio_number TEXT NOT NULL UNIQUE,
twilio_number_sid TEXT,
closebot_source_id TEXT NOT NULL,
closebot_bot_id TEXT,
bot_name TEXT,
greeting_message TEXT,
after_hours_reply TEXT,
business_hours_json TEXT, -- {"mon": {"start": "09:00", "end": "17:00"}, ...}
max_concurrent INTEGER DEFAULT 50,
active BOOLEAN DEFAULT TRUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Contacts: phone numbers we've interacted with
CREATE TABLE contacts (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
phone TEXT NOT NULL UNIQUE,
name TEXT,
email TEXT,
status TEXT DEFAULT 'new', -- new, active, qualified, booked, closed, cold
closebot_lead_id TEXT,
assigned_bot_id TEXT,
assigned_route_id TEXT REFERENCES routes(id),
tags TEXT, -- JSON array
fields_json TEXT, -- collected fields from CloseBot
first_contact DATETIME DEFAULT CURRENT_TIMESTAMP,
last_contact DATETIME DEFAULT CURRENT_TIMESTAMP,
message_count INTEGER DEFAULT 0
);
-- Messages: every SMS in/out
CREATE TABLE messages (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
contact_id TEXT REFERENCES contacts(id),
route_id TEXT REFERENCES routes(id),
direction TEXT NOT NULL, -- 'inbound' | 'outbound'
source TEXT NOT NULL, -- 'customer' | 'bot' | 'manual'
body TEXT NOT NULL,
twilio_sid TEXT,
twilio_status TEXT, -- queued, sent, delivered, failed, undelivered
closebot_message_id TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Settings: app-wide config
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Events: activity log for dashboard feed
CREATE TABLE events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT NOT NULL, -- 'message_in', 'message_out', 'booking', 'new_lead', 'status_change'
contact_id TEXT REFERENCES contacts(id),
route_id TEXT REFERENCES routes(id),
data_json TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
4. API ROUTES
Webhook Endpoints (public, Twilio/CloseBot call these)
| Route | Method | Purpose |
|---|---|---|
/api/webhooks/twilio/inbound |
POST | Receive inbound SMS from Twilio |
/api/webhooks/twilio/status |
POST | Receive delivery status updates |
/api/webhooks/closebot/response |
POST | Receive CloseBot bot responses |
Internal API (authenticated, frontend calls these)
| Route | Method | Purpose |
|---|---|---|
/api/dashboard/stats |
GET | Active convos, messages today, bookings, response rate |
/api/dashboard/activity |
GET | Recent activity feed (SSE endpoint) |
/api/conversations |
GET | List conversations with pagination/filters |
/api/conversations/[contactId] |
GET | Get single conversation with messages |
/api/conversations/[contactId]/send |
POST | Send manual SMS message |
/api/bots |
GET | List CloseBot bots (proxied from CloseBot API) |
/api/bots/[id] |
GET | Get bot details + metrics |
/api/contacts |
GET | List/search contacts with filters |
/api/contacts/[id] |
GET/PUT/DELETE | Contact CRUD |
/api/contacts/export |
GET | Export CSV |
/api/analytics/overview |
GET | Summary metrics with date range |
/api/analytics/messages |
GET | Message volume time series |
/api/analytics/bots |
GET | Per-bot conversation counts |
/api/analytics/outcomes |
GET | Outcome distribution |
/api/analytics/leaderboard |
GET | Top performing bots |
/api/routes |
GET/POST | List routes, create new route |
/api/routes/[id] |
GET/PUT/DELETE | Route CRUD |
/api/settings |
GET/PUT | App settings (Twilio creds, CloseBot key) |
/api/settings/test-connection |
POST | Test Twilio + CloseBot connections |
5. PAGE-BY-PAGE UI SPEC
5A. DASHBOARD (/)
Matches mockup: closebot-sms-dashboard.png
Layout:
- Left sidebar (240px): Logo "CloseBot SMS" + 6 nav items with icons
- Top bar: Global search input
- Main content area
Components:
-
Stat Cards Row — 4 cards in a grid
- Active Conversations (chat bubble icon, count from DB)
- Messages Today (envelope icon, count from DB where date = today)
- Bookings Made (calendar icon, from CloseBot metrics API)
- Response Rate (trending icon, calculated: bot_responses / inbound_messages * 100)
- Each card: dark glass-morphism background (
bg-slate-800/50 backdrop-blur), cyan border glow, icon top-left, label + big number
-
Real-time Activity Table
- Columns: SMS (phone number), Bot Name, Badges (status pill), Timestamp
- Status pills:
active(green),pending(yellow),closed(gray) - Auto-updates via SSE — new rows slide in at top
- Click row → navigate to conversation
Data sources:
- Stats:
GET /api/dashboard/stats→ queries SQLite counts - Activity:
GET /api/dashboard/activity→ SSE stream from events table
5B. CONVERSATIONS (/conversations)
Matches mockup: closebot-sms-conversations.png
Layout: Two-panel split (left 380px list, right flexible chat)
Left Panel — Conversation List:
- Search bar with filter icon + settings icon
- "All Filters" dropdown (by status, bot, date range)
- Conversation rows: avatar (generated from initials), name, phone, last message preview (truncated), timestamp, unread badge (cyan circle with count)
- Selected conversation highlighted with left cyan border
- Sorted by most recent message
Right Panel — Chat Thread:
- Header: avatar, name, phone number, "CloseBot SMS AI" badge, status dot + "Active" label
- Message bubbles:
- Inbound (customer): dark gray background (
bg-slate-700), left-aligned with avatar - Outbound (bot): cyan/blue gradient background, right-aligned
- Each bubble shows text, no timestamps on individual messages (clean look)
- Inbound (customer): dark gray background (
- Bottom: text input "Type a message..." with cyan send button
- Sending from here = manual override, bypasses CloseBot
Data sources:
- List:
GET /api/conversations?search=&status=&bot=&page= - Messages:
GET /api/conversations/[contactId] - Send:
POST /api/conversations/[contactId]/send - Live updates: SSE for new messages appended to thread
5C. BOTS (/bots)
Matches mockup: closebot-sms-bots.png
Layout: Grid of bot cards (3 columns on desktop)
Top Bar:
- "Bot Management" heading
- Search bots input + filter icon + sort icon
- "+ Create New Bot" button (cyan, calls CloseBot create_bot_with_ai)
Bot Cards:
- Card header: bot name in bold, gradient top border (different colors per bot)
- Fields: Status toggle (Active/Inactive), Twilio # (from route mapping), Messages count, Conversion % (from CloseBot metrics), Last Active
- Inactive bots appear dimmed/grayed
- Click expand chevron → expanded card shows:
- Connected Sources list
- Recent Performance sparkline (mini chart, last 7 days)
- "Edit Flow" button (opens CloseBot dashboard in new tab)
Data sources:
- Bots list:
GET /api/bots→ proxies CloseBotGET /bot+ merges route data from SQLite - Metrics: CloseBot
GET /botMetric/agencySummary - Toggle active:
PUT /api/routes/[id]to enable/disable route
5D. CONTACTS (/contacts)
Matches mockup: closebot-sms-contacts.png
Layout: Full-width data table with optional slide-out detail panel
Top Bar:
- Search input
- Filter dropdowns: "Filter by Status" (hot/warm/cold/new), "Filter by Bot", date range picker
- "Import Contacts" button (cyan outline) + "Export CSV" button (cyan outline)
Table Columns:
- Name (bold)
- Phone Number
- Assigned Bot
- Status (colored dot: red=Hot Lead, orange=Warm, gray=Cold + text label)
- Messages Exchanged (number)
- Last Contact (relative time: "2 hours ago", "Yesterday")
- Tags (colored pills)
Slide-out Detail Panel (on row click):
- Contact name (large, bold)
- Phone, Email, Company fields
- "Conversation Summary" section — AI-generated from CloseBot
- Bullet points: "Product Interest", "Budget Discussion", etc.
- "Field Values Collected" — mini table of CloseBot-collected fields (Company Size, Industry, Priority)
- Action buttons: "View Full History" + "Send Message" (cyan)
Data sources:
- Table:
GET /api/contacts?search=&status=&bot=&dateFrom=&dateTo=&page=&limit= - Detail:
GET /api/contacts/[id] - Export:
GET /api/contacts/export→ CSV download - Import:
POST /api/contacts/import(CSV upload, creates contacts + optionally sends first message)
5E. ANALYTICS (/analytics)
Matches mockup: closebot-sms-analytics.png
Layout: Scrollable dashboard with multiple chart sections
Top Bar:
- "Analytics" heading
- Tab navigation: Dashboard, Conversations, Bots, Contacts, Settings
- Date range picker dropdown (top right): "Last 30 Days (Oct 1 - Oct 30, 2024)"
Section 1 — Stat Cards (4 across):
- Total Conversations (large number + sparkline + % change vs last period)
- Booking Rate (percentage + sparkline + change)
- Avg Response Time (duration format "1m 45s" + sparkline + change)
- Customer Satisfaction (rating "4.8/5" + sparkline + change)
- Each card has colored gradient background (red→pink, green, blue, purple)
Section 2 — Messages Over Time (full width):
- Line chart with dual lines: Inbound (blue) vs Outbound (green)
- X-axis: dates over selected range
- Y-axis: message count
- Tooltip on hover showing exact values
- Chart library: Recharts (React-native, works with Next.js)
Section 3 — Two charts side by side:
- Left: "Conversations by Bot" — horizontal bar chart with colored bars per bot
- Right: "Outcome Distribution" — donut chart with segments (Booked 40%, Qualified 30%, Dropped 18%, Pending 12%), total in center
Section 4 — Top Performing Bots:
- Mini leaderboard table: Rank, Bot Name (with icon), Conversations, Booking Rate, CSAT Score
- Sorted by booking rate descending
Data sources:
- Stats:
GET /api/analytics/overview?start=&end= - Messages chart:
GET /api/analytics/messages?start=&end=&resolution=daily - By bot:
GET /api/analytics/bots?start=&end= - Outcomes:
GET /api/analytics/outcomes?start=&end= - Leaderboard:
GET /api/analytics/leaderboard?start=&end= - All backed by SQLite queries (message counts, conversation outcomes) + CloseBot metrics API for bookings/CSAT
5F. ROUTING (/routing)
Matches mockup: closebot-sms-routing.png
Layout: Three-column visual routing display
Top Bar:
- Breadcrumb: "Routing / Phone Number Routing"
- Top nav tabs: Dashboard, Routing, Bots, Analytics, Settings
- "+ Add New Route" button (top right)
- Search bar + filter icon
Three Columns:
- Left: Twilio Phone Numbers — list of phone number cards with phone icon
- Center: Routing — animated connection lines (CSS/SVG) linking numbers to bots
- Right: CloseBot Bots & Sources — bot cards with: name, source badge (WEB_LEAD, EMAIL_INQUIRY, etc.), Active/Paused toggle, message count badge, "Configure" button
Expanded Route Configuration (on Configure click):
- Modal/drawer overlaying the route:
- Greeting Message Override (textarea, optional)
- After-Hours Auto-Reply Text (textarea)
- Business Hours Schedule — day-of-week toggle grid (Mon-Sun), time range "Mon-Fri: 9:00 AM - 5:00 PM", "Add Exception" link
- Max Concurrent Conversations — slider (1-100) with current value displayed
- Save + Close Configuration buttons
Data sources:
- Routes:
GET /api/routes→ SQLite routes table - Twilio numbers: fetched from Twilio API on settings save, cached
- Bots:
GET /api/bots→ CloseBot API - Update:
PUT /api/routes/[id]with config JSON
5G. SETTINGS (/settings)
Matches mockup: closebot-sms-settings.png
Layout: Two-column card layout
Cards:
- Twilio Connection — Account SID input (masked), Auth Token input (masked), "Connection Status" indicator (green dot + "Connected")
- CloseBot Connection — API Key input (masked), Webhook Source ID (display), "Connection Status" indicator
- Phone Numbers — list of Twilio numbers with assigned bot + toggle switch
- Notifications — toggles: Email Alerts, SMS Delivery Failures, New Lead Alerts
- Webhook URLs — read-only display of:
- Inbound URL (the URL you give to Twilio)
- Response URL (the URL you give to CloseBot Webhook Source)
- Copy buttons next to each
Data sources:
- Settings:
GET/PUT /api/settings - Test:
POST /api/settings/test-connection→ pings both APIs
6. FILE STRUCTURE
closebot-sms/
├── package.json
├── next.config.js
├── tailwind.config.ts
├── tsconfig.json
├── .env.local.example
├── BUILD_PLAN.md
├── README.md
├── prisma/ (or drizzle/)
│ └── schema.sql
├── src/
│ ├── app/
│ │ ├── layout.tsx # Root layout with sidebar
│ │ ├── page.tsx # Dashboard
│ │ ├── conversations/
│ │ │ └── page.tsx # Conversations split view
│ │ ├── bots/
│ │ │ └── page.tsx # Bot grid
│ │ ├── contacts/
│ │ │ └── page.tsx # Contacts table
│ │ ├── analytics/
│ │ │ └── page.tsx # Analytics dashboard
│ │ ├── routing/
│ │ │ └── page.tsx # Phone number routing
│ │ ├── settings/
│ │ │ └── page.tsx # Settings/config
│ │ └── api/
│ │ ├── webhooks/
│ │ │ ├── twilio/
│ │ │ │ ├── inbound/route.ts
│ │ │ │ └── status/route.ts
│ │ │ └── closebot/
│ │ │ └── response/route.ts
│ │ ├── dashboard/
│ │ │ ├── stats/route.ts
│ │ │ └── activity/route.ts # SSE
│ │ ├── conversations/
│ │ │ ├── route.ts
│ │ │ └── [contactId]/
│ │ │ ├── route.ts
│ │ │ └── send/route.ts
│ │ ├── bots/
│ │ │ ├── route.ts
│ │ │ └── [id]/route.ts
│ │ ├── contacts/
│ │ │ ├── route.ts
│ │ │ ├── export/route.ts
│ │ │ └── [id]/route.ts
│ │ ├── analytics/
│ │ │ ├── overview/route.ts
│ │ │ ├── messages/route.ts
│ │ │ ├── bots/route.ts
│ │ │ ├── outcomes/route.ts
│ │ │ └── leaderboard/route.ts
│ │ ├── routes/
│ │ │ ├── route.ts
│ │ │ └── [id]/route.ts
│ │ └── settings/
│ │ ├── route.ts
│ │ └── test-connection/route.ts
│ ├── components/
│ │ ├── layout/
│ │ │ ├── sidebar.tsx
│ │ │ ├── topbar.tsx
│ │ │ └── nav-item.tsx
│ │ ├── dashboard/
│ │ │ ├── stat-card.tsx
│ │ │ └── activity-feed.tsx
│ │ ├── conversations/
│ │ │ ├── conversation-list.tsx
│ │ │ ├── conversation-item.tsx
│ │ │ ├── chat-thread.tsx
│ │ │ ├── message-bubble.tsx
│ │ │ └── chat-input.tsx
│ │ ├── bots/
│ │ │ ├── bot-grid.tsx
│ │ │ └── bot-card.tsx
│ │ ├── contacts/
│ │ │ ├── contacts-table.tsx
│ │ │ ├── contact-detail-panel.tsx
│ │ │ └── contact-filters.tsx
│ │ ├── analytics/
│ │ │ ├── stat-card-sparkline.tsx
│ │ │ ├── messages-chart.tsx
│ │ │ ├── bots-bar-chart.tsx
│ │ │ ├── outcome-donut.tsx
│ │ │ └── bot-leaderboard.tsx
│ │ ├── routing/
│ │ │ ├── routing-view.tsx
│ │ │ ├── phone-number-card.tsx
│ │ │ ├── bot-route-card.tsx
│ │ │ ├── connection-lines.tsx # SVG animated lines
│ │ │ └── route-config-modal.tsx
│ │ └── settings/
│ │ ├── twilio-card.tsx
│ │ ├── closebot-card.tsx
│ │ ├── phone-numbers-card.tsx
│ │ ├── notifications-card.tsx
│ │ └── webhook-urls-card.tsx
│ ├── lib/
│ │ ├── db.ts # SQLite connection + queries
│ │ ├── twilio.ts # Twilio client wrapper
│ │ ├── closebot.ts # CloseBot API client (reuse from MCP server)
│ │ ├── sse.ts # SSE broadcast utility
│ │ └── utils.ts # Formatters, helpers
│ └── styles/
│ └── globals.css # Tailwind base + custom dark theme
7. DESIGN SYSTEM
Colors (from mockups):
--bg-primary: #0f1729; /* deepest navy */
--bg-secondary: #1a2332; /* card backgrounds */
--bg-tertiary: #1e293b; /* elevated surfaces */
--bg-hover: #2d3748; /* table row hover */
--text-primary: #e2e8f0; /* main text */
--text-secondary: #94a3b8; /* muted text */
--text-muted: #64748b; /* timestamps, labels */
--accent-cyan: #22d3ee; /* primary accent */
--accent-blue: #3b82f6; /* secondary accent */
--accent-green: #22c55e; /* success, active */
--accent-yellow: #eab308; /* warning, pending */
--accent-red: #ef4444; /* error, hot lead */
--accent-orange: #f97316; /* warm */
--accent-purple: #a855f7; /* bot cards */
--border: #334155; /* subtle borders */
--border-glow: rgba(34, 211, 238, 0.2); /* cyan card glow */
Typography:
- Font:
Inter(system-ui fallback) - Headings: 600-700 weight
- Body: 400 weight
- Monospace numbers:
font-variant-numeric: tabular-nums
Card Style:
.card {
background: rgba(30, 41, 59, 0.5);
backdrop-filter: blur(12px);
border: 1px solid rgba(51, 65, 85, 0.5);
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
Status Badges:
- Active:
bg-green-500/20 text-green-400 border-green-500/30 - Pending:
bg-yellow-500/20 text-yellow-400 border-yellow-500/30 - Closed:
bg-gray-500/20 text-gray-400 border-gray-500/30
8. BUILD PHASES
Phase 1 — Foundation (Day 1)
- Next.js project scaffold with Tailwind + shadcn/ui
- SQLite schema + db.ts with all queries
- Global layout with sidebar navigation (matches dashboard mockup)
- Dark theme CSS variables
- Environment config (.env.local)
- Twilio client wrapper
- CloseBot API client (port from closebot-mcp)
Phase 2 — Core Webhook Bridge (Day 1-2)
POST /api/webhooks/twilio/inbound— receive SMS, forward to CloseBotPOST /api/webhooks/closebot/response— receive bot reply, send via TwilioPOST /api/webhooks/twilio/status— delivery status updates- Contact auto-creation on first inbound
- Message logging to SQLite
- Route lookup logic (Twilio number → CloseBot source)
- Business hours check + after-hours auto-reply
- State passthrough (phone + route info in CloseBot state field)
Phase 3 — Dashboard + Real-time (Day 2)
- Dashboard page with 4 stat cards
- Real-time activity feed (SSE)
- Activity table with status badges
- Auto-refresh stats
Phase 4 — Conversations (Day 2-3)
- Conversation list with search/filter
- Chat thread with message bubbles
- Manual message send
- Unread badges
- Live message updates via SSE
Phase 5 — Bots + Contacts (Day 3)
- Bot grid with cards from CloseBot API
- Bot status toggle (enable/disable route)
- Contacts table with all filters
- Slide-out detail panel
- CSV export
Phase 6 — Analytics (Day 3-4)
- Stat cards with sparklines
- Messages over time chart (Recharts)
- Conversations by bot bar chart
- Outcome distribution donut chart
- Bot leaderboard table
- Date range picker
Phase 7 — Routing + Settings (Day 4)
- Phone number routing view with visual connections
- Route config modal (business hours, greeting, max concurrent)
- Settings page with credential cards
- Connection testing
- Webhook URL display with copy
Phase 8 — Polish (Day 4-5)
- Loading states + skeletons
- Error handling + toast notifications
- Mobile responsive adjustments
- Auth gate (simple login)
- README with deploy instructions
9. EXTERNAL DEPENDENCIES
npm packages:
{
"dependencies": {
"next": "^14.2",
"react": "^18.3",
"twilio": "^5.0",
"better-sqlite3": "^11.0",
"recharts": "^2.12",
"lucide-react": "^0.400",
"@radix-ui/react-dialog": "^1.0",
"@radix-ui/react-dropdown-menu": "^2.0",
"@radix-ui/react-toggle": "^1.0",
"@radix-ui/react-slider": "^1.0",
"class-variance-authority": "^0.7",
"clsx": "^2.1",
"tailwind-merge": "^2.3",
"next-auth": "^4.24"
}
}
Environment Variables:
# Twilio
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# CloseBot
CLOSEBOT_API_KEY=cb_xxxxxxxxxxxxxxxx
# App
NEXTAUTH_SECRET=random-secret-here
NEXTAUTH_URL=https://your-domain.com
APP_URL=https://your-domain.com # Used to construct webhook URLs
# Database
DATABASE_PATH=./data/closebot-sms.db
10. WHAT MAKES THIS DIFFERENT
- No GHL required — CloseBot's Webhook Source is the channel, Twilio is the pipe
- Multi-tenant ready — one app, many Twilio numbers, many bots
- Human takeover — click into any convo and type a manual reply
- Business hours built-in — auto-reply after hours, resume bot in morning
- Full audit trail — every message logged with direction, source, status
- Real-time everything — SSE for live dashboard, no polling
- CloseBot metrics integrated — booking rates, leaderboards, CSAT from their API
- $0.0079/SMS — Twilio pricing, no GHL middleman markup
Plan version: 1.0 | Last updated: 2026-02-06