# WABA Message Flow

This file explains the WhatsApp Business message flow in plain English.

Use this file when you want to understand:

- how a WhatsApp message enters the system
- what database records are used
- how the system decides what to send back
- how outbound replies, files, and media are sent

If you want the AI-only explanation, read [WABA_AI_FLOW.md](/e:/Coding/api.Insale.ai/WABA_AI_FLOW.md).

## What This File Covers

This file covers the message pipeline for:

- inbound WhatsApp webhook messages
- normal AI replies
- fixed business-rule replies
- meetings
- file/document sending
- manual outbound text and media

It does not focus on Meta onboarding or account connection setup. It focuses on message handling.

## Main Routes

`GET /webhook`

- Used only for Meta webhook verification.

`POST /webhook`

- Main inbound route for WhatsApp messages.
- This is the route that receives customer messages from Meta.

`POST /send`

- Sends a manual text message from your app to WhatsApp.

`POST /send-media`

- Sends a manual media message from your app to WhatsApp.

## Main Records Used

The message flow mainly uses these records:

- `Whatsapp`: the connected WhatsApp account for the user
- `BWAMessage`: all inbound and outbound WhatsApp chat messages
- `Lead`: the current customer or lead
- `Company`: company name, website, and some company-level links
- `AiAgent`: the agent identity and instructions
- `UserFile`: uploaded knowledge files and documents
- `Offer`: offer and discount records
- `Meeting`: real scheduled meetings
- `PendingMeeting`: temporary proposed meeting times waiting for confirmation
- `ScheduleSettings`: timezone, business hours, blackout dates
- `notificationSettings`: settings for sending internal notifications

## End-to-End Message Flow

### Step 1: Meta sends the inbound WhatsApp webhook

Meta sends the message payload to `POST /webhook`.

The route reads:

- sender number
- WhatsApp business `phone_number_id`
- message body
- button/list reply text
- media information if present

### Step 2: The system finds the correct WhatsApp account

The route uses `phone_number_id` to find the correct `Whatsapp` record.

This matters because the system must reply from the exact WhatsApp number that received the message.

### Step 3: The system extracts usable text

The inbound message can be:

- text
- button reply
- list reply
- media with caption
- media without caption
- reaction

The code normalizes this into a single text value so later logic can process it.

### Step 4: The inbound message is saved

The system stores the incoming message in `BWAMessage`.

This gives the system:

- full conversation history
- later context for replies
- a record of what happened

### Step 5: The system finds the lead

The sender phone number is matched to a `Lead`.

The lead is used for:

- customer name
- campaign
- assigned agent
- follow-up state
- current lead status
- user ownership

If needed, the webhook also normalizes phone matching so different number formats still resolve to the same lead.

### Step 6: The system resets follow-up timing

When a real inbound reply arrives, the lead's follow-up counters and timestamps are reset.

This prevents automated follow-ups from continuing as if the lead is still silent.

### Step 7: The system loads the company

The route loads the `Company` record for the lead's owner.

This gives the system:

- company name
- website
- official company context for replies

### Step 8: The route calls `generateReplyForWhatsapp()`

This function is the main decision engine for WABA messages.

It can return:

- a normal reply text
- `sendFiles: true`
- no reply if AI is disabled or campaign rules stop the flow

## What `generateReplyForWhatsapp()` Does

This function mixes:

- business rules
- schedule rules
- history checks
- database checks
- AI-based classification
- final reply generation

The AI-specific part is explained in [WABA_AI_FLOW.md](/e:/Coding/api.Insale.ai/WABA_AI_FLOW.md).

This file explains the practical message behavior.

### Step 9: It checks whether WhatsApp AI is enabled

If channel AI is disabled, the function stops early.

### Step 10: It loads recent chat history

The system pulls recent `BWAMessage` rows for the same conversation.

Important rules:

- it prefers history for the current `phone_number_id`
- it excludes the current inbound message
- it uses history for continuity, not as the main source of company facts

### Step 11: It checks what the last bot message was about

This is used for short follow-up replies like:

- yes
- no
- send more details
- link please

The system checks whether the last bot message was about:

- meeting intent
- meeting time
- offers
- supervisor forwarding

### Step 12: It applies hard decision branches first

Before the final AI reply is generated, the system checks special branches such as:

- not interested
- qualification
- human intervention
- service refocus
- name recall
- company documents
- meeting flow
- meeting link requests

These branches matter because some replies should not be left to free-form AI text.

## Message Behaviors by Topic

## Name Recall

If the user asks:

- what is my name
- do you remember my name
- I told you before

the system tries to answer from:

- lead name
- lead first/last name
- recent received messages

It does not forward this kind of message to the supervisor.

## Service Refocus

If the user asks unrelated general questions, the system does not continue random off-topic chat.

It redirects the conversation back to the company's services.

## Qualification / Not Interested / Human Intervention

