Appearance
Campaign Service
The Campaign Service manages the full lifecycle of outreach campaigns — from creation through multi-step email, SMS, and voicemail execution to completion. It lives inside the apps/app monolith and delegates heavy async work to the worker service via BullMQ queues.
Campaign Lifecycle
| Status | Meaning |
|---|---|
DRAFT | Being configured; not yet running |
ACTIVE | Running — jobs are being enqueued and sent |
PAUSED | Temporarily stopped; pending jobs are cancelled |
COMPLETED | All steps finished |
ARCHIVED | Historical record only |
Data Models
| Model | Purpose |
|---|---|
Campaigns | Campaign metadata, status, audience type, AI flag |
CampaignSteps | Ordered steps (EMAIL / SMS / VOICEMAIL / WAIT) grouped by day |
CampaignLeadGroups | Many-to-many between campaigns and lead groups |
CampaignLeads | Per-contact enrollment and engagement state |
StepExecutions | Per-contact, per-step execution record (sent, opened, replied, etc.) |
Campaign Launch Flow
This is the complete path from a user clicking "Launch" to an email arriving in a prospect's inbox.
Step Types
| Type | Description |
|---|---|
EMAIL | Sent via Gmail OAuth (sender account rotation) |
SMS | Sent via Twilio |
VOICEMAIL | Delivered via Twilio voicemail drop |
WAIT | Introduces a delay between groups (e.g., 3 days, 7 days) |
Steps are organized into groups (day numbers). All steps in group 0 fire immediately after launch; group 1 fires after 1 day + any WAIT steps, etc.
Credit System
Before launch, the system calculates and reserves credits:
credit_cost = Σ (step_count_per_type × total_contacts)- 1 credit = $0.001 (1,000 credits = $1)
- Plan tiers: Basic (1,000), Standard (10,000), Premium (100,000)
- Credits are reserved atomically before status changes to ACTIVE. If insufficient, launch is rejected.
Sender Account Rotation
For EMAIL steps, the worker selects a Gmail sender account per contact:
- Consistency — reuses the same sender account previously used for this contact (improves deliverability).
- Quota check — verifies
sendsToday < dailyLimit. - Warmup-aware — accounts in warmup have progressively increasing daily limits; skips accounts at cap.
- Fallback — tries up to 3 accounts, sorted by highest remaining quota.
- Atomic increment —
sendsTodayis incremented before sending to prevent over-sending across concurrent workers.
Cron Jobs
| Job | Schedule | Purpose |
|---|---|---|
| Email Warmup Reset | Daily at midnight UTC | Resets sendsToday counter on all sender accounts |
| Follow-up Processor | Periodic | Re-enqueues follow-up steps for contacts who haven't replied |
API Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/campaign/ | Create campaign (name, audience, lead groups, optional template) |
POST | /v1/campaign/{id}/launch | Validate and launch a DRAFT campaign |
POST | /v1/campaign/{id}/pause | Pause an ACTIVE campaign |
POST | /v1/campaign/{id}/resume | Resume a PAUSED campaign |
GET | /v1/campaign/ | List campaigns for brand |
GET | /v1/campaign/{id} | Get campaign details with steps and metrics |
Full interactive reference: API Documentation