---
id: casos/assistente-whatsapp
area: AI
usage: common
effort: medium
grain: Offerable item x tenant for the agent; message and conversation for monitoring
---

# AI assistant on WhatsApp

The customer asks on WhatsApp about a property, product or time slot and gets an instant answer drawn from a ready table, only with what is available, and is handed to a human when the AI should not answer.

## Executive summary

**For:** Companies that serve end customers on WhatsApp and want the AI to answer with the real catalog and availability.

**What it solves**

- The AI only offers what is available today, at the right price, and never invents an item.
- A message written the way the customer types finds the right item, even when the catalog is abbreviated.
- You can measure how much the AI resolved alone, how much went to an agent and how many visits it booked.

**Why it matters:** On WhatsApp the answer goes straight to the customer, with nobody reviewing it. A sold property offered as available or an outdated price costs the sale and the trust. And because the channel is external, an over-broad credential or a query built from the customer's text becomes a data leak risk.

**Business questions it answers**

- How many conversations did the AI resolve on its own this week, and how many went to an agent?
- How many visits or appointments did the AI book this month, by store or branch?
- How many customer messages arrive outside business hours?
- Which items could the AI not answer about?
- Was any sold or unavailable item offered by the AI in the last few days?

**What you need**

- The system that holds the catalog and availability connected to Nekt (CRM, ERP or website database)
- The WhatsApp tool with its message history landing in the lakehouse (connector or webhook)
- The business rule for what can be offered and when the conversation goes to a human

**What you get**

- A consumption table per tenant, one row per offerable item, with text ready for the agent
- A search index that maps the way customers write to the catalog code
- An agent credential restricted to the consumption tables
- A customer service dashboard: resolved by AI, handoff, after hours and appointments

## Detailed

### The problem

The WhatsApp agent reads the raw CRM catalog: it offers a property that was already sold, shows a zero price, cannot find the product because the catalog is abbreviated and mixes the items of two clients that share the same agent. Then nobody can say how much the AI resolved, because one-turn conversations count as service and a pre-booked status counts as a visit.

### Business rules

