Sell on WhatsApp with a catalog and a cart
A store gets a WhatsApp message, the agent greets, asks what the person is looking for, shows products from the catalog, receives the cart the person builds, and tells the team to close the sale. When the person asks for a human, the case moves to a stage where your team answers. Weeks later, a template campaign brings quiet contacts back.
Who it is for. Stores and service businesses that sell from a catalog and close the sale with a person. Scopes. agents:write, pipelines:write, knowledge:write, skills:write, actions:write, webhooks:write, whatsapp:write, cases:read, cases:write, cases:converse, turns:read, contacts:write, files:write is not needed. Use a key with all of them, or the one the setup guide creates.
Code
The runnable version of every step is in examples/use-cases/whatsapp-sales-agent. The TypeScript blocks of this page come from that script, which ran against a real number. It stops before the campaign, because that step messages people.
0. Set up
Every example reads the key from LELEMON_API_KEY and the TypeScript steps use the SDK. The cURL tabs send the same requests.
Code
1. Write the agent
The prompt is the product. This one gives the agent a role, a voice, the order in which it asks for data, how it uses the catalog, hard limits and exactly when to hand over. The catalog id and the retailer ids go in the prompt: send_products takes them from there, so the agent never invents one.
The agent starts as a draft. The channels say where it can answer: whatsapp for the number, api for cases you open yourself. A low temperature keeps prices and policies stable. See Agents for every field.
What you get:
Code
2. Create the pipeline and its stages
A pipeline is the path of a sale. The entry stage is where every new case starts and where the agent works. Needs a person is where a handed-over case lands, and the next steps use stageId to refer to a stage by its name.
What you get:
Code
3. Create the fields of the case
Fields are the data the sale needs. source: "agent" means the agent fills them with save_case_data while it talks; source: "system" means only your backend writes them. A stage can require fields before a case enters it: Order placed needs the comuna and the order reference, so a case cannot jump there half empty.
What you get:
Code
4. Give the agent knowledge
Policies that change and are too long for a prompt go in a knowledge collection. The agent searches only the collections you grant it.
A document starts as processing. Listen for knowledge_document.ready or knowledge_document.failed before you count on it. See Knowledge.
5. Write the skills
A skill is a procedure the agent opens only when the conversation needs it. Only its name and description travel in the prompt; the steps are loaded on demand, which keeps the prompt short.
There is no tool to grant for skills. As soon as an agent has one, Lelemon gives it the tool that opens them on every turn, and GET /v2/agents/{id}/skills is the list of what it can open.
6. Register the stock check as an action
An action is an HTTP endpoint of yours that the agent calls as a tool. This one answers how many units are in stock. Lelemon signs every call; your server verifies it with the signing secret of the action (Actions and MCP). audience: "customers" lets an agent that talks to the public use it.
origin in the answer is the site your key must be allowed to call. If it is not, the call answers 403 action_origin_not_allowed and an administrator adds the site to the key.
7. Grant the tools
A tool does nothing until you grant it to the agent. save_case_data limits which fields the agent may write. transfer_to_human takes the stage the case moves to and the goodbye the contact reads, in and out of business hours. The goodbye is written by the tool, not the model, so the agent cannot promise what the team will not do.
What you get:
Code
8. Receive events
Register an endpoint for what your backend must react to: message.received (it carries the type, order for a cart, never the text), case.escalated and case.stage_entered. Your server verifies each delivery as in Verify signatures.
9. Activate and connect the number
activate turns the agent on and says in readiness.missing what still keeps people from reaching it. An empty list means it is reachable.
setupUrl opens the Meta onboarding for the number you pass in phone; the number appears in GET /v2/whatsapp/phone-numbers when the owner finishes, and phone_number.connected fires. The script does not connect a number: it reads the id of one you already connected from LELEMON_WHATSAPP_PHONE_NUMBER_ID.
10. Connect the catalog
The catalog is created in Meta Commerce Manager and connected in WhatsApp Manager. Save its id on the number, and turn on the cart button and the catalog icon. A product message only goes out when the catalog_id of the message is the one saved here; otherwise it answers 422 catalog_not_connected.
What you get:
Code
11. A customer writes first
The customer writes to the number from WhatsApp. The agent answers and your webhook receives message.received.
Code
The agent answers in a few seconds. case.turn_completed tells you the turn ended; then read the thread and the turn. The turn shows which tools ran, with their input and output:
Code
The agent saved interest, checked the stock with the signed call to your server, and sent a product message from the catalog. Its wording changes from run to run; the tools it calls do not.
12. The customer sends a cart
When the person fills the cart from the catalog and sends it, the message has order: { catalogId, items }. The webhook says type: "order"; read the items from the message. Your backend creates the order in its own system, writes the reference in the field with source: "system" and moves the case.
If the case lacks a required field, move answers 422 required_fields_missing with the field in param. Here the agent already saved delivery_comuna from the message, and your backend wrote order_reference, so the move succeeds:
Code
13. The customer asks for a person
The prompt lists when to hand over: a human requested, a discount, a bulk order. The agent calls transfer_to_human. The case goes to human control and to Needs a person, the contact reads the goodbye of the tool and case.escalated fires with the history.
A person writes with author: "team" while the case is in human control; it needs the 24-hour window of WhatsApp. release-control hands the case back to the agent, which then answers with the messages of the team in its context.
Code
14. Re-engage contacts with a template campaign
Outside the 24-hour window only an approved template goes out. Create it, wait for approved (WhatsApp reviews it), then send a campaign to a list of contacts. onReply names the agent that continues when someone answers.
The preview shows who gets the message, who is skipped and why, and a rendered sample before anything goes out. Launching freezes the list. See Run a campaign.
Code
Notes
- A wrong catalog id shows up as a failed message.
- Past the 24-hour window only an approved template goes out.
What you see in the dashboard
- Inbox: the case of Ana with the thread, the product message, the cart and who answered (agent or team). The fields
interest,delivery_comunaandorder_referenceshow in the card. - Pipeline board: the case moves from
QualifyingtoOrder placed, and a handed-over case waits inNeeds a person. - Agent, Activity: each turn with the tools it called, tokens and cost.
- WhatsApp, Campaigns: the recipients of the campaign with their status.
Before customers write
- Save the real catalog id on the number.
- Turn on the recipient allowlist while you validate.
What's next
- Schedule meetings from the same conversation.
- Approve agent actions before an agent moves money.
- WhatsApp messages: every format and what the person can send back.
- API reference:
POST /v2/agents,POST /v2/pipelines,PUT /v2/agents/{id}/tools/{toolId},POST /v2/campaigns.