@agenzo/merchant-cli 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm](https://img.shields.io/npm/v/@agenzo/merchant-cli.svg)](https://www.npmjs.com/package/@agenzo/merchant-cli) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](../../LICENSE) ![node](https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg)
4
4
 
5
5
  > **Merchant-fulfillment CLI** for the Agenzo platform — binary `agenzo-merchant-cli`.
6
- > Agents fulfill commerce services here. Each capability is a noun and the set grows over time — use `services` to discover what's available; today's capability is ride-hailing (`ride-elife`).
6
+ > Agents fulfill commerce services here. Each capability is a noun and the set grows over time — use `services` to discover what's available; today's capabilities are ride-hailing (`ride-elife`) and hotel booking (`hotel-redaug`).
7
7
 
8
8
  **[Overview](#overview)** · **[Features](#features)** · **[Quick Start](#quick-start)** · **[Global flags](#global-flags)** · **[Errors](#output-and-error-contract)** · **[Idempotency-Key](#idempotency-key)**
9
9
 
@@ -14,7 +14,8 @@
14
14
  `agenzo-merchant-cli` is the command-line entry point for Agents to fulfill commerce services on the Agenzo platform. Each fulfillment capability is exposed as a **noun**, and the set grows over time:
15
15
 
16
16
  - **`services`** (capability discovery): list what's currently available and how to call it — run this first to learn the current capability set.
17
- - **`ride-elife`** (ride-hailing): the capability available today — the full loop of quote → book → query/poll → cancel → list-orders.
17
+ - **`ride-elife`** (ride-hailing): the full loop of quote → book → query/poll → cancel → list-orders.
18
+ - **`hotel-redaug`** (hotel booking): search, find-destination, hotel-filters, list-cities, hotel-detail, quote, create-order (locks the room AND settles payment inline), get (status/poll), cancel, checkout, get-checkout, list-orders. Supports both **monthly_settlement** (settlement-account deduction) and **pay_per_call** (the platform's own server-side EVO integration; optionally target a specific bound card via `--payment-method-id`) — the funds path is decided server-side by `billing_mode`, the CLI call is identical either way.
18
19
 
19
20
  More fulfillment capabilities are added as new nouns over time; `services list` always reflects the current set.
20
21
 
@@ -23,14 +24,28 @@ More fulfillment capabilities are added as new nouns over time; `services list`
23
24
  | Noun | Verb | Type | HTTP | Description |
24
25
  |---|---|---|---|---|
25
26
  | `services` | `list` | Read | — (local) | List available merchant-fulfillment capabilities |
26
- | `services` | `get <service-id>` | Read | — (local) | View the full metadata of a single capability (miss → `SERVICE_NOT_FOUND`) |
27
+ | `services` | `get <service-id>` | Read | — (local) | Service-layer view: `selection_hints` / `schema_ref` / `conventions` / `workflow` / `verbs_summary` (miss → `SERVICE_NOT_FOUND`); full per-verb flags/response schema is fetched separately via `schema_ref` |
27
28
  | `ride-elife` | `quote` | Read | `POST /ride/quote` | Point-to-point quote (`vehicle_classes[]` + meet-and-greet) |
28
29
  | `ride-elife` | `book` | Write/Y | `POST /ride/book` | Book against a quote (monthly_settlement-aware, see below) |
29
30
  | `ride-elife` | `get` | Read | `GET /ride/<id>/status` | Query order status; `--watch` emits an NDJSON polling stream |
30
31
  | `ride-elife` | `cancel` | Write/Y | `POST /ride/<id>/cancel` | Cancel an order (no body, may incur a fee) |
31
32
  | `ride-elife` | `list-orders` | Read | `GET /ride/orders` | List booked trips (pagination + filtering) |
32
-
33
- > Write commands (`book` / `cancel`) are subject to the idempotency-key rules (see [Idempotency-Key](#idempotency-key)).
33
+ | `hotel-redaug` | `search` | Read | `POST /hotel/search` | Search hotels by coordinates or destination-id + stay dates + filters |
34
+ | `hotel-redaug` | `find-destination` | Read | `POST /hotel/find-destination` | Resolve free-text to destinations (destination_id + coordinates) |
35
+ | `hotel-redaug` | `hotel-filters` | Read | `POST /hotel/filters` | Get available filter options for a location (codes → search flags) |
36
+ | `hotel-redaug` | `list-cities` | Read | `POST /hotel/cities` | List cities for a country (destination_id + coordinates) |
37
+ | `hotel-redaug` | `hotel-detail` | Read | `POST /hotel/detail` | Hotel detail with facilities/images AND `rooms[]` (area/floor/beds/photos) — call before quote |
38
+ | `hotel-redaug` | `quote` | Read | `POST /hotel/quote` | Real-time rooms/rates for one hotel (`product_token` + `price_items`) |
39
+ | `hotel-redaug` | `create-order` | Write/Y | `POST /hotel/create-order` | Create AND pay for a hotel order (locks the rate + settles payment inline; billing path chosen server-side by `billing_mode`); returns `order_id`, already `PAID` |
40
+ | `hotel-redaug` | `pay-order` | Write/Y | `POST /hotel/{order_id}/pay` | Trigger supplier confirmation (upstream payOrder) for a paid order; takes only `--order-id` — no payment params needed |
41
+ | `hotel-redaug` | `get` | Read | `GET /hotel/<id>/status` | Query order status; `--watch` emits an NDJSON polling stream |
42
+ | `hotel-redaug` | `cancel` | Write/Y | `POST /hotel/<id>/cancel` | Cancel a whole order (acceptance ≠ proof; poll `get`) |
43
+ | `hotel-redaug` | `checkout` | Write/Y | `POST /hotel/<id>/checkout` | Partial check-out / out-of-policy cancellation (async) |
44
+ | `hotel-redaug` | `get-checkout` | Read | `GET /hotel/checkout/<task_order_code>` | Poll a check-out application; `--watch` emits an NDJSON stream |
45
+ | `hotel-redaug` | `list-orders` | Read | `GET /hotel/orders` | List hotel orders (pagination + status filter) |
46
+
47
+ > Write commands (`ride-elife book` / `cancel`; `hotel-redaug create-order` / `pay-order` / `cancel` / `checkout`) are subject to the idempotency-key rules (see [Idempotency-Key](#idempotency-key)).
48
+ > Read status verbs `get` / `get-checkout` support `--watch` for NDJSON status polling.
34
49
  > `ride-elife track` is not available — use `get --watch` for order-status polling.
35
50
 
36
51
  ## Quick Start
@@ -56,12 +71,13 @@ A runtime-plane CLI that uses an **API Key** (`--api-key`, carried per command a
56
71
  - When `--api-key` is omitted, it is requested interactively (password input).
57
72
  - No Bearer Token or local keystore — every command carries the API Key.
58
73
 
59
- ### End-to-end example
74
+ ### Ride-hailing end-to-end example
60
75
 
61
76
  ```bash
62
77
  # 1. Discover capabilities
63
78
  agenzo-merchant-cli services list
64
- agenzo-merchant-cli services get ride-elife
79
+ agenzo-merchant-cli services get ride-elife # service-layer view: workflow + conventions + verbs_summary
80
+ agenzo-merchant-cli ride-elife book --help --format json # capability layer: this verb's full flags/response schema
65
81
 
66
82
  # 2. Quote (produces quote_id)
67
83
  agenzo-merchant-cli ride-elife quote --api-key "$API_KEY" \
@@ -86,6 +102,88 @@ agenzo-merchant-cli ride-elife cancel --api-key "$API_KEY" --yes \
86
102
  --order-id "$RIDE_ID" --idempotency-key "cancel-$(date +%s)"
87
103
  ```
88
104
 
105
+ ### Hotel booking end-to-end example
106
+
107
+ The core Agent loop is `search → quote → create-order → get`. `create-order` is a single write step
108
+ that BOTH locks the room AND settles payment inline — there is no separate settlement call. Amounts
109
+ are decimal currency units (e.g. `320.00` = 320.00 yuan). The billing path is chosen server-side by
110
+ the developer's `billing_mode`, but the CLI call is identical either way:
111
+ - **monthly_settlement**: `total_amount` is deducted from the developer's settlement-account balance inline.
112
+ - **pay_per_call**: `total_amount` is authorized + captured on the developer's bound card via the platform's own server-side EVO integration — no EVO parameters are ever passed through this CLI. Optionally pass `--payment-method-id` to charge a specific bound card instead of the auto-selected one.
113
+
114
+ ```bash
115
+ # 1. Search hotels by coordinates + stay dates (or use --destination-id from find-destination).
116
+ # Pick a hotels[].hotel_id from the result for the quote step.
117
+ agenzo-merchant-cli hotel-redaug search --api-key "$API_KEY" \
118
+ --lat 31.2304 --lng 121.4737 --distance 20 \
119
+ --check-in 2026-02-10 --check-out 2026-02-12 \
120
+ --adults 2 --children 0 --room-num 1
121
+
122
+ # 2. Quote one hotel (produces rates[].product_token, total_price, price_items)
123
+ agenzo-merchant-cli hotel-redaug quote --api-key "$API_KEY" \
124
+ --hotel-id "$HOTEL_ID" \
125
+ --check-in 2026-02-10 --check-out 2026-02-12 \
126
+ --adults 2 --room-num 1 --nationality CN
127
+
128
+ # 3. Create Order (write op: locks rate, no charge; returns order_id + payable amount).
129
+ agenzo-merchant-cli hotel-redaug create-order --api-key "$API_KEY" --yes \
130
+ --product-token "$PRODUCT_TOKEN" \
131
+ --total-amount 640.00 --currency CNY \
132
+ --price-items '[{"sale_date":"2026-02-10","sale_price":320.00,"breakfast_num":2},{"sale_date":"2026-02-11","sale_price":320.00,"breakfast_num":2}]' \
133
+ --check-in 2026-02-10 --check-out 2026-02-12 \
134
+ --guest-name "Zhang San" --contact-name "Zhang San" \
135
+ --contact-phone "13800138000" --contact-country-code 86 \
136
+ --idempotency-key "hotel-create-$(date +%s)"
137
+
138
+ # 4a. Pay Order — monthly_settlement path (on-account)
139
+ agenzo-merchant-cli hotel-redaug pay-order --api-key "$API_KEY" --yes \
140
+ --order-id "$ORDER_ID" \
141
+ --idempotency-key "hotel-pay-$(date +%s)"
142
+
143
+ # 4b. Pay Order — pay_per_call path (user already paid via EVO using order_id
144
+ # as the EVO merchantTransID). Same command, no other flag.
145
+ agenzo-merchant-cli hotel-redaug pay-order --api-key "$API_KEY" --yes \
146
+ --order-id "$ORDER_ID" \
147
+ --idempotency-key "hotel-pay-$(date +%s)"
148
+
149
+ # 4c. Pay Order — pay_per_call with --watch (polls until PAID or timeout)
150
+ agenzo-merchant-cli hotel-redaug pay-order --api-key "$API_KEY" --yes \
151
+ --order-id "$ORDER_ID" \
152
+ --idempotency-key "hotel-pay-$(date +%s)" \
153
+ --watch --watch-interval 5 --watch-timeout 120
154
+
155
+ # 5. Query / poll status. create-order returns order_status=AWAITING_PAYMENT;
156
+ # after pay-order succeeds, status becomes PAID; poll get until CONFIRMED.
157
+ agenzo-merchant-cli hotel-redaug get --api-key "$API_KEY" --order-id "$ORDER_ID"
158
+ agenzo-merchant-cli hotel-redaug get --api-key "$API_KEY" --order-id "$ORDER_ID" \
159
+ --watch --watch-interval 5 --watch-timeout 600
160
+
161
+ # 6. List orders (pagination + optional status filter)
162
+ agenzo-merchant-cli hotel-redaug list-orders --api-key "$API_KEY" \
163
+ --status CONFIRMED --page 1 --page-size 20
164
+
165
+ # 7. Cancel a whole order (write op). Acceptance is NOT proof — poll get until CANCELLED.
166
+ agenzo-merchant-cli hotel-redaug cancel --api-key "$API_KEY" --yes \
167
+ --order-id "$ORDER_ID" --fc-order-code "$FC_ORDER_CODE" \
168
+ --reason "Change of plans" \
169
+ --idempotency-key "hotel-cancel-$(date +%s)"
170
+
171
+ # 8. Partial check-out / out-of-policy cancellation (write op, async).
172
+ # Returns task_order_code; poll get-checkout for the refund outcome.
173
+ agenzo-merchant-cli hotel-redaug checkout --api-key "$API_KEY" --yes \
174
+ --order-id "$ORDER_ID" --fc-order-code "$FC_ORDER_CODE" \
175
+ --reason "Guest departing early" \
176
+ --checkout-rooms '[{"room_index":"1","guest_name":"Zhang San","cancel_check_in_date":"2026-02-11"}]' \
177
+ --refund-type 1 \
178
+ --idempotency-key "hotel-checkout-$(date +%s)"
179
+
180
+ # 9. Poll the check-out application until a terminal refund status
181
+ agenzo-merchant-cli hotel-redaug get-checkout --api-key "$API_KEY" \
182
+ --task-order-code "$TASK_ORDER_CODE"
183
+ agenzo-merchant-cli hotel-redaug get-checkout --api-key "$API_KEY" \
184
+ --task-order-code "$TASK_ORDER_CODE" --watch --watch-interval 10 --watch-timeout 600
185
+ ```
186
+
89
187
  ## Global flags
90
188
 
91
189
  | Flag | Default | Description |
@@ -100,6 +198,7 @@ agenzo-merchant-cli ride-elife cancel --api-key "$API_KEY" --yes \
100
198
  - **`--format json` (non-watch commands)**: stdout contains only a **single valid JSON** (business payload + `profile`/`endpoint` envelope, where endpoint is host-only without a path); all status/progress/spinner lines go to stderr and are silenced in json mode.
101
199
  - **`--format table`**: business output goes to stdout, status lines/spinner go to stderr.
102
200
  - **`get --watch`**: stdout is a line-by-line NDJSON stream, **not wrapped** in the profile/endpoint envelope; polling stops when it hits the terminal-status set (`At destination` / `Cancelled` / `Rejected` / `Customer no show` / `Driver no show`, case-sensitive) or times out; on timeout the final line is `{ "watch_status": "timeout", ... }`.
201
+ - **`hotel-redaug get --watch` / `hotel-redaug get-checkout --watch`**: same NDJSON line-stream contract (no envelope). `get` stops when `order_status_code ∈ {3, 4, 5}` (equivalently `order_status ∈ {CONFIRMED, CANCELLED, COMPLETED}`); `get-checkout` stops when `refund_status ∈ {approved, rejected, refunded}`; on timeout the final line is `{ "watch_status": "timeout", ... }`.
103
202
  - **Error envelope**: `json` → `{ "error": { "code", "code_num", "message", "request_id"? } }`; `table` → `✗ [<code_num>] <message>`. When a request fails, retry with the same `--idempotency-key`; if it persists, contact support with the `request_id` from the error output.
104
203
 
105
204
  Exit codes:
@@ -107,7 +206,7 @@ Exit codes:
107
206
  | Exit code | Meaning | Representative error codes |
108
207
  |---|---|---|
109
208
  | `0` | Success | — |
110
- | `1` | Business / param | `PARAM_INVALID`(2101) · `PARAM_IDEMPOTENCY_KEY_REQUIRED`(2102) · `SERVICE_NOT_FOUND`(4101) · `VEHICLE_UNAVAILABLE`(4201) · `QUOTE_EXPIRED`(4202) · `BOOKING_FAILED`(4203) · `CANCELLATION_NOT_ALLOWED`(4204) · `BILLING_MODE_MISMATCH`(3001) · `ACCOUNT_*`(31xx) · `PAYMENT_ORDER_*`(32xx) |
209
+ | `1` | Business / param | `PARAM_INVALID`(2101) · `PARAM_IDEMPOTENCY_KEY_REQUIRED`(2102) · `SERVICE_NOT_FOUND`(4101) · `VEHICLE_UNAVAILABLE`(4201) · `QUOTE_EXPIRED`(4202) · `BOOKING_FAILED`(4203) · `CANCELLATION_NOT_ALLOWED`(4204) · `NO_AVAILABILITY`(4301) · `PRICE_CHANGED`(4302) · `NAME_FORMAT_INVALID`(4303) · `HOTEL_ORDER_NOT_FOUND`(4304) · `ALREADY_CANCELLED`(4305) · `CHECKOUT_NOT_ALLOWED`(4306) · `CHECKOUT_TASK_NOT_FOUND`(4307) · `PAY_PER_CALL_NOT_AVAILABLE`(4308) · `BILLING_MODE_MISMATCH`(3001) · `ACCOUNT_*`(31xx) · `PAYMENT_ORDER_*`(32xx) |
111
210
  | `2` | Upgrade required | `UPGRADE_REQUIRED`(9008) |
112
211
  | `3` | Auth / invalid key | `KEY_INVALID`(1101) · `KEY_SCOPE_DENIED`(1102) |
113
212
  | `4` | Network / 5xx | `RATE_LIMITED`(5001) · `UPSTREAM_ERROR`(5101) · `INTERNAL_ERROR`(5201) |
@@ -117,7 +216,7 @@ Exit codes:
117
216
 
118
217
  ## Idempotency-Key
119
218
 
120
- The write commands `ride-elife book` / `cancel` accept `--idempotency-key`:
219
+ The write commands `ride-elife book` / `cancel` and `hotel-redaug create-order` / `pay-order` / `cancel` / `checkout` accept `--idempotency-key`:
121
220
 
122
221
  - Format: `[A-Za-z0-9_-]{1,128}`.
123
222
  - **The CLI never auto-generates one**: `--yes` with a missing key → hard error `PARAM_IDEMPOTENCY_KEY_REQUIRED` (exit 1), and no request is sent; a missing key without `--yes` → requested interactively.
@@ -133,6 +232,22 @@ The write commands `ride-elife book` / `cancel` accept `--idempotency-key`:
133
232
 
134
233
  The request body contains at most an optional `payment_order_id`.
135
234
 
235
+ ### hotel-redaug billing (create-order + pay-order, two billing modes)
236
+
237
+ `hotel-redaug` uses a **two-step flow**: `create-order` (locks rate, no charge) then `pay-order` (settles).
238
+
239
+ `pay-order` takes only `--order-id`; there is no merchant-transaction-id flag. The billing path is
240
+ chosen server-side by the developer's `billing_mode`:
241
+
242
+ - **monthly_settlement**: deducted from the monthly-settlement account. The response carries `payment_status=ON_ACCOUNT`.
243
+ - **pay_per_call**: the user pays via shared EVO parameters out-of-band using the create-order `order_id` as the EVO merchantTransID; the platform queries EVO for that same `order_id` to confirm payment before calling upstream `payOrder` (response `settlement_path` is `pay_per_call`). If EVO reports "not yet paid", the CLI receives `PAYMENT_NOT_COMPLETED` (exit 1) — use `--watch` to poll until confirmed.
244
+
245
+ If the order's `billing_mode` is neither of the two values above, `pay-order` returns `BILLING_MODE_MISMATCH` (exit 1).
246
+
247
+ ## Amount units (decimal currency)
248
+
249
+ Both `ride-elife` and `hotel-redaug` express **every monetary amount in DECIMAL currency units** paired with an ISO 4217 `currency` code — `320.00` means 320.00 yuan, never `32000` minor units (cents/fen). This applies to inputs (`hotel-redaug create-order --total-amount`, each `--price-items[].sale_price`) and to every rendered amount (`quote` totals and `price_items`, `get` / `list-orders` prices, cancellation fees, and refunds). Amounts are forwarded and rendered **verbatim**, with no minor-unit conversion in either direction. This differs from `agenzo-token-cli` and `agenzo-payment-cli`, which use minor units.
250
+
136
251
  ## profile / host model
137
252
 
138
253
  merchant-cli **has no host / config commands** and does not govern environments. It reuses the environment configured by `agenzo-admin-cli` (persisted under `~/.agenzo-admin-cli/`):
@@ -144,9 +259,15 @@ merchant-cli **has no host / config commands** and does not govern environments.
144
259
 
145
260
  ## Machine-readable verb schema
146
261
 
147
- Every `ride-elife` verb supports `--help --format json`, emitting that verb's machine-readable schema (`cli` / `noun` / `verb` / `description` / `flags` / `response` / `example`, some with `error_recovery` / `polling`):
262
+ Every `ride-elife` and `hotel-redaug` verb supports `--help --format json`, emitting that verb's machine-readable schema (`cli` / `noun` / `verb` / `description` / `flags` / `response` / `example`, some with `error_recovery` / `polling`):
148
263
 
149
264
  ```bash
150
265
  agenzo-merchant-cli ride-elife quote --help --format json
151
266
  agenzo-merchant-cli ride-elife book --help --format json
267
+ agenzo-merchant-cli hotel-redaug quote --help --format json
268
+ agenzo-merchant-cli hotel-redaug create-order --help --format json # write verb: error_recovery
269
+ agenzo-merchant-cli hotel-redaug pay-order --help --format json # write verb: error_recovery
270
+ agenzo-merchant-cli hotel-redaug get --help --format json # long-running: polling block
152
271
  ```
272
+
273
+ For `hotel-redaug`, `create-order` / `pay-order` / `cancel` / `checkout` are the write verbs that require `--idempotency-key`, and `get` / `get-checkout` are the long-running reads that support `--watch` NDJSON streaming (their schemas carry a `polling` block).