1. **A consumption table with only what can be offered.** The agent does not read the raw catalog. Build a consumption table with the items that pass the business rule: property flagged for the website with a status of sale, sale and rent or under negotiation; new developments separated from resale; rentals with rent above zero and below a ceiling that cuts mistyped values; active products. One row per item, with the columns customers ask about: type, neighborhood, bedrooms, area, price and link. (Avoid: Point the agent at the whole CRM table and rely on the prompt to filter.)
2. **Ready text and formatted price in the table.** Nested fields (amenities, features, photos) become readable text, one label per field. Prices use the Brazilian format (R$ 1.250.000,00). A zero or null price becomes a fixed sentence, such as 'Contact us for pricing', never R$ 0,00. New developments show 'starting at'; resale shows the price. The first photo comes with a public URL. (Avoid: Let the AI format prices and parse nested JSON.)
3. **Search the way the customer writes.** The lakehouse SQL engine has no string similarity function. Precompute an inverted index weighted by term rarity and an alias dictionary validated by the business (qj for queijo, bov for bovino). Mark which catalog word is the category: in many ERPs the first word of the description is the product and the rest is brand or flavor. Without it, someone asking for picanha gets a picanha-flavored breaded snack. (Avoid: LIKE on the product name with the message text.)
4. **The agent never builds SQL from customer text.** An external channel is an attack surface. Queries are fixed in the backend; customer text only enters as a parameter, validated against an allowed character list. The agent credential is an MCP token scoped to the consumption tables, never a full-access API key. The scope is frozen at creation: adding a table means issuing and swapping the token, and the token expiry date goes into monitoring. (Avoid: An agent free to generate SQL with an admin key.)
5. **tenant_id on every row and separate caches.** When the same agent serves several clients, every row carries the tenant_id and the agent always filters by it. The item cache and the contact cache live in separate tables, each with its tenant. A new client comes in by configuration, not by copying another client's transformation. (Avoid: A single cache with every client's properties, filtered by the prompt.)
6. **What the customer may see is a governance decision.** Exposing stock, cost or another client's data on an external channel requires written approval. In a real case, answering whether an item is in stock was approved, but not how many. Record the condition with the approval: if the agent starts showing quantities, the approval no longer holds. Personal data of other contacts never goes into an answer. (Avoid: Answering the stock quantity because the column is in the table.)
7. **Not found and unavailable are different answers.** If the item does not exist in the catalog, the agent says it could not find it and offers similar ones. If it exists but is out of stock, sold or reserved, it says it is unavailable. A sold or reserved item never appears as available. (Avoid: The same 'we don't have it' answer for both cases.)
8. **Human handoff has triggers and a log.** Write down when the AI hands the conversation to an agent: price negotiation, complaint, document submission, question outside the catalog or customer request. Every transfer is logged with reason, queue and time. The KPI is the share of conversations resolved without handoff, per queue and closed day. (Avoid: The AI trying to answer everything, with no record of when it gave up.)
9. **Measure what happened, not the status.** A real conversation has more than one turn; a one-turn conversation is just the opening message. An appointment counts only when it exists in the appointments table; statuses such as pre-booked or in progress are not visits. If the customer and the AI store the same timestamp on each turn, response time cannot be computed and should not be reported. (Avoid: Counting conversations and service statuses as AI results.)
10. **Freshness is part of the answer.** The consumption table runs on an event right after the source, never on a manual trigger. Every row stores the last load date. If the load is late beyond the agreed limit, the agent does not confirm availability and says an agent will confirm. (Avoid: Refreshing the cache once a week or by hand.)

### How to measure the AI's customer service

From the history of conversations, messages, transfers and appointments.

- **More than one turn between customer and AI** → Real conversation
- **Closed with no transfer to a human** → Resolved by AI
- **Transfer logged with a reason** → Handoff
- **Customer message outside configured hours** → After hours
- **Record in the appointments table** → Real appointment
- **Delivery status with error** → Failed message
- **Pre-booked, in progress, one-turn conversation** → Does not count as a result

### Definitions

| Metric | Definition |
|---|---|
| Eligible item | item that passes the business display rule on the last load: active, cleared for publication and with an offerable status |
| Real conversation | conversation between customer and agent with more than one turn, in the period |
| Resolved without handoff | conversations closed on the closed day, in local time, with no transfer to a human / conversations closed on the same day |
| % after hours | customer messages outside store hours / customer messages in stores with configured hours; stores without hours are left out |
| Appointment | records created by the AI in the appointments table in the period; pre-booked status does not count |
| Search hit rate | test questions where the right item is among the top N results / test questions |
| Time to final answer | from the customer message to the agent's last final answer, ignoring intermediate waiting messages |

### Pitfalls

- **Unlisted item offered.** The agent read the whole CRM catalog and offered properties that were not cleared for publication or were already sold. How to avoid: Apply the display rule in the consumption table, not in the prompt.
- **Wrong product, with confidence.** Search returned a picanha-flavored breaded snack to someone asking for picanha, because the short description won the ranking. Tightening the threshold to force a single answer made it worse. How to avoid: Mark the category term and measure the hit rate within the top N.
- **Status counted as a visit.** Dozens of free-text service statuses were grouped and pre-booked was counted as a visit booked by the AI. How to avoid: An appointment only exists in the appointments table.
- **AI switched on that never talked.** In one snapshot, a large share of stores had the AI switched on and no real conversation. The AI-on flag defaulted to true even without the module contracted. How to avoid: Count as operating only stores with the module contracted and the AI on, and measure real conversations.
- **Media that expires.** Audio and image links delivered by the WhatsApp tool expire in about 30 days, and the history lost the content. How to avoid: Download media and transcribe audio incrementally right after each load.
- **A history that moves.** The service tool API only returned the last few weeks of tickets. The table was a moving window and the previous month had less than half of the real tickets. How to avoid: Accumulate in your own table, one record per id, with the latest version winning.

### Acceptance test

- [ ] No item in the consumption table is sold, reserved, inactive or unpublished in the source, on the same load date.
- [ ] For each tenant, the item count in the consumption table matches the count of eligible items in that client's CRM.
- [ ] On a set of at least 30 real customer questions, the right item is among the top 3 results in at least 9 out of 10.
- [ ] A query with the agent token on any table outside the consumption tables returns an access error.
- [ ] Conversations resolved by AI + transferred conversations = total conversations closed that day, with nothing left over.

### Context document

```text
WhatsApp customer service assistant
- Answer only with data from the agent consumption tables: <items table>, <appointments table>. Never use the raw catalog.
- Always filter by tenant_id <tenant>. Never show an item or contact from another tenant.
- Available item = item present in the consumption table on the last load. Sold, reserved or inactive items are not offered.
- If the item does not exist, say you could not find it and offer up to 3 similar ones. If it exists and is unavailable, say it is unavailable.
- Price: use the formatted field. Missing price: 'Contact us for pricing.' New developments: 'starting at'.
- Stock: say whether there is stock, not how much, unless there is a recorded approval.
- Never share personal data of other contacts, cost, margin or commission.
- Hand over to an agent for price negotiation, complaints, document submission, questions outside the catalog or a customer request. Log the reason.
- If the last load is older than <n> hours, do not confirm availability: say an agent will confirm.
- Outside store hours, share the opening hours and offer to book an appointment.
Client exceptions:
- <client>: display rule = <field> equal to 'Sim' and status in <list>.
- <client>: alias dictionary approved on <date> by <team>.
- <client>: stock may be shared as a quantity (approved on <date>).
```

### Variations

- **Website and portals:** The same table feeds the website and the XML feed for real estate portals, with public photo URLs.
- **Semantic search:** One text row per item sent to a vector database, with metadata to filter by tenant and status.
- **Internal salesperson:** The same index serves the salesperson who asks on WhatsApp whether the distribution center has the product, without exposing the quantity.
