Answer order and stock questions from your WooCommerce shop
The goal: stop answers being written around the facts. “Where’s my order?”, “is this in stock?”, “was I actually charged?”, “why won’t my discount code work?” — none of those are writing problems. The answer exists in your shop, and someone is being paid to go and look it up. Connect the shop and a flow does the looking, so the reply is grounded in the real order rather than in a plausible guess.
This is the other half of a support desk: Answer Zendesk tickets brings the question in, these steps find the answer.
Step 1 — Connect your shop
Section titled “Step 1 — Connect your shop”Go to Settings → Connections → Apps and open the E-commerce section, then pick WooCommerce.
In WordPress, go to WooCommerce → Settings → Advanced → REST API and generate a key pair with Read permission. Then paste into Routario:
- Store URL — your shop’s home page, e.g.
https://www.yourshop.com. - Consumer key — starts
ck_. - Consumer secret — starts
cs_.
Click Connect. Routario reads a single product back as a check — a product rather than an order, so testing the connection doesn’t pull customer data. Your key and secret are stored encrypted and never shown again.
Two things that will be refused, both on purpose:
- A plain
http://shop. The key and secret travel on every request, and over plain http they travel in the clear. - Credentials in the address. WooCommerce also accepts the key and secret as
?consumer_key=…&consumer_secret=…, which is what most tutorials show. Routario won’t do it: secrets in a URL end up in access logs, proxy logs and browser history.
If Connect fails, the message tells you which of the two usual causes it was: a 403 almost always means the key was created with the wrong permission (Write-only instead of Read), and a 404 means the address isn’t a WooCommerce shop.
Step 1b — Say what “Out of stock” means in your shop
Section titled “Step 1b — Say what “Out of stock” means in your shop”On the same page there is one more question, and it is worth thirty seconds: What “Out of stock” means in this shop.
WooCommerce gives you three stock states — In stock, Out of stock, On backorder — and attaches no commercial meaning to any of them. Shops use them differently, and the difference is invisible in the data. Many shops run this convention:
- On backorder — we still sell it, there just isn’t one on the shelf today.
- Out of stock — we have stopped selling this. It is finished.
If that is how your shop works, choose The product is discontinued. Every
lookup then reports an extra field, availability, alongside the raw stock
state:
| Your stock state | availability |
|---|---|
| In stock | available |
| On backorder | temporarily_unavailable |
| Out of stock | discontinued |
If your shop means Out of stock literally, choose Just out of stock right now instead, and nothing is ever reported as discontinued.
Step 2 — Look one thing up
Section titled “Step 2 — Look one thing up”Find WooCommerce order
Section titled “Find WooCommerce order”The workhorse. Give it an order number or a customer e-mail:
- With an order number, it fetches that order.
- With an e-mail, it returns their most recent order, and lists any older
ones in
other_ordersso a reply can ask which one they mean. - Give it both and the order number wins, because it’s unambiguous.
Both keys exist because a support ticket carries an order number only when the customer bothered to paste one, which on most forms is optional. E-mail is the fallback that fires most often.
You get back the status, whether it’s paid, when it was placed and completed,
the total and currency, the destination country, and line_items — what
they actually bought, each with a name, SKU and quantity.
Two more outputs tell a live order from history, which matters because the “most recent” order for an e-mail can be years old:
age_days— whole days since it was placed (-1when there’s no order).is_open— true while the status is one the shop still works on:processingoron-hold. If your shop adds statuses of its own (say, an order waiting for a spare part), list them in Open statuses so an old order that is still being worked on isn’t treated as history.
A rule like “only mention an order older than 45 days when it is still open” is then a condition on those two, not a code step.
Branch on found. A customer quoting an order number that doesn’t exist, or
writing in from a different address than they ordered with, is completely
normal — and it needs a question, not an invented answer.
Check WooCommerce stock
Section titled “Check WooCommerce stock”Looks one product up by SKU and says whether it can actually be bought right now. It returns the name, the price, how many are left, and the link to the product page — which is what an “order it here” line should point at.
The important part is that it keeps three different negatives apart:
foundis false — the shop has no such SKU. The part number is wrong, or it isn’t something you sell.foundis true butin_stockis false — the right part exists, and there are none left today.availabilityisdiscontinued— the right part exists and you have stopped selling it. It is not coming back.
Those are three different replies. “Wrong part number” sends them to check their invoice; “none left” invites them to wait or be told when it lands; “we no longer make it” should offer the nearest thing you do sell. Answering the third with the second is how a customer ends up waiting for a restock that will never happen.
availability is only meaningful once you have answered Step
1b; before that it is
unknown and says nothing.
Gate any “you can order this” line on this step rather than on what the drafting model believes.
List WooCommerce orders
Section titled “List WooCommerce orders”When the question is about a group rather than one order. Filters combine:
status— pending, processing, on-hold, completed, cancelled, refunded, failed.after/before— when orders were placed.modified_after/modified_before— when they were last changed.search— matches customer name or e-mail.product_id— everyone who bought a particular thing, e.g. when a batch turns out faulty.
List WooCommerce products
Section titled “List WooCommerce products”The catalogue search — for when a customer describes a part instead of naming
its code. Filters on free text, an exact sku, a category, and stock state
(instock, outofstock, onbackorder). Each result carries the categories the
product sits in, and its availability — so a list of suggestions can drop the
ones you no longer sell before a customer ever sees them.
Each result also carries an excerpt of the product’s own description,
cleaned of the shop’s page-builder markup (default 600 characters, tunable per
step). Anything clipped ends with a note saying so and sets
description_truncated.
Reach for Check WooCommerce stock instead when you already have the SKU: it’s the direct answer, it distinguishes an unknown code from an empty shelf, and — being a single-product lookup — it carries the whole description rather than an excerpt.
List WooCommerce categories
Section titled “List WooCommerce categories”Your shop’s own category vocabulary — id, name, slug, parent, and how many products sit in each. Two jobs:
- It is the only place the numeric category id appears. Nothing in the
product API shows it, so without this the category filter is usable only by
someone who has opened the shop admin. (
categoryon List WooCommerce products also accepts a name or slug and resolves it for you.) - It answers “what do you carry for X?” — a question a product-name search cannot.
Tracking: only if your shop publishes it
Section titled “Tracking: only if your shop publishes it”Find WooCommerce order and List WooCommerce orders both return a
carrier and a tracking_number — but only when your shop puts them on the
order. Whether yours does is the whole question, and it is worth understanding
why, because “where is my parcel?” is one of the most common things a shop gets
asked.
WooCommerce itself has no concept of tracking. It arrives on an order as extra
data written by whichever shipment-tracking plugin you run, and every plugin
stores it differently — which is why Routario can’t read it out of a standard
shop. What it can read is two plain fields, carrier and tracking_number, if
your shop is set up to expose them. Some shops publish them directly; others
have a developer add a few lines that copy the plugin’s data onto the order.
Ask whoever looks after your WordPress whether those two fields are on your
orders API.
When they’re filled, answer from them: carrier reads like dpd or
fedex, and tracking_number is the number the carrier knows. An order that
shipped as several parcels can carry several numbers separated by commas — pass
the whole value through rather than taking the first.
When they’re empty, they’re empty for one of two reasons and neither means “delivered”: the parcel has no label yet, or your shop doesn’t publish these fields at all. Either way you don’t know, so route the question to a person.
When was the label made? On the day a label appears, the parcel is usually
still with you — the courier hasn’t collected it, and the address can often
still be changed. tracking_added_today is true on that day, and
tracking_added_at gives the time:
- If your tracking plugin records when it shipped (
date_shippedon its tracking items), that time is used (tracking_added_source: shop). - If it doesn’t, Routario uses the first time it saw the tracking number
(
tracking_added_source: observed) — but only when it knows the number wasn’t there before: it looked the order up earlier without one, or the order was placed since the previous working day. An old order that was already labelled the first time anyone asked about it gets an emptytracking_added_at, never a guess.
Answer “why isn’t my discount code working?”
Section titled “Answer “why isn’t my discount code working?””A customer types a code, it doesn’t apply, and they write in. The answer is almost always in the shop, and it’s almost never “our website is broken”.
Check WooCommerce coupon
Section titled “Check WooCommerce coupon”Give it a code and it tells you whether that code works right now. It comes back with the type and amount of the discount, when it expires, how many times it’s been used and any usage limit, the minimum order it needs, and whether it includes free shipping.
The useful part is the three plain answers it works out for you, so a reply doesn’t have to reason about it:
expired— the expiry date has passed.exhausted— the code has a usage limit and has hit it. A one-time code is just a limit of one.email_restricted— the code only works for particular e-mail addresses. The shop deliberately does not say which, so nobody can check this from a reply. Hand it to a colleague.
usable folds all three together and is the field to branch on. It answers
“is this code live right now” — not “will it work on this customer’s basket”.
The minimum order, product scope and free-shipping flag come back alongside
precisely because those are yours to weigh.
List WooCommerce coupons
Section titled “List WooCommerce coupons”Every coupon in the shop, newest first — for a report, a morning check of what expired overnight, or a table you keep current. Unlike the order and product lists, this one does page through until it has them all, because the question it serves is a sweep: a half-read list would quietly imply that the codes it didn’t reach no longer exist.
Each coupon in coupons has the same shape Check WooCommerce coupon
returns, including expired, exhausted, email_restricted and usable.
A worked example: the order question
Section titled “A worked example: the order question”A support flow handling “where’s my order?” reads:
- Find WooCommerce order with the order number from the ticket, falling back to the requester’s e-mail.
- On the missing path, draft a reply asking for the order number from their confirmation e-mail — don’t guess.
- On the found path, Ask AI drafts the
answer, given the status, the payment state and
line_items. - Post the draft back for a human to approve.
Because step 3 is handed real values, the draft says “your order of 2× Windshield Kit, placed on 4 August, was paid and completed on the 6th” rather than something that merely reads like an answer.
Testing it on your own shop
Section titled “Testing it on your own shop”Every step above can be exercised by hand before you wire it into anything. The
repository ships ops/woocommerce-smoke-flows.py, which creates four tiny
flows — one per step — each shaped ask a question → run the step → show the
result. Run one, type a known order number or SKU, and read the pop-up.
They’re worth keeping and re-running after an upgrade: the pop-ups name every output explicitly, so anything that stops working shows up as a blank rather than passing quietly.
Where to go next
Section titled “Where to go next”- Answer Zendesk tickets with a drafted reply — the support desk these lookups feed.
- Branch on an AI decision — routing a question to the right lookup in the first place.
- Template variables — how to reference a step’s output,
like
{{ find_order.line_items }}, further down the flow.