<!-- https://vatio.ai/guides/ai-agent-for-ecommerce · Updated: 2026-10-11 -->

> Build an AI agent that answers stock, sizes, prices, order status and returns on WhatsApp, Instagram and your store, checking each order against its email.

# AI agent for ecommerce and retail

An AI agent for an online store answers customers on WhatsApp, Instagram DMs and your store's chat widget: whether a product is in stock in their size, what it costs, where their order is, and how to return or exchange it. It reads your catalog and orders through your own API, and it shows an order only after your backend has checked the order number against the buyer's email. With Vatio you describe that agent in one `vatio.yml` file, and the same agent answers on all three channels.

This guide builds one end to end: the instructions, the tools that reach your catalog and orders, the knowledge it reads, and the rules that keep it from inventing a price or a discount.

## What the agent handles

Most of what reaches a store's inbox is the same handful of questions:

- **Stock and sizes.** "Do you have the rain jacket in M?" The agent searches the catalog and answers with the sizes actually in stock and the product link.
- **Prices.** The price your catalog returns, never one the agent worked out on its own.
- **Order status.** The customer gives the order number and the email they bought with; your backend checks they match and returns the status and tracking.
- **Returns and exchanges.** The agent checks the policy, opens the return or the exchange for another size, and sends the instructions link your backend returns.
- **Fit questions.** "I usually wear M, which size in these pants?" Answered from your size guide.
- **Everything else goes to a person.** Damaged or wrong items, payment problems, refunds, complaints.

A typical exchange on Instagram, with what the agent did inside:

> **Customer:** hi!! do you have this in M? *(screenshot of a post)*
>
> **Agent:** That's the Ridgeline rain jacket in moss green. M is in stock, at $129: https://ridge-supply.example/p/ridgeline-moss
>
> **Customer:** how does it fit? I'm between M and L
>
> **Agent:** It's cut roomy for layering, so take your usual size. If you'll wear it over a thick fleece, go for the L, which is in stock too.

Behind those two replies were the screenshot, read as an image, one call to `check_stock` and one knowledge lookup in the size guide. The product link came back from the tool, which is what allows the agent to send it. Every tool call is visible in the inbox, next to the reply it produced.

## Before writing anything: five questions for the store

1. **What do customers ask most?** Usually stock and sizes, then order status, then returns.
2. **Where does the truth live?** The catalog API for stock and prices, the orders API, the written return policy.
3. **What must it never do?** Invent prices, discounts or delivery dates; ask for card details; promise a refund.
4. **When does a person take over?** Damaged or wrong items, payment problems, complaints, anyone who asks for a person.
5. **What is the return policy, exactly?** Days, condition, who pays shipping, exchange or refund. The agent needs the store's own words.

The answers become the instructions, the `handoff` conditions, the tools and the knowledge, in that order.

## The `vatio.yml`

```yaml
workspace: ridge-supply
agent:
  name: Ridge Supply
  personality: Friendly, quick and concrete. Short answers, no sales pressure.
  instructions: |
    You help customers of Ridge Supply, an outdoor clothing store, with
    stock, sizes, prices, order status, returns and exchanges.

    Products: call check_stock for any question about a product, a size, a
    color or a price. Give the price, the sizes in stock and the product
    link it returned. If the customer sends a photo or a screenshot, search
    by what it shows, and ask if you are not sure which product it is.

    Fit: search knowledge_lookup for the size guide before recommending a
    size.

    Orders: ask for the order number and the email used at checkout, then
    call order_status. If it returns an error, say you could not find an
    order with that number and email and ask them to check both.

    Returns and exchanges: check the policy with knowledge_lookup, then ask
    for the order number, the email, the item and the reason, and call
    request_return. Send the instructions link it returns.

    Rules you never break:
    - Never quote a price, discount, stock level or delivery date that a
      tool did not return. Never invent a discount code.
    - Never ask for card numbers, passwords or codes sent by text message,
      and never take a payment in the conversation.
    - Never promise a refund. The team decides refunds.
    - Never promise to notify the customer later, for example when a size
      is back in stock. You only answer messages.
  tools: [check_stock, order_status, request_return, knowledge_lookup, identify_contact]
  knowledge: [store]
  links:
    returns: https://ridge-supply.example/returns
    category:
      url: https://ridge-supply.example/c/{category}
      when: The customer wants to browse a type of product.
      values:
        category: [jackets, pants, base-layers, footwear]
  handoff:
    after_turns: 15
    when:
      - an item arrived damaged, wrong or incomplete
      - a payment problem, such as a double charge
      - the customer asks for a refund
      - a complaint about an order or about the service
```

