About shoplazza-orders
shoplazza-orders is a Shoplazza CLI skill for handling orders and related records, including fulfillment, refunds, and payment activity. It maps common requests to commands and emphasizes confirmation and dry runs for sensitive writes.
Key features
- 01Search and count orders
- 02Ship orders and update tracking
- 03Refund or update orders
- 04Handle fulfillment and refund records
- 05Manage risks and payment transactions
- 06Safety checks for sensitive writes
Use cases
- 01Finding orders by customer or status
- 02Shipping an order with tracking details
- 03Preparing and confirming a refund
- 04Updating order tracking information
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ shoplazza/ shoplazza-cli --skill shoplazza-ordersAfter installing, type/shoplazza-ordersin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/fulfillments.mdorders-create.mdpost-sales.mdrefunds.mdrisks.mdshipping-schemas.mdtracking-carriers.mdtransactions.mdDetails
From the project READMEshoplazza CLI — orders module
CRITICAL — before anything else, use Read on ../shoplazza-common/SKILL.md.
It owns every cross-cutting mechanic: the three access tiers, the output envelope (.data),
--dry-run, --jq (incl. "don't pass -r"), --fields, schema, api rest, auth / profiles,
and the safety protocol. This file covers only the orders domain and never repeats them.
Overview
The orders module manages the order lifecycle (search, count, get, create, update, cancel,
pay, delete) and its sub-resources: fulfillments (shipping records), refunds, fraud risks,
payment transactions, after-sales (post-sales) records, shipping zones/rates, and tracking
carriers. All three access tiers apply (tier-selection rule is in shoplazza-common — prefer
+shortcut).
Shortcuts exist for +search / +count / +ship / +refund / +update-tracking only —
every other operation (get, cancel, create, pay, and all sub-resources) is a spec leaf.
Orders is a large domain: this file is the router plus the high-frequency operations;
per-sub-resource depth lives in references/.
Command map
Intent → command, highest-fit tier first. The authoritative flags/params live in
shoplazza orders <cmd> --help and shoplazza schema orders.<cmd>, not this table.
| User intent | Command |
|---|---|
| Search / filter orders | orders +search [--email <addr>] [--keyword <no/name/email>] [--status …] [--financial-status …] [--fulfillment-status …] [--customer-id <id>] [--since <t>] [--until <t>] |
| Count orders | orders +count — same filters as +search, minus --page-limit |
| Ship an order (发货) | orders +ship --order-id <id> --tracking <no> [--company <name>] [--company-code <code>] [--line-items id:qty,…] [--notify] |
Refund a buyer (退款; money → --dry-run first) | orders +refund --order-id <id> --amount <n> [--note <txt>] [--return-items] [--payment-line-id <id>] |
| Fix / update tracking info | orders +update-tracking --order-id <id> --fulfillment-id <id> --tracking <no> [--company <name>] [--tracking-url <url>] [--notify] |
| Get one order by internal ID | orders get --params '{"order_id":"<id>"}' |
| Get order by order NUMBER (#…) | orders get-by-number --params '{"number":"<number>"}' |
List with filters +search lacks (multi-status arrays, ids, skus, tags, fuzzy search…) | orders list --params '{…}' (see schema orders.list) |
| Create an order on a customer's behalf (手工建单 / 代客下单) | orders create --data '{"order":{…}}' — heavy nested body → references/orders-create.md |
| Update order note / tags / shipping address | orders update --params '{"order_id":"<id>"}' --data '{"order":{…}}' |
Cancel an order (destructive → --dry-run first) | orders cancel --params '{"order_id":"<id>"}' [--data '{"reason":"…"}'] |
| Mark an order paid | orders pay --params '{"order_id":"<id>"}' --data '{"payment_line":{"payment_channel":"<channel>","payment_method":"<method>","transaction_no":"<txn>"}}' — empty body = bogus TEST payment; real channel/method/txn go in payment_line, custom display name in gateway (schema orders.pay) |
Delete an order (destructive → --dry-run first) | orders delete --params '{"order_id":"<id>"}' |
| Fulfillment records CRUD / cancel / complete | orders fulfillments … → references/fulfillments.md |
| Refund records (one order / store-wide / finish) | orders refunds … → references/refunds.md |
| Fraud risk records (标记高风险) | orders risks … → references/risks.md |
| Payment transactions on an order (支付流水) | orders transactions list --params '{"order_id":"<id>"}' → references/transactions.md |
| After-sales records (售后) | orders post-sales … → references/post-sales.md |
| Shipping zones / rates / available lines (运费区域) | orders shipping-schemas … → references/shipping-schemas.md |
| Which carrier is this tracking number? (承运商识别) | orders tracking-carriers detect --params '{"tracking_number":"<no>"}' → references/tracking-carriers.md |
Acting on a request
"发货 / 退款 / 取消订单 / ship / refund / cancel" is an action, not a question:
- Match intent to a shortcut via the trigger table below (sub-resource leaves are in
references/). - Check required fields (each shortcut's no-default flags). Missing or ambiguous →
ask with
AskUserQuestion, never fabricate — especially--amount(money) and--tracking(a real-world tracking number you cannot invent). Bundle missing fields into ONE question batch. - Never ask about a flag that has a CLI default or is omit-to-disable. Let the default win.
- All required present → execute, with safety per shoplazza-common:
+refundmoves money — ALWAYS--dry-runfirst, restate in plain language (which order, how much, note, inventory returned or not), wait for the user's go-ahead, then run for real.- Destructive leaves (
orders cancel/orders delete/fulfillments cancel/risks delete/post-sales delete/shipping-schemas delete-zone) —--dry-runfirst + restate, wait for the user's go-ahead, then run. orders paywrites a payment record — same treatment as+refund:--dry-runfirst, restate (which order, channel, transaction no), wait for the user's go-ahead. Never send it with an empty body — no body silently records a bogus TEST payment.payment_line'spayment_channel/payment_method/transaction_noare free strings, not enums — fill them from the user's wording (e.g. "走的 PayPal" →"payment_channel":"paypal","payment_method":"paypal"),transaction_noverbatim; do not block asking which enum value to use.+ship/+update-tracking/+search/+countare safe to run directly once required values are confirmed.
Trigger phrase → shortcut
| User says | Shortcut | How to extract values |
|---|---|---|
| 查订单 / 找订单 / 今天有没有新订单 / search or list orders | +search | a known email → --email; a partial name / order-no fragment / anything else → --keyword; "今天/最近 N 天" → --since only (leave --until open); status words → the enum table below |
| 还没发货的订单 / unshipped orders | +search --fulfillment-status waiting | 未发货 = waiting — there is no unfulfilled value |
| 某客户 / 某邮箱的订单 / orders from customer X | +search | customer id → --customer-id; a full email address → --email (exact match, the precise path); never stuff an id or an address into --keyword when a dedicated flag exists |
| 有多少订单 / 订单总数 / how many orders | +count | "总共" = no filters, do not ask for a time range; count from .data.count |
| 发货 / 标记发货 / ship order X | +ship | tracking no → --tracking verbatim; carrier name → --company; "通知买家" → --notify; whole order = omit --line-items |
| 部分发货 / ship only some items | +ship --line-items id:qty,… | per-line quantities as line-id:qty pairs |
| 退款 / 给买家退 X 元 / refund the buyer | +refund | amount → --amount verbatim; stated reason → --note; "库存退回去/restock" → --return-items |
| 改运单号 / 运单号填错了 / fix the tracking number | +update-tracking | needs all three: --order-id, --fulfillment-id, --tracking |
| 订单号 #… 的详情 / look up order by number | get-by-number (leaf) | strip the leading # → --params '{"number":"…"}'; internal IDs go to get instead |
| 手工建单 / 代客下单 / create an order for a customer | create (leaf) | heavy nested body under order → references/orders-create.md; resolve variant_id via products +search; never fabricate buyer identity, address, or price |
| 取消订单 / cancel order X | cancel (leaf) | id → --params; a stated reason → --data '{"reason":"…"}' (optional); not fulfillments cancel |
| 取消发货记录 / cancel a fulfillment | fulfillments cancel (leaf) | both order_id and fulfillment_id in --params; not orders cancel |
| 标记高风险 / 像欺诈单 / flag as fraud | risks create (leaf) | 高/中/低 → level high/medium/low; stated reason → details array → references/risks.md |
| 订单支付流水 / payment transactions | transactions list (leaf) | order id → --params; this is buyer payments, not billing |
| 运单号 X 是哪家承运商 / which carrier | tracking-carriers detect (leaf) | --params '{"tracking_number":"…"}' — don't list + match by hand |
| 设置运费区域 / 邮费 / shipping zones & rates | shipping-schemas leaves | → references/shipping-schemas.md |
If multiple rows match, ask which one. Don't guess.
Required-vs-ask matrix
Only no-default flags are askable.
| Shortcut | Must ASK if user did not specify | Infer if possible | Default silently |
|---|---|---|---|
+refund | --amount (money — never fabricate; you may offer to look up the order total via orders get for a full refund, but still confirm the number); --order-id if absent | --note from the stated reason; --return-items from 库存退回/restock wording | --payment-line-id (only needed when the order has multiple payment lines — the CLI errors with candidates; pick or ask then) |
+ship | --tracking (never invent a tracking number); --order-id if absent | --company from a named carrier (keep the user's naming); --notify from 通知买家 wording | --line-items (omit = all fulfillable items), --company-code |
+update-tracking | whichever of --order-id / --fulfillment-id / --tracking is missing | --company, --tracking-url only if the user gave them | --notify (set only on explicit re-notify wording) |
+search / +count | (nothing — all filters optional; never ask) | filters from wording via the enum table | --page-limit; time bounds only from the user's own time words |
cancel (leaf) | order id if absent | reason body only if the user stated one | reason (optional — omit if not given) |
create (leaf) | any missing required buyer/address sub-field (last_name, email, country_code, province_code, city, address, zip) and the line item(s) — never fabricate identity, address, or price; ask or look up variant_id via products +search | currency_code from the store (shop info get --jq '.data.currency'); a neutral shipping_name label ("Standard Shipping"); an omitted catalog price (the variant prices it) | notify flags, tags, note, discount_application, payment_line (record payment via orders pay) |
Never-ask list
Flags with a CLI default or omit-to-disable — they never appear in a question:
--notify (omit unless the user asks to notify) · --line-items (default: all fulfillable) ·
--company / --company-code (optional carrier info) · --payment-line-id (only after a
multi-payment-line error) · --note (only if a reason was given) · --return-items (explicit
wording only) · --tracking-url · --page-limit · --since / --until (only from the
user's own time words — never invent a time range).
Decision examples
| User says | Verdict |
|---|---|
| "订单 111222 退 15.50 给买家,备注 wrong size,库存退回" | REFUND — +refund --order-id 111222 --amount 15.50 --note "wrong size" --return-items; --dry-run first, restate, wait for go-ahead, then run |
| "给订单 333444 退个款" | ASK — the amount (money; never invent). Do NOT ask which order — it's in the utterance. May offer a full-refund lookup, still confirm |
| "订单 555 可以发货了,运单号 YT123,中通,通知买家" | SHIP — +ship --order-id 555 --tracking YT123 --company 中通 --notify; safe to run directly |
| "把订单 666 标记发货" | ASK — the tracking number (required, never fabricate); carrier is optional, offer alongside but don't block on it |
| "找最近 7 天还没发货的订单" | SEARCH — +search --fulfillment-status waiting --since <today-7d>; no --until |
| "取消订单 777,原因是买家申请" | CANCEL — orders cancel --params '{"order_id":"777"}' --data '{"reason":"买家申请"}'; --dry-run first + restate |
| "订单 888 像欺诈单,标成高风险" | RISK — orders risks create --params '{"order_id":"888"}' --data '{"risk":{"level":"high","details":["…"]}}'; restate before writing |
| "手工帮客户下个单:1 件 variant V123,单价 29.9,寄给 John Doe ([email protected]),美国加州洛杉矶 123 Main St 90012" | CREATE — build the nested order body (line_items variant_id+quantity+price, full shipping_address incl. province_code, shipping_line, tax_total, currency_code), restate + --dry-run first → references/orders-create.md |
| "帮客户下个单" (no items / buyer given) | ASK — which variant(s) & quantity, and the buyer's shipping details (name, email, address); never fabricate them. shipping_price/tax_total are money — use stated amounts, or "0.00" only when the user implies no charge and restate that |
Status enums (memorize these three)
From schema orders.list — used by +search / +count / list:
| Field | Values |
|---|---|
--status (order) | opened (pending payment) · placed (in progress) · finished · cancelled |
--financial-status | waiting · paying · authorized · partially_paid · paid · cancelled · failed · refunding · refund_failed · refunded · partially_refunded |
--fulfillment-status | initialled · waiting (未发货 / waiting to ship) · partially_shipped · shipped · partially_finished · finished · cancelled · returning · partially_returned · returned |
unfulfilled / fulfilled are NOT valid values — "还没发货" maps to waiting.
Each shortcut flag takes ONE value; to filter on several at once use the list leaf, whose
status / financial_status / fulfillment_status params are JSON arrays.
Time window — which field. +search --since/--until bound the placed time
(placed_at_min/placed_at_max), ISO date or unix ts — that is the sales clock and the right
default. To filter on a different moment, drop to the list leaf, which exposes one
_min/_max pair per time field; pick it from the user's verb:
| User's words | Param |
|---|---|
| 下单 / 支付 / 成交 / 售出 / 卖 / 卖了多少 / 销量 / 销售额 / placed / paid / sold | placed_at_min / placed_at_max |
| 创建 / 新增 / created | created_at_min / created_at_max |
| 更新 / 修改 / 最后交互 / updated / last changed | updated_at_min / updated_at_max |
| 完成 / 订单完成 / finished | finished_at_min / finished_at_max |
| 发货完成 / 履约完成 / fulfilled | fulfilled_at_min / fulfilled_at_max |
created_at ≠ placed_at (easy to get wrong). A Shoplazza order row is created the moment a
buyer enters checkout — before payment — so created_at counts abandoned / unpaid carts too.
placed_at is when the order was actually placed (paid). For anything measuring real sales
(销量 / 卖了多少 / 成交量 / 销售额 / how much sold), filter on placed_at_*, never created_at_*,
or you fold abandoned carts into the number. Use created_at_* only when the user literally asks
how many orders were created / 新增. With no time verb at all: if a financial_status or
fulfillment_status filter is present the intent is sales → placed_at_*; otherwise created_at_*.
Restate the resolved window. When you turn a relative phrase (最近 7 天 / 这个月) into
--since / --until, tell the user the concrete window you used (e.g. 2026-09-10 to
2026-09-17) — a wrong boundary or timezone then shows up instead of silently skewing the count.
Searching orders precisely
orders list exposes three ways to match on the same field. Pick the narrowest one that
expresses the request — shoplazza-common's precision ladder, in this domain's terms:
| Tier | Params | Use when |
|---|---|---|
| Exact-match arrays | customer_emails, shipping_emails, shipping_phones, order_tags, skus, spus, product_ids, browser_ips, ids | You have the whole value. +search --email is the shortcut for customer_emails. |
| Keyword | keyword (+ optional keyword_scope_fields to narrow which fields it searches) | A fragment, or the user did not say which field it is. +search --keyword maps here. |
| Fuzzy trio | fuzzy_fields + fuzzy_keywords + fuzzy_relation | Prefix/fragment matching on specific named fields, or several fields AND/OR-ed together. Leaf only. |
keyword_scope_fields and fuzzy_fields share one vocabulary — the field-name list in
schema orders.list --view request under fuzzy_fields (name, number, id,
shipping_email, tracking_number, discount_code, …). Read it there rather than guessing.
Boundaries
Reads like orders, actually belongs elsewhere (and lookalikes this domain owns):
| Sounds like | Actually belongs to | Command |
|---|---|---|
| 退款 / 给顾客退钱 / refund a buyer | HERE (not discounts — 折扣/优惠码 price the cart; not billing — app charges) | orders +refund |
| 订单支付流水 / buyer payment transactions | HERE | orders transactions list |
| 应用收费流水 / app-charge transactions billed to the merchant | shoplazza-billing | billing transactions |
| 快递承运商查询 / 运单号识别 / tracking carrier lookup | HERE | orders tracking-carriers {detect,list} |
| 注册实时运费报价承运商 / real-time rate quote carriers | shoplazza-shop | shop carrier-services |
| 运费区域 / 邮费方案 / shipping zones & rates | HERE | orders shipping-schemas … |
| 按邮箱查某客户的订单 / a customer's orders | HERE (+search --email <addr> or --customer-id) | resolving the id via customers +search first is fine — the final query is an orders query |
| 客户资料本身 / the customer record | shoplazza-customers | customers +search / customers get |
| 库存 / 补货 / product stock | shoplazza-products | products +stock / products inventory |
| 退款时库存退回 / restock on refund | HERE | orders +refund --return-items |
Permissions · Scope
Authorization is by domain (the unit of --domain), not per command. Authorization flow is
in shoplazza-common → Authentication.
| Operation | Needs | Grant |
|---|---|---|
read (get / get-by-number / list / +search / +count / sub-resource reads) | orders read scope | auth login --domain orders |
write (+ship / +refund / +update-tracking / create / update / cancel / pay / delete / sub-resource writes) | orders write scope | auth login --domain orders |
Look up exact scope literals with shoplazza auth scopes; --domain orders expands into them.
Gotchas
Domain-specific pitfalls only (generic ones — .data prefix, --jq without -r — are in
shoplazza-common).
| Symptom | Cause | Fix |
|---|---|---|
Filtered on unfulfilled / fulfilled | Not in the enum | 未发货 = waiting; see the enum table above |
orders get finds nothing for a #… number | get takes the internal order_id; order numbers are a different key | get-by-number --params '{"number":"…"}' (strip the #) |
+refund errors "order has N payment_lines" | Multi-payment-line order needs an explicit choice | Re-run with --payment-line-id from the listed candidates |
+refund / +ship dry-run prints TWO requests | These shortcuts GET the order first (resolve payment lines / fulfillable items), then POST | Expected. The dry-run POST body omits looked-up data (e.g. refund_line_items, empty payment_line_id) — the live run fills them in |
| Cancelled the order when only a shipment should die (or vice versa) | 取消订单 ≠ 取消发货记录 | Order → orders cancel; fulfillment → orders fulfillments cancel (both path ids) |
Hand-built refunds create body for a simple refund | The leaf needs the full body incl. refund_payments | Prefer +refund; leaf only for split/itemized refunds → references/refunds.md |
Store-wide refunds list for one order's records | Two different endpoints | One order → refunds list-by-order --params '{"order_id":"…"}' |
--status with a comma list on +search | Shortcut flags are single-valued | Multi-status → orders list --params '{"status":["opened","placed"]}' |
| A search "for one buyer" returns the whole store | The filter was dropped, or the page just looks small | Cross-check with orders +count filtered vs unfiltered before answering — see shoplazza-common → "Reading a filtered list" |
keyword_scope_fields=["email"] or ["order_no"] returns 0 hits | Those are the schema description's example strings, not the accepted vocabulary | Use the fuzzy_fields field names (shipping_email, number, name, …) — see "Searching orders precisely" |
unknown flag: --fields | No orders command has --fields | Project with --jq |
orders create rejected for missing fields | Whole body nests under an order wrapper; line_items[].quantity, shipping_address (last_name, email, country_code, province, province_code, city, address, zip), shipping_line (shipping_name, shipping_price), tax_total, currency_code are ALL required | Build the full nested body → references/orders-create.md (verified against schema orders.create --view request) |
orders create order fails despite country/province set | country_code / province_code (ISO: US, CA) are the required keys — the display-name country / province are optional | Send both codes; see references/orders-create.md |
Copied the orders pay payment_line object into orders create | In orders create the schema types payment_line as a string (registry flattening), unlike orders pay where it is an object | Omit payment_line on create; record payment afterward with orders pay |
orders pay with no body "succeeded" unexpectedly | Empty body = bogus test payment | Pass payment_line (payment_channel, payment_method, transaction_no) for a real channel, or gateway for a custom method |
| Schema summaries say "shopping zone" | Registry typo — they mean shipping zone | Ignore; commands are shipping-schemas {create,update,delete}-zone |
Recipes
# 1. Orders placed in the last 7 days that are not yet shipped
orders +search --fulfillment-status waiting --since <today-7d, e.g. 2026-07-16>
# 2. Paid orders for one customer
orders +search --customer-id 100200 --financial-status paid
# 3. All orders from a buyer email — exact, complete, and checked against the store total
orders +search --email [email protected] --page-limit 250
orders +count --email [email protected] --jq '.data.count' # must be < the unfiltered count
orders +count --jq '.data.count'
# 4. Total order count, no filters
orders +count --jq '.data.count'
# 5. Order detail by order number
orders get-by-number --params '{"number":"2026071500123"}' --jq '.data.order'
# 6. Ship the whole order and notify the buyer
orders +ship --order-id 4300123 --tracking SF0011223344 --company "顺丰" --notify
# 7. Fix a mistyped tracking number (no re-notify)
orders +update-tracking --order-id 991100 --fulfillment-id 77001 --tracking YT5544332211
# 8. Partial refund + return inventory — dry-run, restate, wait for go-ahead, then run
orders +refund --order-id 887799 --amount 19.90 --note "wrong size" --return-items --dry-run
orders +refund --order-id 887799 --amount 19.90 --note "wrong size" --return-items
# 9. Cancel an order with a reason — dry-run first
orders cancel --params '{"order_id":"660011"}' --data '{"reason":"买家重复下单"}' --dry-run
orders cancel --params '{"order_id":"660011"}' --data '{"reason":"买家重复下单"}'
# 10. Flag an order as high fraud risk with a reason
orders risks create --params '{"order_id":"445500"}' \
--data '{"risk":{"level":"high","details":["收货地址与 IP 所在国家不一致"]}}'
# 11. Which carrier owns this tracking number?
orders tracking-carriers detect --params '{"tracking_number":"9400111899223344556677"}'
# 12. Payment transactions on an order
orders transactions list --params '{"order_id":"778899"}'
# 13. One order's refund records
orders refunds list-by-order --params '{"order_id":"220033"}' --jq '.data.records'
References
- references/orders-create.md — manual/draft order creation: full nested body (required vs optional), required-vs-ask, minimal + fuller examples
- references/fulfillments.md — fulfillment records: leaf CRUD, cancel/complete, body shapes
- references/refunds.md — refund record body (split/itemized refunds), store-wide vs per-order lists,
finishfor custom-channel refunds - references/risks.md — fraud risk records: level enum, details, CRUD
- references/transactions.md — buyer payment transactions, status enum
- references/post-sales.md — after-sales records: list filters, delete
- references/shipping-schemas.md — general schema, zones, available shipping lines (GB special case)
- references/tracking-carriers.md — carrier detect / list
- Per-command flags:
shoplazza orders <cmd> --help - Spec-leaf params / body / response:
shoplazza schema orders.<cmd>(nested:schema orders.fulfillments.create) - Cross-cutting mechanics (auth / tiers / output envelope /
--dry-run/--jq/ safety):../shoplazza-common/SKILL.md - Shortcut source of truth:
shortcuts/orders/*.go