Understand how incoming messages are processed and routed.
Overview
When a new SMS message arrives at your campaign phone number, the system processes it through a series of steps to determine the appropriate response. This guide explains each step of the process and how the system differentiates between EchoWord messages and standard messages.
1. Message Receipt & Initial Processing
When the sending partner receives an incoming message, the webhook is triggered with the following data:
| Field | Description |
|---|---|
From | Sender's phone number |
To | Recipient phone number (your campaign number) |
Body | Message content |
MessageSid | Unique message identifier |
NumMedia | Number of media attachments |
NumSegments | Number of SMS segments |
Step 1.1: The system parses the raw webhook data and extracts all message parameters.
Step 1.2: The message body is normalized to uppercase and trimmed for consistent matching.
Step 1.3: The system validates that both From and To phone numbers are in E.164 format (e.g., +12345678901).
2. Global Phone Number Detection
Step 2.1: The system checks if the recipient phone number (To field) matches the configured global phone number.
Step 2.2: If it's a global phone number:
- Validates both
FromandTophone numbers are in E.164 format - If validation fails, logs an error and skips global processing
- If validation passes, proceeds to Global EchoWord Processing (see Section 3)
Step 2.3: If it's not a global phone number, proceeds to Campaign Lookup (see Section 4).
3. Global EchoWord Processing
If the message is sent to a global phone number:
Step 3.1: The system fetches all global EchoWords (EchoWords with type: 'global').
Step 3.2: It searches for a matching global EchoWord where the code matches the message body.
Step 3.3: If a match is found:
- Retrieves the campaign using the global EchoWord's
campaignId - Upserts the contact for the sender:
- Uses
upsertSingleContactto create or update the contact - Requires: phone number, brandId, and createdBy (from campaign)
- If
createdByis missing, logs an error and skips contact creation - Logs success or failure of the upsert operation
- Uses
- Saves an opt-in record for the sender
- Sends the campaign's
optinMessageas the response (or default message if not configured) - Processing ends (no further routing)
Step 3.4: If no match is found:
- Sends default response: "Message received. Thank you."
- Processing ends
Note: Global phone numbers skip the normal campaign lookup process and handle EchoWords directly.
4. Campaign Lookup
For non-global phone numbers:
Step 4.1: The system looks up the campaign associated with the recipient phone number (To field).
Step 4.2: If a campaign is found, the system retrieves:
- Campaign configuration
- Brand information
- Phone number details
- Campaign creator (
createdBy)
Step 4.3: If no campaign is found:
- System proceeds to error handling
- Sends error message: "This number is not configured for messaging. Please contact support."
5. Reply Record Creation
Step 5.1: The incoming message is saved to the replies table with:
- Message content
- Sender and recipient phone numbers
- Timestamp
- Campaign creator (if available)
Step 5.2: A unique reply ID is generated for tracking.
6. Message Routing Decision
The system now determines which processing path to take based on the message content:
Path A: Standard Keywords (START, STOP, HELP, YES)
Path B: EchoWord Match
Path C: Autoresponder Fallback (for non-keyword messages)
Path A: Standard Keyword Processing
If the message contains standard compliance keywords, the system processes them immediately:
START Keyword
Step A.1: System saves an opt-in record for the sender.
Step A.2: Sends the campaign's opt-in message (or default message if not configured).
Step A.3: No further processing occurs.
YES Keyword
Step A.1: System saves an opt-in record for the sender.
Step A.2: Sends a confirmation message: "Thanks for confirming!"
Step A.3: No further processing occurs.
STOP Keyword
Step A.1: System saves an opt-out record for the sender.
Step A.2: Sends the campaign's opt-out message (or default message if not configured).
Step A.3: No further processing occurs.
HELP Keyword
Step A.1: Sends the campaign's help message (or default message if not configured).
Step A.2: No further processing occurs.
Path B: EchoWord Processing
If the message doesn't match standard keywords, the system checks for EchoWord matches:
Step B.1: Fetch Available EchoWords
The system retrieves:
- Campaign EchoWords (campaign-specific, not global)
Step B.2: Fetch Campaign Phone Numbers
Step B.2.1: The system fetches all phone numbers for the campaign that are:
- Not deleted (
deletedAt IS NULL) - Not archived (
archivedAt IS NULL)
Step B.2.2: Extracts phone number IDs into an array for validation.
Step B.3: EchoWord Matching Process
EchoWord Matching:
- Checks if message body matches any EchoWord code
- Phone number validation:
- If EchoWord has a
phoneNumberId, it must match the incoming phone number ID - If EchoWord has no
phoneNumberId, the incoming phone number ID must be in the list of all campaign phone number IDs
- If EchoWord has a
- First valid match wins
Note: EchoWords validate against all campaign phone numbers, not just the primary/default phone number.
Step B.4: Match Found - Process Actions
If a matching EchoWord is found:
Step B.4.1: Check if EchoWord is paused
- If paused, skip all actions
- If active, continue processing
Step B.4.2: Check expiration date/time
- If
expirationDateis set, compare with current time - If
expirationTimeis set, combine with expiration date - If expired, skip all actions
- If not expired, continue processing
Step B.4.3: Get or Create Contact
- Search for existing contact by phone number and brand
- If not found, create new contact with:
- Phone number
- Brand ID
- Campaign creator as
createdBy(required)
- Store contact ID for subsequent actions
Step B.4.4: Process Autoresponder Action
- If
actions.autoresponderIdis configured:- Fetch autoresponder from database (validated against campaign ID)
- Send autoresponder message to sender
- Message is not saved to
sent_messages(no associated text message)
Step B.4.5: Process Contact Group Actions
- If
actions.contactGroupIdsis configured:- For each group ID:
- Add contact to group (if not already in group)
- Update contact's
contact_group_idsarray
- Log each group addition
- For each group ID:
Step B.4.6: Default Opt-In Message
- If no autoresponder is configured:
- Send campaign's opt-in message (or default)
- This serves as a fallback response
Step B.4.7: Save Opt-In Record
- Create opt-in record for the sender
- Link to the reply record
- Associate with campaign
Step B.5: No Match Found
If no EchoWord matches:
- System proceeds to Path C: Autoresponder Fallback
Path C: Autoresponder Fallback
For messages that don't match keywords or EchoWords:
Step C.1: Find Last Sent Message
Step C.1.1: Query sent_messages table for:
- Last message sent to this phone number
- From the same campaign
- Status:
sentordelivered - Direction:
outboundoroutbound-api - Ordered by most recent first
Step C.2: Check for Autoresponder
Step C.2.1: If a previous message is found:
- Retrieve the text message details
- Check if the text has an
autoresponderIdconfigured
Step C.2.2: If autoresponder is configured:
- Fetch autoresponder message from database
- Send autoresponder message to sender
- Message is saved to
sent_messageswith the original text ID
Step C.2.3: If no autoresponder is configured:
- No response is sent
- Message is logged but not replied to
7. Response Generation
After processing, the system generates a LaML (Laravel Markup Language) response:
Step 7.1: All messages added during processing are compiled into the response.
Step 7.2: Response is sent back to the sending partner.
Step 7.3: The sending partner delivers the response to the sender.
8. Error Handling
At each step, errors are caught and logged:
Error Handling:
- Errors in EchoWord processing fall back to default opt-in message
- Errors in autoresponder processing are logged but don't block the webhook
- Errors in contact group processing are logged per group
- All errors include detailed context for debugging (error message, stack trace, relevant IDs)
Key Differences: EchoWord vs Non-EchoWord
| Aspect | EchoWord | Non-EchoWord Message |
|---|---|---|
| Matching | Exact code match required | No code matching |
| Phone Validation | Validates against all campaign phone numbers | No phone validation |
| Actions | Can trigger autoresponder + contact groups | Only autoresponder from last text |
| Contact Creation | Creates contact if needed | No contact creation |
| Opt-In | Always saves opt-in record | No opt-in record |
| Expiration | Checks expiration date/time | No expiration check |
| Status Check | Checks if EchoWord is paused | No status check |
Processing Flow Diagram
Incoming Message
↓
Parse & Normalize
↓
Validate E.164 Format
↓
├─→ Global Phone Number?
│ ├─→ Yes → Fetch Global EchoWords
│ │ ├─→ Match Found?
│ │ │ ├─→ Yes → Get Campaign → Upsert Contact → Save Opt-In → Send OptinMessage → End
│ │ │ └─→ No → Send "Message received. Thank you." → End
│ │ └─→ Invalid E.164 → Log Error → End
│ │
│ └─→ No → Lookup Campaign by Phone
│ ├─→ Campaign Found?
│ │ ├─→ Yes → Save Reply Record
│ │ │ ├─→ Standard Keyword? → Process Keyword → End
│ │ │ │
│ │ │ ├─→ EchoWord Match?
│ │ │ │ ├─→ Yes → Check Status & Expiration
│ │ │ │ │ ├─→ Valid → Get/Create Contact
│ │ │ │ │ │ ├─→ Process Autoresponder
│ │ │ │ │ │ ├─→ Process Contact Groups
│ │ │ │ │ │ ├─→ Save Opt-In → End
│ │ │ │ │ └─→ Invalid → End
│ │ │ │ │
│ │ │ │ └─→ No → Find Last Sent Message
│ │ │ │ ├─→ Has Autoresponder? → Send Autoresponder → End
│ │ │ │ └─→ No Autoresponder → End (No Response)
│ │ │ │
│ │ └─→ No → Send Error Message → End
Summary
The incoming message processing system handles three main scenarios:
- Global EchoWords - Messages to global phone numbers that match global EchoWords upsert the contact, save an opt-in record, and respond with the campaign's optinMessage
- Standard Keywords (START, STOP, HELP, YES) - Immediate compliance responses
- EchoWord Matches - Automated actions with autoresponders and contact groups, validated against all campaign phone numbers
- Autoresponder Fallback - Replies to previous text messages with autoresponders
Key Features
- E.164 Validation: All phone numbers are validated for E.164 format before processing
- Phone Number Validation: EchoWords validate against all campaign phone numbers (not just primary)
- Campaign-Specific Autoresponders: Autoresponders are now campaign-specific and validated against campaign ID
- No Legacy EchoCodes: System only uses EchoWords (legacy EchoCodes removed)
Each path ensures proper compliance, contact management, and user experience while maintaining detailed logging for debugging and audit purposes.