@ratio-mcp/dev-server 1.5.0 → 1.6.0
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 +118 -0
- package/dist/schemas/app-distribution.json +36 -0
- package/dist/schemas/customers.json +26 -0
- package/dist/schemas/discounts.json +81 -0
- package/dist/schemas/draft_orders.json +112 -0
- package/dist/schemas/loyalty.json +147 -0
- package/dist/schemas/oauth.json +71 -0
- package/dist/schemas/orders.json +597 -102
- package/dist/schemas/product_reviews.json +45 -0
- package/dist/schemas/products.json +401 -118
- package/dist/schemas/tags.json +98 -0
- package/dist/schemas/variants.json +112 -0
- package/dist/schemas/webhooks.json +148 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +39 -5
- package/dist/server.js.map +1 -1
- package/dist/services/app-state-sync.d.ts +34 -0
- package/dist/services/app-state-sync.d.ts.map +1 -0
- package/dist/services/app-state-sync.js +85 -0
- package/dist/services/app-state-sync.js.map +1 -0
- package/dist/services/elicitation.d.ts +25 -0
- package/dist/services/elicitation.d.ts.map +1 -0
- package/dist/services/elicitation.js +101 -0
- package/dist/services/elicitation.js.map +1 -0
- package/dist/services/flow-profiles.d.ts +46 -0
- package/dist/services/flow-profiles.d.ts.map +1 -0
- package/dist/services/flow-profiles.js +100 -0
- package/dist/services/flow-profiles.js.map +1 -0
- package/dist/services/questionnaire.d.ts +89 -0
- package/dist/services/questionnaire.d.ts.map +1 -0
- package/dist/services/questionnaire.js +167 -0
- package/dist/services/questionnaire.js.map +1 -0
- package/dist/services/session-state.d.ts +17 -0
- package/dist/services/session-state.d.ts.map +1 -1
- package/dist/services/session-state.js +26 -1
- package/dist/services/session-state.js.map +1 -1
- package/dist/services/tool-guard.d.ts +15 -18
- package/dist/services/tool-guard.d.ts.map +1 -1
- package/dist/services/tool-guard.js +150 -97
- package/dist/services/tool-guard.js.map +1 -1
- package/dist/tools/app-management.d.ts.map +1 -1
- package/dist/tools/app-management.js +181 -33
- package/dist/tools/app-management.js.map +1 -1
- package/dist/tools/codegen.d.ts.map +1 -1
- package/dist/tools/codegen.js +21 -0
- package/dist/tools/codegen.js.map +1 -1
- package/dist/tools/gather-requirements.d.ts.map +1 -1
- package/dist/tools/gather-requirements.js +5 -3
- package/dist/tools/gather-requirements.js.map +1 -1
- package/dist/tools/get-status.d.ts.map +1 -1
- package/dist/tools/get-status.js +45 -34
- package/dist/tools/get-status.js.map +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/lifecycle.d.ts.map +1 -1
- package/dist/tools/lifecycle.js +6 -3
- package/dist/tools/lifecycle.js.map +1 -1
- package/dist/tools/reference-data.d.ts +16 -0
- package/dist/tools/reference-data.d.ts.map +1 -1
- package/dist/tools/reference-data.js +12 -8
- package/dist/tools/reference-data.js.map +1 -1
- package/dist/tools/requirements.d.ts.map +1 -1
- package/dist/tools/requirements.js +17 -9
- package/dist/tools/requirements.js.map +1 -1
- package/dist/tools/submission.d.ts.map +1 -1
- package/dist/tools/submission.js +50 -13
- package/dist/tools/submission.js.map +1 -1
- package/dist/tools/webhooks.d.ts.map +1 -1
- package/dist/tools/webhooks.js +3 -1
- package/dist/tools/webhooks.js.map +1 -1
- package/dist/utils/logger.d.ts +3 -2
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +19 -10
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/schema-resources.d.ts +8 -0
- package/dist/utils/schema-resources.d.ts.map +1 -0
- package/dist/utils/schema-resources.js +25 -0
- package/dist/utils/schema-resources.js.map +1 -0
- package/package.json +3 -3
- package/dist/orchestrated-index.d.ts +0 -11
- package/dist/orchestrated-index.d.ts.map +0 -1
- package/dist/orchestrated-index.js +0 -33
- package/dist/orchestrated-index.js.map +0 -1
- package/dist/orchestrated-server.d.ts +0 -21
- package/dist/orchestrated-server.d.ts.map +0 -1
- package/dist/orchestrated-server.js +0 -101
- package/dist/orchestrated-server.js.map +0 -1
- package/dist/services/orchestrator.d.ts +0 -63
- package/dist/services/orchestrator.d.ts.map +0 -1
- package/dist/services/orchestrator.js +0 -845
- package/dist/services/orchestrator.js.map +0 -1
- package/dist/services/response-formatter.d.ts +0 -24
- package/dist/services/response-formatter.d.ts.map +0 -1
- package/dist/services/response-formatter.js +0 -311
- package/dist/services/response-formatter.js.map +0 -1
- package/dist/tools/agent-chat.d.ts +0 -9
- package/dist/tools/agent-chat.d.ts.map +0 -1
- package/dist/tools/agent-chat.js +0 -465
- package/dist/tools/agent-chat.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# @ratio-mcp/dev-server
|
|
2
|
+
|
|
3
|
+
> MCP server exposing 33 individually-callable tools that cover the full Ratio app-creation lifecycle. Production environment.
|
|
4
|
+
|
|
5
|
+
Not installed directly — included via [`@ratio-mcp/setup`](https://www.npmjs.com/package/@ratio-mcp/setup).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
Lets developers describe an app in plain English and walks them through every phase:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
auth → app creation → scope selection → webhook setup
|
|
15
|
+
→ scaffold frontend → build → validate → submit → review
|
|
16
|
+
→ publish → scaffold backend → generate API routes
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Each tool is gated by a **prerequisite-graph guard**. Calling `upload_build` before `validate_build` returns a structured error showing exactly which tools are missing and the chain needed to unblock — the LLM self-corrects instead of guessing.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Tool catalog (33 tools)
|
|
24
|
+
|
|
25
|
+
| Category | Tools |
|
|
26
|
+
|---|---|
|
|
27
|
+
| **Auth** (3) | `developer_signup`, `developer_verify_otp`, `developer_login` |
|
|
28
|
+
| **Reference data** (1) | `get_categories` |
|
|
29
|
+
| **Hookdeck** (1) | `setup_hookdeck` |
|
|
30
|
+
| **App management** (5) | `create_app`, `get_app`, `update_app`, `list_apps`, `delete_app` |
|
|
31
|
+
| **Requirements** (3) | `gather_requirements`, `define_app_requirements`, `validate_scopes` |
|
|
32
|
+
| **Scaffold** (2) | `scaffold_frontend`, `scaffold_backend` |
|
|
33
|
+
| **Token mgmt** (2) | `refresh_access_token`, `check_token_status` |
|
|
34
|
+
| **Codegen** (1) | `generate_api_routes` |
|
|
35
|
+
| **Build** (3) | `build_frontend`, `validate_build`, `create_submission_zip` |
|
|
36
|
+
| **Submission** (4) | `upload_build`, `submit_for_review`, `get_app_status`, `publish_app` |
|
|
37
|
+
| **Webhooks** (5) | `get_webhook_topics`, `create_webhooks`, `list_webhooks`, `toggle_webhook`, `delete_webhook` |
|
|
38
|
+
| **Lifecycle / status** (2) | `get_app_lifecycle`, `get_status` |
|
|
39
|
+
|
|
40
|
+
Call `get_status` at any time to see which tools are completed, available, or blocked by missing prerequisites.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Generated artifacts (written to developer's filesystem)
|
|
45
|
+
|
|
46
|
+
When the developer runs `scaffold_frontend` + `scaffold_backend` + `generate_api_routes`:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
~/Desktop/<project>/
|
|
50
|
+
├── frontend/ # React + Vite (auth, routing, layout pre-wired)
|
|
51
|
+
│ └── ...
|
|
52
|
+
└── backend/ # NestJS
|
|
53
|
+
└── src/
|
|
54
|
+
├── main.ts
|
|
55
|
+
├── app.module.ts # auto-patched with new module imports
|
|
56
|
+
├── oauth/ # OAuth callback handler (merchant install)
|
|
57
|
+
├── orders/ # scope-filtered from schemas/orders.json
|
|
58
|
+
│ ├── orders.controller.ts
|
|
59
|
+
│ ├── orders.service.ts
|
|
60
|
+
│ └── orders.module.ts
|
|
61
|
+
├── products/ # same pattern for products
|
|
62
|
+
└── webhook/ # only if webhooks configured
|
|
63
|
+
├── webhook.controller.ts # HMAC-SHA256 signature verification
|
|
64
|
+
├── webhook.service.ts # 8 orders + 3 products event handlers
|
|
65
|
+
└── webhook.module.ts
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
After `generate_api_routes`, the backend auto-starts on port 3000 with `npm run dev`. If Hookdeck was configured earlier, a public tunnel is also live.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Webhook event coverage
|
|
73
|
+
|
|
74
|
+
The generated `webhook.service.ts` routes these events out of the box:
|
|
75
|
+
|
|
76
|
+
| Resource | Events handled |
|
|
77
|
+
|---|---|
|
|
78
|
+
| Orders (8) | `orders/create` (also alias `order-create`), `orders/updated`, `orders/cancelled`, `orders/fulfilled`, `orders/paid`, `orders/partially_fulfilled`, `orders/delete`, `orders/edited` |
|
|
79
|
+
| Products (3) | `products/create`, `products/update`, `products/delete` |
|
|
80
|
+
| App (1) | `app/uninstalled` |
|
|
81
|
+
|
|
82
|
+
Other events the platform fires (`customers/*`, `inventory/*`, `collections/*`, etc.) hit the `default:` branch and log a warning — they need handler stubs added if the developer subscribes to them.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Environment
|
|
87
|
+
|
|
88
|
+
**Production** — `https://gkx.gokwik.co/aes`
|
|
89
|
+
|
|
90
|
+
Override at runtime via `RATIO_API_BASE_URL` in the developer's `.env` file (loaded before the server starts).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Persistent state
|
|
95
|
+
|
|
96
|
+
The MCP keeps per-user state in `~/.ratio-v2/`, created lazily at first use. State survives Claude Desktop restarts — in-progress work isn't lost across sessions.
|
|
97
|
+
|
|
98
|
+
**Active:**
|
|
99
|
+
|
|
100
|
+
| Path | Purpose |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `~/.ratio-v2/requirements.json` | Per-app scope + project-path state. Written by `define_app_requirements`, enriched by `scaffold_frontend`, read by `generate_api_routes` to scope-filter the generated controllers. **Load-bearing — the whole multi-session codegen flow depends on it.** |
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
## Logging
|
|
106
|
+
|
|
107
|
+
Dual output:
|
|
108
|
+
|
|
109
|
+
- **stderr** (MCP protocol — visible in Claude Desktop logs)
|
|
110
|
+
- **File** (`logs/dev-server.log`)
|
|
111
|
+
|
|
112
|
+
Key prefixes: `[tool-guard]`, `[session-state]`, `API_REQ:`, `API_RES:`, `API_ERR:`.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
UNLICENSED — internal to the Ratio platform / GoKwik.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"topic": "app_distribution",
|
|
4
|
+
"summary": "Every Ratio app has a distribution type chosen at creation: public or private. It controls who can install the app, whether it is listed in the marketplace, and whether it goes through human review.",
|
|
5
|
+
"types": {
|
|
6
|
+
"public": {
|
|
7
|
+
"definition": "Available to ALL merchants via the marketplace.",
|
|
8
|
+
"distribution": "Listed in the public marketplace; any merchant can discover and install it.",
|
|
9
|
+
"review": "Each submitted version must pass admin (human) review before it can be published.",
|
|
10
|
+
"publication": "Published manually after approval (or via the app's auto-publish setting).",
|
|
11
|
+
"use_case": "Third-party integrations sold to many merchants.",
|
|
12
|
+
"create": "Default. create_app with app_type omitted or app_type: \"public\"."
|
|
13
|
+
},
|
|
14
|
+
"private": {
|
|
15
|
+
"definition": "Available ONLY to an explicit whitelist of merchants.",
|
|
16
|
+
"distribution": "Not listed in the marketplace; installable only by whitelisted merchant IDs.",
|
|
17
|
+
"review": "Skips human review — versions are auto-reviewed (system actor) and auto-published on upload.",
|
|
18
|
+
"publication": "Immediate on version upload.",
|
|
19
|
+
"requirement": "At least one merchant ID must be provided at creation time.",
|
|
20
|
+
"whitelist_management": "Add/remove merchants any time via the manage_private_merchants tool (or GET/POST/DELETE /applications/:id/private-merchants).",
|
|
21
|
+
"use_case": "Custom builds for specific enterprise clients or partner integrations.",
|
|
22
|
+
"create": "create_app with app_type: \"private\" and merchant_ids: [\"merchant-id-1\", ...] (at least one)."
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"comparison": [
|
|
26
|
+
{ "aspect": "Distribution", "public": "All merchants", "private": "Whitelisted merchants only" },
|
|
27
|
+
{ "aspect": "Marketplace", "public": "Listed", "private": "Hidden" },
|
|
28
|
+
{ "aspect": "Review", "public": "Human review required", "private": "Auto-reviewed (system)" },
|
|
29
|
+
{ "aspect": "Publication", "public": "After approval", "private": "Immediate on upload" },
|
|
30
|
+
{ "aspect": "Merchant ID whitelist", "public": "N/A", "private": "Required (>= 1)" }
|
|
31
|
+
],
|
|
32
|
+
"mcp_support": {
|
|
33
|
+
"create_app": "Accepts app_type ('public' | 'private', default public) and merchant_ids. Private requires merchant_ids (>= 1).",
|
|
34
|
+
"manage_private_merchants": "list | add | remove whitelisted merchants for a private app."
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"resource": "customers",
|
|
3
|
+
"auth": {
|
|
4
|
+
"type": "bearer",
|
|
5
|
+
"header": "Authorization",
|
|
6
|
+
"format": "Bearer <access_token>"
|
|
7
|
+
},
|
|
8
|
+
"_generated": "by scripts/sync-schemas.mjs from backend OpenAPI (x-required-scope). Do not hand-edit.",
|
|
9
|
+
"endpoints": [
|
|
10
|
+
{
|
|
11
|
+
"method": "GET",
|
|
12
|
+
"path": "/api/v1/customers/:id",
|
|
13
|
+
"controller_order": 1,
|
|
14
|
+
"handler_name": "getCustomerById",
|
|
15
|
+
"required_scope": "read_customers",
|
|
16
|
+
"path_params": [
|
|
17
|
+
{
|
|
18
|
+
"name": "id",
|
|
19
|
+
"type": "string",
|
|
20
|
+
"required": true
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"request_body": null
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"resource": "discounts",
|
|
3
|
+
"auth": {
|
|
4
|
+
"type": "bearer",
|
|
5
|
+
"header": "Authorization",
|
|
6
|
+
"format": "Bearer <access_token>"
|
|
7
|
+
},
|
|
8
|
+
"common_headers": {
|
|
9
|
+
"idempotency-key": "header"
|
|
10
|
+
},
|
|
11
|
+
"_generated": "by scripts/sync-schemas.mjs from backend OpenAPI (x-required-scope). Do not hand-edit.",
|
|
12
|
+
"endpoints": [
|
|
13
|
+
{
|
|
14
|
+
"method": "POST",
|
|
15
|
+
"path": "/api/v1/discounts",
|
|
16
|
+
"controller_order": 1,
|
|
17
|
+
"handler_name": "create",
|
|
18
|
+
"required_scope": "write_discounts",
|
|
19
|
+
"request_body": {
|
|
20
|
+
"content_type": "application/json",
|
|
21
|
+
"fields": []
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"method": "GET",
|
|
26
|
+
"path": "/api/v1/discounts",
|
|
27
|
+
"controller_order": 2,
|
|
28
|
+
"handler_name": "findAll",
|
|
29
|
+
"required_scope": "read_discounts",
|
|
30
|
+
"request_body": null
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"method": "GET",
|
|
34
|
+
"path": "/api/v1/discounts/:id",
|
|
35
|
+
"controller_order": 3,
|
|
36
|
+
"handler_name": "findOne",
|
|
37
|
+
"required_scope": "read_discounts",
|
|
38
|
+
"path_params": [
|
|
39
|
+
{
|
|
40
|
+
"name": "id",
|
|
41
|
+
"type": "string",
|
|
42
|
+
"required": true
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"request_body": null
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"method": "PUT",
|
|
49
|
+
"path": "/api/v1/discounts/:id",
|
|
50
|
+
"controller_order": 4,
|
|
51
|
+
"handler_name": "update",
|
|
52
|
+
"required_scope": "write_discounts",
|
|
53
|
+
"path_params": [
|
|
54
|
+
{
|
|
55
|
+
"name": "id",
|
|
56
|
+
"type": "string",
|
|
57
|
+
"required": true
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"request_body": {
|
|
61
|
+
"content_type": "application/json",
|
|
62
|
+
"fields": []
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"method": "DELETE",
|
|
67
|
+
"path": "/api/v1/discounts/:id",
|
|
68
|
+
"controller_order": 5,
|
|
69
|
+
"handler_name": "remove",
|
|
70
|
+
"required_scope": "write_discounts",
|
|
71
|
+
"path_params": [
|
|
72
|
+
{
|
|
73
|
+
"name": "id",
|
|
74
|
+
"type": "string",
|
|
75
|
+
"required": true
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"request_body": null
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"resource": "draft_orders",
|
|
3
|
+
"auth": {
|
|
4
|
+
"type": "bearer",
|
|
5
|
+
"header": "Authorization",
|
|
6
|
+
"format": "Bearer <access_token>"
|
|
7
|
+
},
|
|
8
|
+
"common_headers": {
|
|
9
|
+
"gk-merchant-id": "Required. Tenant/merchant context for the request."
|
|
10
|
+
},
|
|
11
|
+
"notes": "Paths carry a doubled /v1 segment (global /api/v1 prefix + controller 'v1/draft-orders'). Line-item / customer / address shapes mirror the orders resource.",
|
|
12
|
+
"endpoints": [
|
|
13
|
+
{
|
|
14
|
+
"method": "POST",
|
|
15
|
+
"path": "/api/v1/v1/draft-orders",
|
|
16
|
+
"controller_order": 1,
|
|
17
|
+
"handler_name": "createDraftOrder",
|
|
18
|
+
"required_scope": "write_draft_orders",
|
|
19
|
+
"summary": "Create a draft order",
|
|
20
|
+
"request_body": {
|
|
21
|
+
"content_type": "application/json",
|
|
22
|
+
"fields": [
|
|
23
|
+
{ "name": "email", "type": "string", "required": false, "description": "Customer email" },
|
|
24
|
+
{ "name": "currency", "type": "string", "required": false, "description": "Currency code (e.g. INR)" },
|
|
25
|
+
{ "name": "line_items", "type": "array", "required": false, "description": "Line items (same shape as orders: variant_id, product_id, title, quantity, sku, price)" },
|
|
26
|
+
{ "name": "customer", "type": "object", "required": false, "description": "Customer details (same shape as orders)" },
|
|
27
|
+
{ "name": "billing_address", "type": "object", "required": false, "description": "Billing address (same shape as orders)" },
|
|
28
|
+
{ "name": "shipping_address", "type": "object", "required": false, "description": "Shipping address (same shape as orders)" },
|
|
29
|
+
{ "name": "note", "type": "string", "required": false }
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"response_schema": "DraftOrder"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"method": "PUT",
|
|
36
|
+
"path": "/api/v1/v1/draft-orders",
|
|
37
|
+
"controller_order": 2,
|
|
38
|
+
"handler_name": "updateDraftOrder",
|
|
39
|
+
"required_scope": "write_draft_orders",
|
|
40
|
+
"summary": "Update a draft order",
|
|
41
|
+
"description": "Update a draft order. The draft order id is supplied in the request body (not the path).",
|
|
42
|
+
"request_body": {
|
|
43
|
+
"content_type": "application/json",
|
|
44
|
+
"fields": [
|
|
45
|
+
{ "name": "id", "type": "string", "required": true, "description": "The draft order ID to update (in body)" },
|
|
46
|
+
{ "name": "email", "type": "string", "required": false },
|
|
47
|
+
{ "name": "line_items", "type": "array", "required": false },
|
|
48
|
+
{ "name": "customer", "type": "object", "required": false },
|
|
49
|
+
{ "name": "shipping_address", "type": "object", "required": false },
|
|
50
|
+
{ "name": "billing_address", "type": "object", "required": false }
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"response_schema": "DraftOrder"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"method": "GET",
|
|
57
|
+
"path": "/api/v1/v1/draft-orders",
|
|
58
|
+
"controller_order": 3,
|
|
59
|
+
"handler_name": "getDraftOrders",
|
|
60
|
+
"required_scope": "read_draft_orders",
|
|
61
|
+
"summary": "List draft orders",
|
|
62
|
+
"query_params": [
|
|
63
|
+
{ "name": "limit", "type": "number", "required": false },
|
|
64
|
+
{ "name": "offset", "type": "number", "required": false },
|
|
65
|
+
{ "name": "status", "type": "string", "required": false }
|
|
66
|
+
],
|
|
67
|
+
"request_body": null,
|
|
68
|
+
"response_schema": "DraftOrderListResponse"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"method": "GET",
|
|
72
|
+
"path": "/api/v1/v1/draft-orders/:id",
|
|
73
|
+
"controller_order": 4,
|
|
74
|
+
"handler_name": "getDraftOrderById",
|
|
75
|
+
"required_scope": "read_draft_orders",
|
|
76
|
+
"summary": "Get a draft order by ID",
|
|
77
|
+
"path_params": [
|
|
78
|
+
{ "name": "id", "type": "string", "required": true, "description": "The draft order ID" }
|
|
79
|
+
],
|
|
80
|
+
"request_body": null,
|
|
81
|
+
"response_schema": "DraftOrder"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"method": "DELETE",
|
|
85
|
+
"path": "/api/v1/v1/draft-orders/:id",
|
|
86
|
+
"controller_order": 5,
|
|
87
|
+
"handler_name": "deleteDraftOrder",
|
|
88
|
+
"required_scope": "write_draft_orders",
|
|
89
|
+
"summary": "Delete a draft order",
|
|
90
|
+
"path_params": [
|
|
91
|
+
{ "name": "id", "type": "string", "required": true, "description": "The draft order ID to delete" }
|
|
92
|
+
],
|
|
93
|
+
"request_body": null,
|
|
94
|
+
"response_schema": "DraftOrder"
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"schemas": {
|
|
98
|
+
"DraftOrder": {
|
|
99
|
+
"id": "string — draft order identifier",
|
|
100
|
+
"email": "string | null",
|
|
101
|
+
"currency": "string",
|
|
102
|
+
"line_items": "LineItem[] — same shape as orders",
|
|
103
|
+
"customer": "Customer object",
|
|
104
|
+
"shipping_address": "Address | null",
|
|
105
|
+
"billing_address": "Address | null",
|
|
106
|
+
"note": "string | null",
|
|
107
|
+
"status": "string — draft status",
|
|
108
|
+
"created_at": "string — ISO 8601",
|
|
109
|
+
"updated_at": "string — ISO 8601"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
{
|
|
2
|
+
"resource": "loyalty",
|
|
3
|
+
"auth": {
|
|
4
|
+
"type": "bearer",
|
|
5
|
+
"header": "Authorization",
|
|
6
|
+
"format": "Bearer <access_token>"
|
|
7
|
+
},
|
|
8
|
+
"_generated": "by scripts/sync-schemas.mjs from backend OpenAPI (x-required-scope). Do not hand-edit.",
|
|
9
|
+
"endpoints": [
|
|
10
|
+
{
|
|
11
|
+
"method": "POST",
|
|
12
|
+
"path": "/api/v1/loyalty/points/credit",
|
|
13
|
+
"controller_order": 1,
|
|
14
|
+
"handler_name": "credit",
|
|
15
|
+
"required_scope": "write_loyalty",
|
|
16
|
+
"summary": "Credit loyalty points to a customer (idempotent).",
|
|
17
|
+
"description": "Adds points to the customer’s balance. Same `idempotency_key` on retry returns the existing transaction without double-crediting.",
|
|
18
|
+
"request_body": {
|
|
19
|
+
"content_type": "application/json",
|
|
20
|
+
"fields": [
|
|
21
|
+
{
|
|
22
|
+
"name": "phone",
|
|
23
|
+
"type": "string",
|
|
24
|
+
"required": true,
|
|
25
|
+
"description": "Customer phone number (loyalty key)"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "points",
|
|
29
|
+
"type": "number",
|
|
30
|
+
"required": true,
|
|
31
|
+
"description": "Points to apply (positive integer, max 100000 per transaction)"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "idempotency_key",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"required": true,
|
|
37
|
+
"description": "Caller-supplied idempotency key. Same key on retry returns the existing transaction without double-applying."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "description",
|
|
41
|
+
"type": "string",
|
|
42
|
+
"required": false,
|
|
43
|
+
"description": "Free-text description of the reason"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "metadata",
|
|
47
|
+
"type": "object",
|
|
48
|
+
"required": false,
|
|
49
|
+
"description": "Arbitrary structured data attached to the ledger row"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"method": "POST",
|
|
56
|
+
"path": "/api/v1/loyalty/points/debit",
|
|
57
|
+
"controller_order": 2,
|
|
58
|
+
"handler_name": "debit",
|
|
59
|
+
"required_scope": "write_loyalty",
|
|
60
|
+
"summary": "Debit loyalty points from a customer (idempotent).",
|
|
61
|
+
"description": "Deducts points from the customer’s balance. Returns 400 if the customer’s balance is insufficient.",
|
|
62
|
+
"request_body": {
|
|
63
|
+
"content_type": "application/json",
|
|
64
|
+
"fields": [
|
|
65
|
+
{
|
|
66
|
+
"name": "phone",
|
|
67
|
+
"type": "string",
|
|
68
|
+
"required": true,
|
|
69
|
+
"description": "Customer phone number (loyalty key)"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "points",
|
|
73
|
+
"type": "number",
|
|
74
|
+
"required": true,
|
|
75
|
+
"description": "Points to apply (positive integer, max 100000 per transaction)"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "idempotency_key",
|
|
79
|
+
"type": "string",
|
|
80
|
+
"required": true,
|
|
81
|
+
"description": "Caller-supplied idempotency key. Same key on retry returns the existing transaction without double-applying."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "description",
|
|
85
|
+
"type": "string",
|
|
86
|
+
"required": false,
|
|
87
|
+
"description": "Free-text description of the reason"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "metadata",
|
|
91
|
+
"type": "object",
|
|
92
|
+
"required": false,
|
|
93
|
+
"description": "Arbitrary structured data attached to the ledger row"
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"method": "GET",
|
|
100
|
+
"path": "/api/v1/loyalty/points/:phone/balance",
|
|
101
|
+
"controller_order": 3,
|
|
102
|
+
"handler_name": "getBalance",
|
|
103
|
+
"required_scope": "read_loyalty",
|
|
104
|
+
"summary": "Get a customer's current loyalty balance + lifetime stats.",
|
|
105
|
+
"description": "Returns the redeemable balance and lifetime earned/redeemed/expired/adjusted totals. A customer with no loyalty record yet returns a zero-balance response.",
|
|
106
|
+
"path_params": [
|
|
107
|
+
{
|
|
108
|
+
"name": "phone",
|
|
109
|
+
"type": "string",
|
|
110
|
+
"required": true
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"request_body": null
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"method": "GET",
|
|
117
|
+
"path": "/api/v1/loyalty/points/:phone/history",
|
|
118
|
+
"controller_order": 4,
|
|
119
|
+
"handler_name": "getHistory",
|
|
120
|
+
"required_scope": "read_loyalty",
|
|
121
|
+
"summary": "Get a customer's loyalty transaction history (paginated).",
|
|
122
|
+
"description": "Returns the full points ledger (earn, redeem, adjust, reversal, expire) for the customer, most recent first, with pagination metadata.",
|
|
123
|
+
"query_params": [
|
|
124
|
+
{
|
|
125
|
+
"name": "page",
|
|
126
|
+
"type": "number",
|
|
127
|
+
"required": false,
|
|
128
|
+
"description": "Page number (1-based); os-loyalty defaults to 1"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "limit",
|
|
132
|
+
"type": "number",
|
|
133
|
+
"required": false,
|
|
134
|
+
"description": "Rows per page"
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"path_params": [
|
|
138
|
+
{
|
|
139
|
+
"name": "phone",
|
|
140
|
+
"type": "string",
|
|
141
|
+
"required": true
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
"request_body": null
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"flows": {
|
|
4
|
+
"authorization_code": {
|
|
5
|
+
"description": "Standard OAuth 2.0 Authorization Code flow for installing apps on merchant stores",
|
|
6
|
+
"steps": [
|
|
7
|
+
{
|
|
8
|
+
"step": 1,
|
|
9
|
+
"name": "Request Authorization Code",
|
|
10
|
+
"method": "POST",
|
|
11
|
+
"endpoint": "/api/v1/oauth/authorize",
|
|
12
|
+
"description": "Request an authorization code by providing client_id, merchant_id, redirect_uri, and scopes. The app must be published before this step.",
|
|
13
|
+
"request_body": {
|
|
14
|
+
"clientId": "string — Your app's client ID",
|
|
15
|
+
"redirectUri": "string — Registered redirect URI",
|
|
16
|
+
"merchantId": "string — Merchant ID of the store installing the app",
|
|
17
|
+
"scopes": "string[] — Array of scopes to request (e.g. ['read_orders'])"
|
|
18
|
+
},
|
|
19
|
+
"response": {
|
|
20
|
+
"code": "string — Authorization code (expires quickly)",
|
|
21
|
+
"redirectUri": "string — The redirect URI",
|
|
22
|
+
"expiresAt": "string — ISO 8601 expiry timestamp"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"step": 2,
|
|
27
|
+
"name": "Exchange Code for Tokens",
|
|
28
|
+
"method": "POST",
|
|
29
|
+
"endpoint": "/api/v1/oauth/token",
|
|
30
|
+
"description": "Exchange the authorization code for access and refresh tokens. Must be called immediately — the code expires quickly.",
|
|
31
|
+
"request_body": {
|
|
32
|
+
"grant_type": "authorization_code",
|
|
33
|
+
"code": "string — The authorization code from step 1",
|
|
34
|
+
"clientId": "string — Your app's client ID",
|
|
35
|
+
"clientSecret": "string — Your app's client secret",
|
|
36
|
+
"redirectUri": "string — Must match step 1"
|
|
37
|
+
},
|
|
38
|
+
"response": {
|
|
39
|
+
"access_token": "string — Bearer token for API calls",
|
|
40
|
+
"token_type": "Bearer",
|
|
41
|
+
"expires_in": "number — Seconds until token expires",
|
|
42
|
+
"refresh_token": "string — Token for refreshing access",
|
|
43
|
+
"scope": "string — Granted scopes (comma-separated)",
|
|
44
|
+
"merchant_id": "string — Merchant ID"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"step": 3,
|
|
49
|
+
"name": "Refresh Token",
|
|
50
|
+
"method": "POST",
|
|
51
|
+
"endpoint": "/api/v1/oauth/token",
|
|
52
|
+
"description": "Use the refresh token to get a new access token when the current one expires.",
|
|
53
|
+
"request_body": {
|
|
54
|
+
"grant_type": "refresh_token",
|
|
55
|
+
"refresh_token": "string — The refresh token",
|
|
56
|
+
"clientId": "string — Your app's client ID",
|
|
57
|
+
"clientSecret": "string — Your app's client secret"
|
|
58
|
+
},
|
|
59
|
+
"response": {
|
|
60
|
+
"access_token": "string — New bearer token",
|
|
61
|
+
"token_type": "Bearer",
|
|
62
|
+
"expires_in": "number — Seconds until new token expires",
|
|
63
|
+
"refresh_token": "string — New refresh token",
|
|
64
|
+
"scope": "string — Granted scopes",
|
|
65
|
+
"merchant_id": "string — Merchant ID"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|