If the system strongly detects one of these, it updates the lead record.

Examples:

- `Qualified`
- `Not-interested`
- `Human-Intervention`

This is not only a message reply. It is a real database status change.

## Meeting Flow

The meeting flow is one of the biggest message branches.

### Step 13: The system tries to read the user's requested meeting time

It uses date parsing and AI fallback to understand:

- explicit date/time
- relative date/time
- multilingual time requests

### Step 14: The system checks schedule rules

It checks:

- timezone
- business hours
- enabled days
- blackout dates

### Step 15: The system checks existing meetings and pending meeting history

Before booking a slot, it checks:

- real scheduled meetings
- fresh pending suggested slots
- a 30-minute gap between meetings

This is important because it stops same-time overlap and keeps spacing between meetings.

### Step 16: If the requested time is not available, the system suggests another slot

The system now finds the next valid free slot.

If the requested time is busy or invalid, it:

- saves a `PendingMeeting`
- replies with the alternative slot
- waits for user confirmation

### Step 17: If the user confirms the pending slot, the system tries to create the real meeting

When the user replies positively, the system:

1. tries to create the real meeting
2. saves a `Meeting` record only if creation succeeds
3. deletes the pending suggestion
4. replies with the real result

### Step 18: Meeting link handling

If the user later asks for the meeting link, the system first checks saved meeting data.

It can send:

- the real saved meeting link
- an official calendar link if configured

It should not invent a fake link.

### Step 19: Fake meeting confirmation is blocked

The code is now designed so it should not say a meeting is confirmed if the actual meeting creation failed.

If real creation fails, the system should send:

- a failure message
- or an official calendar link

but not a fake success message.

## Company Documents / Portfolio / Files

### Step 20: The system detects company profile requests

If the user asks for:

- company profile
- brochure
- catalog
- portfolio
- PDF
- documents

the system checks for external `UserFile` records.

### Step 21: If actual external files exist, the system sends them

When `generateReplyForWhatsapp()` returns `sendFiles: true`, the webhook route:

1. sends a short confirmation text
2. sends each file one by one through WhatsApp media messages
3. stores each outbound message in `BWAMessage`

### Step 22: If no sendable files exist, the system falls back

If there are no real external files:

- it may answer from knowledge text if available
- otherwise it sends the document-information fallback

## Offers and Discounts

### Step 23: The system reads real `Offer` records

The system loads offer data from the database.

It does not rely only on chat history for offers.

### Step 24: The system decides whether this message is really about offers

It separates:

- actual offer or discount requests
- generic detail requests
- negotiation
- follow-up on an earlier offer conversation

### Step 25: Offer answers should use real data

Offer replies are based on `Offer` records, not random AI guesses.

The system also checks validity and whether dates are current, expired, or unclear.

## Company Knowledge and Website

### Step 26: The system loads uploaded user files

This is one knowledge source.

### Step 27: The system loads website content

It tries to read the live website first.

If live fetching fails, it can use cached website content.

### Step 28: The system combines all knowledge

For factual replies, the system combines:

- user files
- website content
- offer data

Conversation history is added after these sources, not before them.

## Final Reply Sending

### Step 29: The webhook receives the result

The result from `generateReplyForWhatsapp()` can be:

- reply text
- file-send instruction
- no reply

### Step 30: The system sends the outgoing WhatsApp message

If it is a normal text reply, the webhook sends the message through Meta Graph API.

### Step 31: The outbound message is saved

Every sent reply is stored in `BWAMessage`.

This keeps the chat history complete.

### Step 32: Socket events are emitted

The system pushes live updates so frontend chat and campaign views refresh correctly.

## Manual Outbound Message Flow

## `/send`

This route is used for manual text messages from the app.

What it does:

1. finds the connected WhatsApp account
2. sends the text through Meta
3. saves the outbound record
4. updates related lead timestamps

## `/send-media`

This route is used for manual media sending from the app.

What it does:

1. uploads the media to Meta
2. sends the media message
3. saves the outbound record
4. updates related lead timestamps

## Important Non-AI Rules

These parts are controlled by code and database state, not free-form AI:

- which WhatsApp account is active
- which lead owns the conversation
- whether the last message belongs to the same chat
- whether files really exist
- whether offers really exist
- whether a meeting is scheduled
- whether a meeting slot is free
- 30-minute meeting spacing
- lead status updates

## Short Summary

The WABA message flow is a pipeline.

In simple terms it works like this:

1. Meta sends a message
2. the system finds the right WhatsApp account
3. the system saves the inbound message
4. the system finds the lead and company
5. the system decides whether to use a hard branch or AI
6. the system checks meetings, offers, files, and rules
7. the system sends the reply
8. the system saves the outbound result

If you want the AI-only explanation, read [WABA_AI_FLOW.md](/e:/Coding/api.Insale.ai/WABA_AI_FLOW.md).
