Documentation Index
Fetch the complete documentation index at: https://docs.reach.raysium.com/llms.txt
Use this file to discover all available pages before exploring further.
What are Campaigns?
Campaigns are automated messaging workflows that send personalized messages to leads through Telegram. Each campaign processes leads individually (lead-by-lead), executing a flow of nodes that can send messages, wait for delays, evaluate conditions, and respond to user interactions.Campaign Architecture
Core Components
Campaign Flow (campaign_flows table):
- Defines the visual workflow (nodes and edges)
- Stores campaign metadata (name, description, status, timezone)
- Contains A/B test configuration and variations
- Links to Telegram account for sending messages
flow_executions table):
- One execution per lead in the campaign
- Tracks individual lead progress through the flow
- Stores execution context (variables, node states)
- Maintains status:
pending,running,waiting,completed,responded,failed,paused,cancelled
flow_execution_logs table):
- Audit trail of every node execution
- Records input/output data, status, timestamps
- Used for statistics and debugging
messages table):
- Stores all sent and received messages
- Links to execution and campaign for tracking
- Tracks delivery status and A/B test variation
Processing Model
Campaigns use a worker-based architecture:- UnifiedWorker runs continuously, polling for pending executions
- Each execution is processed independently (lead-by-lead)
- Workers use Redis locks to prevent concurrent processing of the same execution
- Rate limiting is enforced per Telegram account to prevent FloodWaitError
- Response detection runs automatically, checking for replies every 60 seconds
Campaign Statuses
Draft
- Campaign created but not launched
- Can be edited freely
- No executions created yet
Scheduled
- Campaign set to start at a specific date/time
- Timezone-aware: scheduled time is stored in UTC but displayed in campaign’s timezone
- Automatically transitions to
activewhen scheduled time is reached
Active
- Campaign is running and processing executions
- Workers pick up pending executions and process them
- Cannot edit flow configuration (must pause first)
- New leads can be added dynamically
Paused
- Campaign temporarily stopped
- All active executions are paused
- Can be resumed (executions continue from where they stopped)
- Flow configuration can be edited
Completed
- All executions have finished (completed, responded, or failed)
- Campaign automatically transitions to completed when no active executions remain
- Can be reactivated by adding new leads (status changes back to
active)
Cancelled
- Campaign was stopped manually
- All pending executions are cancelled
- Cannot be resumed (must duplicate to restart)
Permissions
Organization Context
Campaigns respect organization isolation: Personal Mode (no organization):- Users can only see/edit campaigns with
organization_id = NULL - Complete isolation from organization data
- Campaigns belong to organization (
organization_idset) - Access controlled by role and
admin_view_enabledsetting
Role-Based Permissions
Owner:- Can view all organization campaigns (if
admin_view_enabled = true) - Can edit any organization campaign (regardless of status)
- Can delete any organization campaign
- Full control over campaign lifecycle
- Can view all organization campaigns (if
admin_view_enabled = true) - Can edit any organization campaign (regardless of status)
- Can delete any organization campaign
- Cannot change organization owner
- Can only view own campaigns (even if
admin_view_enabled = true) - Can edit own campaigns (if status allows)
- Can delete own campaigns
- Cannot view/edit other members’ campaigns
Status-Based Edit Restrictions
Even with proper permissions, editing is restricted by status: Can Edit Flow Configuration:draft- Always editablepaused- Editablescheduled- Editable (before start time)
active- Must pause first (prevents mid-execution changes)completed- Cannot edit (historical record)cancelled- Cannot edit (historical record)
Campaign Processing
Execution Flow
-
Campaign Started:
- Status changes to
active - Executions created for each lead (status:
pending) next_execution_atset tonow()for immediate processing
- Status changes to
-
Worker Picks Up Execution:
- UnifiedWorker queries for executions where
next_execution_at <= now() - Acquires Redis lock to prevent concurrent processing
- Loads campaign flow, contact, and execution context
- UnifiedWorker queries for executions where
-
Node Execution:
- Processes current node based on type:
- START: Initializes execution, moves to first node
- SEND_MESSAGE: Sends message with rate limiting, tag replacement, spintax
- WAIT: Calculates next execution time, sets status to
waiting - CONDITION: Evaluates condition, branches to appropriate path
- END: Marks execution as
completed
- Processes current node based on type:
-
After Node Execution:
- Updates execution context (variables, current_node_id)
- Creates execution log entry (audit trail)
- Calculates next node and
next_execution_at - Releases Redis lock
-
Execution Completion:
- When execution reaches END node or fails
- Status changes to
completed,responded, orfailed - Campaign checks if all executions are done → auto-completes campaign
Rate Limiting
Rate limiting prevents Telegram FloodWaitError: Per-Account Limits:- Cooldown between messages: 30-60 seconds (with 20-40% jitter)
- Daily message limits: Configurable per account profile
- Hourly message limits: Configurable per account profile
- Workers check rate limit before sending
- If cooldown active, execution waits and retries later
next_execution_atadjusted to respect cooldown
conservative: Lower limits, safer for new accountsmoderate: Balanced limitsaggressive: Higher limits (use with caution)
Timezone Handling
Campaigns are timezone-aware: Scheduled Campaigns:scheduled_start_atstored in UTCtimezonefield stores campaign’s timezone (e.g., “America/Sao_Paulo”)- Worker converts UTC to campaign timezone for comparison
- Ensures campaigns start at correct local time
- Duration-based waits are timezone-agnostic (relative)
- Response-based waits use UTC timestamps
Response Detection
Automatic response detection stops sending when lead replies: Detection Process:- UnifiedWorker checks for responses every 60 seconds
- Queries Telegram API for messages after last sent message timestamp
- If response found:
- Execution status →
responded response_detected_attimestamp recordedresponse_textstored (first 500 chars)- Last sent message marked as delivered (response = proof of delivery)
- No further messages sent to this lead
- Execution status →
- Configurable per campaign (
response_timeout_hours) - If no response after timeout, execution continues
- Default: No timeout (waits indefinitely)
- Campaign setting:
pause_on_response - If enabled, execution stops immediately when response detected
- If disabled, execution completes current node before stopping
Flow Builder
Node Types
START Node:- Entry point of campaign
- Defines start type:
immediateorscheduled - For scheduled: requires
scheduled_start_atandtimezone
- Sends text message (with optional media)
- Processes spintax and dynamic tags
- Enforces rate limiting
- Creates message record and execution log
- Duration-based: waits specified time (days/hours/minutes)
- Response-based: waits for lead response with timeout
- Sets
next_execution_atfor future processing
- Evaluates condition based on execution context
- Branches to different paths based on result (
yes/no) - Uses edges with
conditionfield to route flow
- Marks execution as completed
- Campaign checks if all executions done → auto-completes
Flow Configuration
Nodes Array:- Ordered list of all nodes in flow
- Each node has:
id,type,data,position
- Defines connections between nodes
- Sequential edges: connect nodes in order
- Conditional edges: connect condition nodes to branches (
condition: "yes"or"no")
- Nodes processed sequentially by array order
- Edges used only for condition branching
- If no edges, nodes processed in array order
Dynamic Tags
Tag Replacement
Tags are replaced with actual values before sending: Basic Tags:{firstName}→ Contact’s first name{lastName}→ Contact’s last name{username}→ Telegram username (without @){phoneNumber}→ Phone number{groupName}→ Group name (if contact from group)
{cf-fieldName}→ Custom field value- Example:
{cf-companyName}→ “Acme Corp”
- Format:
{tag|fallback} - If tag value missing, uses fallback
- Example:
{firstName|Guest}→ “John” or “Guest”
- Spintax processed first (variations resolved)
- Tags replaced second (with fallbacks)
- Final message sent
Spintax
Spintax allows message variations: Syntax:{option1|option2|option3}- Example:
{Hi|Hello|Hey} {firstName}
- Same lead always gets same variation (deterministic)
- Uses hash of
contact_idas seed - Ensures consistent experience per lead
- Supports nested variations:
{Hi|Hello} {there|here} - Processed recursively until all resolved
- Spintax: 3+ options → random selection
- Tag with fallback: 2 options → data replacement
- Processor distinguishes automatically
A/B Testing
Configuration
Variations:- Multiple flow configurations (A, B, C, etc.)
- Each variation has independent nodes/edges
- Variations can be enabled/disabled independently
- Deterministic: Same lead always gets same variation
- Uses hash of
contact_idfor consistency - Weighted distribution: Configurable weights per variation
- Automatic optimization based on performance metrics
- Compares response rates between variations
- Adjusts weights to favor better-performing variations
- Threshold:
ab_test_optimization_threshold(default: 0.1 = 10%)
- Tracked per variation: messages sent, responses, response rate
- Updated every 5 minutes by worker
- Available via
/campaign-flows/{id}/ab-statisticsendpoint
Statistics
Real-Time Metrics
Execution Metrics:total_contacts: Total leads in campaigncontacts_started: Executions that began processingcontacts_completed: Executions that finished successfullycontacts_failed: Executions that failedcontacts_active: Currently processing executionscontacts_responded: Leads who replied
messages_sent: Total messages sentmessages_failed: Failed send attemptsmessages_delivered: Confirmed deliveriesmessages_not_sent: Pending sends
completion_rate: (completed / total) × 100response_rate: (responded / delivered) × 100delivery_rate: (delivered / sent) × 100
- Statistics computed by database function (
get_campaign_statistics) - Cached for performance (refreshed every 5 minutes)
- Available via
/campaign-flows/{id}/statisticsendpoint
Audit Logs
Execution Logs
Every node execution creates a log entry: Log Fields:node_type: Type of node executedstatus:completed,failed,skippedexecuted_at: Timestamp of executioninput_data: Input context (contact info, message template)output_data: Output result (sent message, contact info)error_message: Error details if failed
sendMessage: Message sent to leadwait: Wait period startedcondition: Condition evaluateddelivery: Delivery status checkedresponse_detection: Response check performed
- Available via
/campaign-flows/{id}/logsendpoint - Filtered by execution for lead-specific view
- Used for debugging and compliance
When Campaigns Stop
Automatic Completion
Campaign automatically stops when:- All executions reach terminal status (
completed,responded,failed,cancelled) - No pending/running/waiting executions remain
- Status changes to
completed
Manual Stopping
Pause:- Temporarily stops processing
- Executions paused (can be resumed)
- Status:
paused
- Immediately cancels all active executions
- Status:
cancelled - Cannot be resumed (must duplicate)
- Toggles
enabledflag tofalse - Cancels all active executions immediately
- Prevents new launches
- Different from pause (cannot launch when disabled)
Response Detection
Ifpause_on_response = true:
- Execution stops immediately when response detected
- Status:
responded - No further messages sent
Fallback Mechanisms
Message Sending Fallback
If primarychat_id fails:
- Tries
telegram_user_id(if available) - Tries
phone_number(if available) - Tries
username(if available) - If all fail, execution marked as
failed
Tag Fallback
If tag value missing:- Uses fallback value if specified:
{tag|fallback} - Otherwise, tag left as-is (prevents broken messages)
Rate Limit Fallback
If rate limit exceeded:- Execution waits for cooldown period
next_execution_atadjusted- Retries automatically on next worker cycle
Best Practices
- Start Small: Test with small audience before full launch
- Monitor Rate Limits: Watch account health and rate limit usage
- Use Fallbacks: Always provide fallback values for tags
- Test Flow: Review flow visually before launching
- Respect Timezones: Set correct timezone for scheduled campaigns
- Monitor Responses: Check response rates and adjust messaging
- Use A/B Testing: Test variations to optimize performance
- Review Logs: Check audit logs for debugging and compliance