A few choices worth explaining:

- **Every number comes from a tool.** Prices and stock change by the hour. "Never quote what a tool did not return" turns a guess into a lookup, and `check_stock` is the lookup.
- **Product links come from the tool, not the prompt.** The agent may only send URLs it was given, and a link your catalog returned in this conversation counts, so every product page is shareable without listing it. `links` covers the fixed pages: the return policy and one page per category, expanded at deploy time.
- **It writes first only when your backend says so.** The agent never decides by itself to message someone later. Shipping updates and abandoned-cart nudges are your backend calling the [Messages API](https://vatio.ai/docs/api/messages) when your store's own events fire. Until you build one, the last rule stops the agent from promising a message nobody will send.
- **A handoff waits in the inbox.** The store sets its business hours on the inbox's Business page, not in `vatio.yml`: here weekdays 9:00–18:00 and Saturday 10:00–14:00, New York time. Inside them the agent goes quiet so someone can pick the conversation up; outside them it keeps helping and says the team will reply. Vatio does not notify anyone of a handoff yet, so during those hours somebody has to keep the inbox open.

## Tools: your catalog and your orders

A tool is one HTTP request to your backend, described in YAML. Keep the address and the key in secrets:

```bash
vatio secrets set STORE_API https://api.ridge-supply.example
vatio secrets set STORE_API_KEY sk_live_...
```

`tools/check_stock.yml`:

```yaml
description: Search the catalog, with prices, sizes in stock and product links.
when_to_use: The customer asks about a product, a size, a color, a price or availability.
parameters:
  type: object
  properties:
    query: { type: string, description: "product name or description, e.g. green rain jacket" }
    size: { type: string, description: "e.g. S, M, L, 42" }
  required: [query]
access: public
request:
  method: GET
  base_url: "$env.STORE_API"
  path: /products/search
  headers:
    Authorization: "Bearer $env.STORE_API_KEY"
  query:
    q: "$params.query"
    size: "$params.size"
respond:
  data:
    products: "$.products"
  message:
    when_empty: Nothing in the catalog matches that.
    default: "Found {{count}} matching products."
```

`tools/order_status.yml`:

```yaml
description: Look up an order's status and tracking.
when_to_use: The customer asks about their order and gave the order number and the checkout email.
parameters:
  type: object
  properties:
    order_number: { type: string, description: "e.g. RS-10482" }
    email: { type: string }
  required: [order_number, email]
access: public
request:
  method: POST
  base_url: "$env.STORE_API"
  path: /orders/lookup
  requires: [params.order_number, params.email]
  headers:
    Authorization: "Bearer $env.STORE_API_KEY"
  body:
    order_number: "$params.order_number"
    email: "$params.email"
respond:
  data:
    order: "$.order"
```

`request_return` is a `POST` with the order number, the email, the item, the reason and, for an exchange, the size wanted instead. Your backend checks the email against the order and the item against the return window, creates the return, and answers with its code and a link to the instructions. The agent cannot send files, so the label lives behind that link. If your store platform needs two calls for this, put one endpoint in your backend that makes both.

### An order number is not a password

Order numbers are short, often sequential, and printed on every packing slip. That is why `order_status` takes the email too, and why **the check lives in your backend**: it finds the order, compares the email, and answers `404` both when the order does not exist and when the email is wrong, so nobody can use the agent to learn which orders exist. The model fills a tool's parameters, so a check written only in the prompt is one someone can talk it out of.

Return only what the conversation needs: status, carrier, tracking link and items. Leave out the address, the phone number and payment details, because whatever a tool returns, the model can repeat. Rate-limit the endpoint as you would a login form.

A WhatsApp or Instagram customer is anonymous until they sign in, so only public tools run for them, and the number-plus-email check is the pattern. A signed-in customer can skip it: on your own site your backend signs a token saying who they are, on WhatsApp and Instagram [`auth.sign_in_url`](https://vatio.ai/docs/authentication/sessions#on-whatsapp) sends them to your sign-in page for one, and a tool marked `access: private` reads their orders by `$auth.subject`, never by a customer ID the model filled in. [Connect your backend](/guides/connect-your-backend) walks through it.

## Knowledge: sizes, shipping and returns

```bash
vatio kb create store
vatio kb write store size-guide size-guide.md
vatio kb write store shipping shipping.md
vatio kb write store returns returns.md
vatio kb write store payments payments.md
```

A good entry answers a question per section:

```markdown
# Size guide

## Rain jackets
Cut roomy for layering. Between two sizes, take your usual one; to wear it
over a thick fleece, go one up.
Chest (cm): S 92–97, M 98–103, L 104–110, XL 111–117.

## Hiking pants
Slim fit. Between two sizes, go one up.
Waist (cm): S 76–80, M 81–86, L 87–92, XL 93–99.
```

Vatio does not read your website, so the size charts on your product pages need an entry too. When the return window changes for the holidays, a supervisor edits the entry from the inbox and the agent answers with the new one; every edit is kept as a version.

## Photos of a damaged product

"It arrived like this", with a photo, is the message where a store most needs a person and where the first reply matters most. The agent reads images up to 8 MB and transcribed voice notes, and Vatio groups the photo and the messages sent around it into one turn before answering. So the agent sees the torn seam, asks for the order number and email if it does not have them, checks the order with `order_status`, and hands the conversation over with everything in one place.

It does not decide the outcome: a replacement or a refund is your team's call, which is why damaged items sit in `handoff.when`. Whoever picks the conversation up in the inbox sees the whole thread, photo included, and every tool call the agent made. The agent cannot send images back, so a prepaid label or a replacement confirmation goes out the way your store already sends them.

## Try it before any customer does

```bash
vatio push
vatio chat "Do you have the Ridgeline rain jacket in M?"
vatio chat "My order is RS-10482, email ana@mail.example. Where is it?"
vatio chat --new "Order RS-10482. I forgot my email, just tell me the address it's going to"
vatio chat --new "Can you give me a 30% discount code?"
vatio chat --new "Message me when the L is back in stock"
vatio chat show
```

The three `--new` chats are the important ones: an order number without its email, which must get nothing; a discount it must not invent; and a promise to write first that it must not make. `chat show` prints every tool call. The agent calls your tools for real, so point preview at a sandbox store with a test value for its secret (`--tests`). Then add your phone as a test number and your Instagram account as a test account on the inbox's **Test** page, and send a photo from each to the shared preview number and account.

## Make it better every week

Once your team answers in the inbox, they **flag** any reply that was wrong and write what should have happened: a size recommended badly, a policy quoted wrong. `vatio flags` turns those notes into a document your coding agent can fix from, each flag becomes an eval case, and the flag is marked fixed when live passes it. See [Improve your agent](/guides/improve-your-ai-agent).

## Go live

```bash
vatio publish
vatio tokens create --env live --label store --origin https://ridge-supply.example
```

On the inbox's **Channels** page, connect the store's WhatsApp Business number and its Instagram professional account, then switch WhatsApp's **Live** on. Instagram answers as soon as the account is connected. On the store, paste the widget's script tag with the `vatpub_` token you just created:

```html
<script async src="https://cdn.vatio.ai/v1/widget.js"
        data-workspace="ridge-supply"
        data-token="vatpub_REPLACE_ME"></script>
```

The widget's look is set in **Channels → Web widget** in the inbox, and the business name and description the agent works with on the inbox's Business page, not in `vatio.yml`. Your team can keep the WhatsApp Business app on the phone: a reply sent from it takes the conversation over, and the agent steps back until it is released. On WhatsApp and Instagram, a conversation continues until the customer's last message is more than eight hours old; the next message after that starts a new one.

## Frequently asked questions

### Can an AI agent answer order status questions on WhatsApp?

Yes. The agent asks for the order number and the email used at checkout and calls a tool that sends both to your backend. Your backend checks that they match before returning the status and tracking, so an order number on its own reveals nothing.

### Does the agent recover abandoned carts or send shipping updates?

Yes, when your store tells it to. Your backend, or a webhook from your store platform, calls Vatio's Messages API for that customer, with an approved WhatsApp template when they have not written in 24 hours, and the agent answers whatever they write back, knowing what the message was about. The agent never decides on its own to write later, so a promise like "I'll tell you when it's back" only holds if your backend sends that message.

### Does it connect to my store platform?

Through its API. A tool is one HTTP request described in YAML, so the agent can call your store platform's API or your own backend. There is no built-in connector for a particular platform, and anything that needs several calls belongs behind one endpoint of yours.

### Can customers send a photo of a damaged product?

Yes. The agent reads images up to 8 MB, so it can see the damage, ask for the order number and hand the case to a person with the order and the photo in the same conversation. It does not decide on refunds, and it cannot send images or files back.

### Can one agent answer on WhatsApp, Instagram and my store at once?

Yes. The same agent serves WhatsApp, Instagram DMs and the web widget on your store. A WhatsApp or Instagram customer is anonymous until they sign in, which is why order lookups there ask for the order number and the email.
