@mongoui/skills 0.1.9 → 0.2.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 +50 -0
- package/dist/products/index.js +12 -5
- package/package.json +7 -3
- package/skills/bms-api/SKILL.md +26 -0
- package/skills/bms-api/references/api-workflows.md +27 -0
- package/skills/bms-api/references/auth-and-calling.md +35 -0
- package/skills/bms-api/references/endpoint-index.md +137 -0
- package/skills/bms-api/references/openapi.json +1 -0
- package/skills/bms-api/references/source-manifest.json +5 -0
- package/skills/bms-api/scripts/bms_signed_request.py +103 -0
- package/skills/glink-hotel-api/SKILL.md +6 -6
- package/skills/glink-hotel-api/references/api-workflows.md +32 -32
- package/skills/glink-hotel-api/references/endpoint-index.md +77 -77
- package/skills/tmc-api/SKILL.md +63 -0
- package/skills/tmc-api/agents/openai.yaml +4 -0
- package/skills/tmc-api/references/api-workflows.md +365 -0
- package/skills/tmc-api/references/auth-and-calling.md +47 -0
- package/skills/tmc-api/references/endpoint-details.md +25964 -0
- package/skills/tmc-api/references/endpoint-index.md +116 -0
- package/skills/tmc-api/scripts/tmc_signed_request.py +199 -0
- package/skills/tmc-whitelabel/SKILL.md +0 -8
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Sign BMS JSON requests offline; use --send explicitly for a network request."""
|
|
3
|
+
import argparse
|
|
4
|
+
import hashlib
|
|
5
|
+
import hmac
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import sys
|
|
10
|
+
import time
|
|
11
|
+
import urllib.error
|
|
12
|
+
import urllib.parse
|
|
13
|
+
import urllib.request
|
|
14
|
+
import uuid
|
|
15
|
+
|
|
16
|
+
TOKEN_EXCEPTIONS = {'/openapi/v1/bms/auth/token', '/openapi/v1/bms/auth/customer/register'}
|
|
17
|
+
|
|
18
|
+
def canonical_query(raw):
|
|
19
|
+
# Match pkg/crypto/signature.go: decode form query before sorting; no re-encoding.
|
|
20
|
+
return '&'.join(key+'='+value for key, value in sorted(urllib.parse.parse_qsl(raw, keep_blank_values=True)))
|
|
21
|
+
|
|
22
|
+
def sign_request(method, path, raw_query, body, app_id, secret, timestamp, nonce):
|
|
23
|
+
canonical = '\n'.join([method.upper(), path, canonical_query(raw_query), hashlib.sha256(body).hexdigest(), timestamp.strip(), nonce.strip(), app_id.strip()])
|
|
24
|
+
signature = hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
|
|
25
|
+
return canonical, {'X-OP-App-Key': app_id.strip(), 'X-OP-Timestamp': timestamp.strip(), 'X-OP-Nonce': nonce.strip(), 'X-OP-Sign': signature}
|
|
26
|
+
|
|
27
|
+
def redact(value):
|
|
28
|
+
if isinstance(value, dict):
|
|
29
|
+
return {key: '<redacted>' if any(word in key.lower() for word in ['secret', 'token', 'password', 'aeskey', 'sign']) else redact(item) for key, item in value.items()}
|
|
30
|
+
if isinstance(value, list):
|
|
31
|
+
return [redact(item) for item in value]
|
|
32
|
+
return value
|
|
33
|
+
|
|
34
|
+
class NoRedirect(urllib.request.HTTPRedirectHandler):
|
|
35
|
+
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
def main():
|
|
39
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
40
|
+
parser.add_argument('--method', required=True)
|
|
41
|
+
parser.add_argument('--path', required=True, help='Complete public path without query')
|
|
42
|
+
parser.add_argument('--query', default='', help='Actual URL query string; percent-encoded when needed')
|
|
43
|
+
body_group = parser.add_mutually_exclusive_group()
|
|
44
|
+
body_group.add_argument('--body-json')
|
|
45
|
+
body_group.add_argument('--body-file', type=Path, help='Exact UTF-8 JSON body bytes')
|
|
46
|
+
parser.add_argument('--base-url', default=os.getenv('OPEN_API_BASE_URL'))
|
|
47
|
+
parser.add_argument('--timestamp', default=str(int(time.time())))
|
|
48
|
+
parser.add_argument('--nonce', default=uuid.uuid4().hex)
|
|
49
|
+
parser.add_argument('--send', action='store_true')
|
|
50
|
+
parser.add_argument('--timeout', type=float, default=20)
|
|
51
|
+
args = parser.parse_args()
|
|
52
|
+
app_id = os.getenv('OPEN_APP_ID', '').strip()
|
|
53
|
+
secret = os.getenv('OPEN_APP_SECRET', '')
|
|
54
|
+
token = os.getenv('BMS_TOKEN', '').strip()
|
|
55
|
+
if not app_id or not secret:
|
|
56
|
+
parser.error('Set OPEN_APP_ID and OPEN_APP_SECRET in the server environment.')
|
|
57
|
+
if not args.path.startswith('/openapi/v1/bms/') or '?' in args.path or '#' in args.path:
|
|
58
|
+
parser.error('--path must be the full public BMS path, without query or fragment.')
|
|
59
|
+
try:
|
|
60
|
+
if args.body_file:
|
|
61
|
+
body = args.body_file.read_bytes()
|
|
62
|
+
json.loads(body)
|
|
63
|
+
elif args.body_json is not None:
|
|
64
|
+
body = json.dumps(json.loads(args.body_json), ensure_ascii=False, separators=(',', ':')).encode()
|
|
65
|
+
else:
|
|
66
|
+
body = b''
|
|
67
|
+
except (OSError, ValueError):
|
|
68
|
+
parser.error('Body must be valid JSON; multipart and file downloads need a separate client.')
|
|
69
|
+
canonical, headers = sign_request(args.method, args.path, args.query, body, app_id, secret, args.timestamp, args.nonce)
|
|
70
|
+
headers['Accept'] = 'application/json'
|
|
71
|
+
if body:
|
|
72
|
+
headers['Content-Type'] = 'application/json'
|
|
73
|
+
if args.path not in TOKEN_EXCEPTIONS:
|
|
74
|
+
if args.send and not token:
|
|
75
|
+
parser.error('Business requests require BMS_TOKEN from this environment.')
|
|
76
|
+
if token:
|
|
77
|
+
headers['token'] = token
|
|
78
|
+
if not args.send:
|
|
79
|
+
print(json.dumps({'mode':'offline', 'method':args.method.upper(), 'path':args.path, 'canonical_string':canonical, 'headers':redact(headers), 'body_bytes':len(body), 'token_required':args.path not in TOKEN_EXCEPTIONS}, ensure_ascii=False, indent=2))
|
|
80
|
+
return 0
|
|
81
|
+
parsed = urllib.parse.urlsplit(args.base_url or '')
|
|
82
|
+
if parsed.scheme not in {'http','https'} or not parsed.netloc or parsed.username or parsed.query or parsed.fragment or parsed.path.rstrip('/'):
|
|
83
|
+
parser.error('Set OPEN_API_BASE_URL to the selected Open Platform gateway origin, without credentials, path, query or fragment.')
|
|
84
|
+
url = args.base_url.rstrip('/')+args.path+('?' + args.query if args.query else '')
|
|
85
|
+
request = urllib.request.Request(url, data=body if body else None, headers=headers, method=args.method.upper())
|
|
86
|
+
try:
|
|
87
|
+
response = urllib.request.build_opener(NoRedirect()).open(request, timeout=args.timeout)
|
|
88
|
+
with response:
|
|
89
|
+
status, data = response.status, response.read()
|
|
90
|
+
except urllib.error.HTTPError as error:
|
|
91
|
+
status, data = error.code, error.read()
|
|
92
|
+
except (urllib.error.URLError, TimeoutError):
|
|
93
|
+
print('Request outcome unknown. Query the business record before replaying a write.', file=sys.stderr)
|
|
94
|
+
return 1
|
|
95
|
+
print('HTTP', status)
|
|
96
|
+
try:
|
|
97
|
+
print(json.dumps(redact(json.loads(data)), ensure_ascii=False, indent=2))
|
|
98
|
+
except (ValueError, UnicodeError):
|
|
99
|
+
print('Non-JSON response; use a binary-capable client for exports.')
|
|
100
|
+
return 0 if 200 <= status < 300 else 1
|
|
101
|
+
|
|
102
|
+
if __name__ == '__main__':
|
|
103
|
+
raise SystemExit(main())
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: glink-hotel-api
|
|
2
|
+
name: glink-hotel-api
|
|
3
3
|
description: Integrate with the Glink hotel OpenAPI exposed through the Open Platform runtime gateway. Use when Codex needs to read, verify, explain, test, or implement against `docs/swagger/glink-api.json` or Glink route code; choose Glink hotel endpoints; generate or debug `X-OP-*` signatures; explain sandbox or production credential issuance/reset; or drive Chinese/English requests about Glink hotel static data, hotel search, hotel info, product detail, booking, payment, order, cancel, order status push/callback, checkout, invoice, and balance workflows.
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -14,11 +14,11 @@ Start with the smallest current source that answers the request:
|
|
|
14
14
|
- Prefer the repository source of truth when it exists: `docs/swagger/glink-api.json`, route handlers, DTOs, and tests.
|
|
15
15
|
- Treat the current DHub shared document and `docs/swagger/glink-api.json` as the route source of truth; older bundled notes can be stale.
|
|
16
16
|
- Customer-facing explanations should use only our short interface paths such as `/search/destination`, `/booking/createOrder`, and `/order/orderDetail`.
|
|
17
|
-
- Read `references/auth-and-credentials.md` for signing, headers, key acquisition, reset, and auth troubleshooting.
|
|
18
|
-
- Read `references/api-workflows.md` for hotel search, booking, cancel, checkout, invoice, and balance workflows.
|
|
19
|
-
- Read `references/endpoint-index.md` for a compact endpoint map and platform-managed field caveats, then verify fragile fields against the current swagger or code.
|
|
20
|
-
- Read `references/field-and-enum-notes.md` for current response-shape changes, renamed fields, enum-like values, and practical scenarios reflected by the latest swagger examples.
|
|
21
|
-
- Use `scripts/glink_signed_request.py` to generate headers, inspect the canonical string, or send a signed request.
|
|
17
|
+
- Read `references/auth-and-credentials.md` for signing, headers, key acquisition, reset, and auth troubleshooting.
|
|
18
|
+
- Read `references/api-workflows.md` for hotel search, booking, cancel, checkout, invoice, and balance workflows.
|
|
19
|
+
- Read `references/endpoint-index.md` for a compact endpoint map and platform-managed field caveats, then verify fragile fields against the current swagger or code.
|
|
20
|
+
- Read `references/field-and-enum-notes.md` for current response-shape changes, renamed fields, enum-like values, and practical scenarios reflected by the latest swagger examples.
|
|
21
|
+
- Use `scripts/glink_signed_request.py` to generate headers, inspect the canonical string, or send a signed request.
|
|
22
22
|
|
|
23
23
|
## Working Rules
|
|
24
24
|
|
|
@@ -38,14 +38,14 @@ These APIs usually feed country/city selection, district filters, POI filters, b
|
|
|
38
38
|
|
|
39
39
|
For Standard API Integration, build local hotel and room mapping in this order:
|
|
40
40
|
|
|
41
|
-
1. `/search/hotelIdList`
|
|
42
|
-
- Fetch the account's saleable hotel ID list and cache it locally.
|
|
43
|
-
- Use `pageNo` and `pageSize` for pagination; current examples default to `pageNo=1` and `pageSize=1000`.
|
|
44
|
-
- Read `totalCount` for the total count when returned.
|
|
45
|
-
2. `/hotel/detail`
|
|
46
|
-
- Fetch hotel and room static data for the cached hotel IDs. Persist only the fields needed for local hotel and room mapping.
|
|
47
|
-
- Current static fields use `facility`, `popularFacility`, `roomInfos`, `latBaidu`, `lngBaidu`, `groupName`, and `brandName`.
|
|
48
|
-
- Room bed structures expose object `bedInfos[]` for both bedroom and living room beds.
|
|
41
|
+
1. `/search/hotelIdList`
|
|
42
|
+
- Fetch the account's saleable hotel ID list and cache it locally.
|
|
43
|
+
- Use `pageNo` and `pageSize` for pagination; current examples default to `pageNo=1` and `pageSize=1000`.
|
|
44
|
+
- Read `totalCount` for the total count when returned.
|
|
45
|
+
2. `/hotel/detail`
|
|
46
|
+
- Fetch hotel and room static data for the cached hotel IDs. Persist only the fields needed for local hotel and room mapping.
|
|
47
|
+
- Current static fields use `facility`, `popularFacility`, `roomInfos`, `latBaidu`, `lngBaidu`, `groupName`, and `brandName`.
|
|
48
|
+
- Room bed structures expose object `bedInfos[]` for both bedroom and living room beds.
|
|
49
49
|
3. `/hotel/increment`
|
|
50
50
|
- Periodically fetch changed hotel IDs, including added, updated, or deleted hotels.
|
|
51
51
|
4. `/hotel/detail`
|
|
@@ -77,16 +77,16 @@ Mandatory interfaces:
|
|
|
77
77
|
|
|
78
78
|
Recommended sequence:
|
|
79
79
|
|
|
80
|
-
1. `/search/destination`
|
|
81
|
-
- Resolve the destination keyword into an Open Platform destination ID.
|
|
82
|
-
- The response `data` is an array of flat destination objects. Use `destinationType` and `source` to decide whether the match is a hotel, city, district, business area, Google/Baidu result, or another type.
|
|
83
|
-
2. `/search/hotelFilters`
|
|
84
|
-
- Fetch filter conditions when the UI needs hotel filters.
|
|
85
|
-
3. `/search/hotelList`
|
|
86
|
-
- Search destination-based hotel results using the destination ID, stay dates, and optional filters.
|
|
87
|
-
- List items use `latBaidu` and `lngBaidu`; `groupName` and `brandName` can be displayed when present.
|
|
88
|
-
4. `/hotel/detail` and optionally `/hotel/images`
|
|
89
|
-
- Read richer hotel details and media for client display after the hotel list returns candidates.
|
|
80
|
+
1. `/search/destination`
|
|
81
|
+
- Resolve the destination keyword into an Open Platform destination ID.
|
|
82
|
+
- The response `data` is an array of flat destination objects. Use `destinationType` and `source` to decide whether the match is a hotel, city, district, business area, Google/Baidu result, or another type.
|
|
83
|
+
2. `/search/hotelFilters`
|
|
84
|
+
- Fetch filter conditions when the UI needs hotel filters.
|
|
85
|
+
3. `/search/hotelList`
|
|
86
|
+
- Search destination-based hotel results using the destination ID, stay dates, and optional filters.
|
|
87
|
+
- List items use `latBaidu` and `lngBaidu`; `groupName` and `brandName` can be displayed when present.
|
|
88
|
+
4. `/hotel/detail` and optionally `/hotel/images`
|
|
89
|
+
- Read richer hotel details and media for client display after the hotel list returns candidates.
|
|
90
90
|
5. `/hotel/lowestPrice`
|
|
91
91
|
- Optional but useful for list-page price reference when the experience needs a stable starting-price display.
|
|
92
92
|
6. `/booking/productDetails`
|
|
@@ -110,12 +110,12 @@ Use this sequence for both Standard API Integration and Lightweight Integration
|
|
|
110
110
|
|
|
111
111
|
1. `/booking/productDetails`
|
|
112
112
|
- Identify the exact sellable room and rate.
|
|
113
|
-
2. `/booking/availabilityCheck`
|
|
114
|
-
- Perform pre-booking validation with the actual room count. Use this before showing or entering the final order submission path.
|
|
115
|
-
- Use response-level `breakfastNum` and `breakfastType`. Tax breakdown is under `priceItems[].taxDetail` and `roomTaxDetail`.
|
|
116
|
-
3. `/booking/createOrder`
|
|
117
|
-
- Submit the order with guest, contact, amount, and price item details. When the local order has been created and is ready to submit, call `/booking/availabilityCheck` again first if there is any delay or state change risk.
|
|
118
|
-
- Use `guestInfos[].guestType` for the guest type dictionary. Do not send the old nested `guestInfos[].nationality` field.
|
|
113
|
+
2. `/booking/availabilityCheck`
|
|
114
|
+
- Perform pre-booking validation with the actual room count. Use this before showing or entering the final order submission path.
|
|
115
|
+
- Use response-level `breakfastNum` and `breakfastType`. Tax breakdown is under `priceItems[].taxDetail` and `roomTaxDetail`.
|
|
116
|
+
3. `/booking/createOrder`
|
|
117
|
+
- Submit the order with guest, contact, amount, and price item details. When the local order has been created and is ready to submit, call `/booking/availabilityCheck` again first if there is any delay or state change risk.
|
|
118
|
+
- Use `guestInfos[].guestType` for the guest type dictionary. Do not send the old nested `guestInfos[].nationality` field.
|
|
119
119
|
4. `/booking/payOrder`
|
|
120
120
|
- Notify payment after local customer payment succeeds, or after the platform has decided the order should be confirmed.
|
|
121
121
|
5. `/notify/orderStatus`
|
|
@@ -134,17 +134,17 @@ Prefer carrying both once they appear, because several aftercare APIs accept one
|
|
|
134
134
|
|
|
135
135
|
Use these calls after booking:
|
|
136
136
|
|
|
137
|
-
- `/order/cancelOrder`
|
|
138
|
-
- Cancel an order when policy permits, when the customer asks to cancel, or when the local unpaid timeout is reached, such as 30 minutes. Send `cancelReason` when there is a customer or platform reason to record. If cancellation returns success, update the local order and do not continue polling for another push.
|
|
137
|
+
- `/order/cancelOrder`
|
|
138
|
+
- Cancel an order when policy permits, when the customer asks to cancel, or when the local unpaid timeout is reached, such as 30 minutes. Send `cancelReason` when there is a customer or platform reason to record. If cancellation returns success, update the local order and do not continue polling for another push.
|
|
139
139
|
- `/notify/orderStatus`
|
|
140
140
|
- Required for order confirmation progress after `/booking/payOrder`; implement idempotency.
|
|
141
141
|
- `/order/checkInDetail`
|
|
142
142
|
- Read extended order or check-in related detail.
|
|
143
143
|
- `/order/checkoutRequest`
|
|
144
144
|
- Submit a checkout or refund-like aftercare request for an order.
|
|
145
|
-
- `/order/checkoutDetail`
|
|
146
|
-
- Query the checkout task by `taskOrderCode`.
|
|
147
|
-
- Use `paymentType` to distinguish prepaid and pay-at-hotel orders. Read `refundDetailList[]` for refund channel/time/amount/bill data and `checkoutDetailPriceItemList[].originalSalePrice` for original daily sale price.
|
|
145
|
+
- `/order/checkoutDetail`
|
|
146
|
+
- Query the checkout task by `taskOrderCode`.
|
|
147
|
+
- Use `paymentType` to distinguish prepaid and pay-at-hotel orders. Read `refundDetailList[]` for refund channel/time/amount/bill data and `checkoutDetailPriceItemList[].originalSalePrice` for original daily sale price.
|
|
148
148
|
|
|
149
149
|
## Finance
|
|
150
150
|
|
|
@@ -161,8 +161,8 @@ Use these calls for financial follow-up:
|
|
|
161
161
|
|
|
162
162
|
- Do not treat HTTP `200` as enough; inspect `code`.
|
|
163
163
|
- Use only our short interface paths in customer-facing docs and workflows.
|
|
164
|
-
- Preserve FCG order identifiers from earlier responses instead of recomputing them.
|
|
165
|
-
- In `/order/orderDetail`, use `roomGuestNumbers[]` for room-level adult and child counts. Use `originalAmount` for order original amount, and top-level `nationality` as country or region code.
|
|
166
|
-
- Keep local saleable hotel ID cache and hotel/room mappings current before pricing and booking.
|
|
164
|
+
- Preserve FCG order identifiers from earlier responses instead of recomputing them.
|
|
165
|
+
- In `/order/orderDetail`, use `roomGuestNumbers[]` for room-level adult and child counts. Use `originalAmount` for order original amount, and top-level `nationality` as country or region code.
|
|
166
|
+
- Keep local saleable hotel ID cache and hotel/room mappings current before pricing and booking.
|
|
167
167
|
- Avoid integration quota waste: skip `/booking/productDetails` for hotels not in the saleable hotel cache.
|
|
168
168
|
- Push/callback is primary for order confirmation; `/order/orderDetail` is only a compensation path and should not be frequent.
|
|
@@ -13,21 +13,21 @@ Integration mode shortcuts:
|
|
|
13
13
|
|
|
14
14
|
## Region Static Data
|
|
15
15
|
|
|
16
|
-
- `/region/countries`
|
|
17
|
-
- Method: `POST`
|
|
18
|
-
- Required body fields: none.
|
|
19
|
-
- Response `data` is an array of country objects directly; there is no `countries` wrapper.
|
|
20
|
-
- `/region/cities`
|
|
21
|
-
- Method: `POST`
|
|
22
|
-
- Common body fields: `countryCode`, `language`.
|
|
23
|
-
- Response `data` is an array of province/city-group objects directly; there is no `provinces` wrapper.
|
|
24
|
-
- `/region/popularCities`
|
|
25
|
-
- Method: `POST`
|
|
26
|
-
- Required body fields: none.
|
|
27
|
-
- Response `data` is an array directly; fields include `latBaidu`, `lngBaidu`, `timeZone`, and `areaType`.
|
|
28
|
-
- `/region/businesses`
|
|
29
|
-
- Method: `POST`
|
|
30
|
-
- Common body fields: `cityCode`, `language`.
|
|
16
|
+
- `/region/countries`
|
|
17
|
+
- Method: `POST`
|
|
18
|
+
- Required body fields: none.
|
|
19
|
+
- Response `data` is an array of country objects directly; there is no `countries` wrapper.
|
|
20
|
+
- `/region/cities`
|
|
21
|
+
- Method: `POST`
|
|
22
|
+
- Common body fields: `countryCode`, `language`.
|
|
23
|
+
- Response `data` is an array of province/city-group objects directly; there is no `provinces` wrapper.
|
|
24
|
+
- `/region/popularCities`
|
|
25
|
+
- Method: `POST`
|
|
26
|
+
- Required body fields: none.
|
|
27
|
+
- Response `data` is an array directly; fields include `latBaidu`, `lngBaidu`, `timeZone`, and `areaType`.
|
|
28
|
+
- `/region/businesses`
|
|
29
|
+
- Method: `POST`
|
|
30
|
+
- Common body fields: `cityCode`, `language`.
|
|
31
31
|
- `/region/districts`
|
|
32
32
|
- Method: `POST`
|
|
33
33
|
- Common body fields: `cityCode`, `language`.
|
|
@@ -37,24 +37,24 @@ Integration mode shortcuts:
|
|
|
37
37
|
|
|
38
38
|
## Hotel Info
|
|
39
39
|
|
|
40
|
-
- `/search/hotelIdList`
|
|
41
|
-
- Method: `POST`
|
|
42
|
-
- Common body fields: `cityCode`, `pageNo`, `pageSize`.
|
|
43
|
-
- Use `pageNo >= 1` and `pageSize >= 1`; examples default to `pageNo=1`, `pageSize=1000`.
|
|
44
|
-
- Response pagination uses `totalCount`, not `total`; pagination fields may be absent.
|
|
45
|
-
- Use for saleable hotel ID bootstrap and cache refresh.
|
|
46
|
-
- `/hotel/popularIdList`
|
|
47
|
-
- Method: `POST`
|
|
48
|
-
- Common body fields: `pageNo`, `pageSize`.
|
|
49
|
-
- `/hotel/detail`
|
|
50
|
-
- Method: `POST`
|
|
51
|
-
- Required body fields: `hotelIds`.
|
|
52
|
-
- Current response uses `facility`, `popularFacility`, `applicableRoomTypes`, `openingDate`, `groupId`, `groupName`, `brandId`, `brandName`, `latBaidu`, `lngBaidu`, `wiredBroadband`, `wirelessBroadband`, `comment.averageScore`, and `comment.source`.
|
|
53
|
-
- Meeting images are under `hotelMeetingInfos[].meetingImages`; do not expect derived size URLs in that node.
|
|
54
|
-
- Room bed info under both `roomBeds` and `livingRoomBeds` uses object `bedInfos[]` with `bedTypeCode`, `bedName`, `bedWidth`, and `bedNum`.
|
|
55
|
-
- `/hotel/increment`
|
|
56
|
-
- Method: `POST`
|
|
57
|
-
- Common body fields: `startTime`, `endTime`, `maxId`, `pageSize`.
|
|
40
|
+
- `/search/hotelIdList`
|
|
41
|
+
- Method: `POST`
|
|
42
|
+
- Common body fields: `cityCode`, `pageNo`, `pageSize`.
|
|
43
|
+
- Use `pageNo >= 1` and `pageSize >= 1`; examples default to `pageNo=1`, `pageSize=1000`.
|
|
44
|
+
- Response pagination uses `totalCount`, not `total`; pagination fields may be absent.
|
|
45
|
+
- Use for saleable hotel ID bootstrap and cache refresh.
|
|
46
|
+
- `/hotel/popularIdList`
|
|
47
|
+
- Method: `POST`
|
|
48
|
+
- Common body fields: `pageNo`, `pageSize`.
|
|
49
|
+
- `/hotel/detail`
|
|
50
|
+
- Method: `POST`
|
|
51
|
+
- Required body fields: `hotelIds`.
|
|
52
|
+
- Current response uses `facility`, `popularFacility`, `applicableRoomTypes`, `openingDate`, `groupId`, `groupName`, `brandId`, `brandName`, `latBaidu`, `lngBaidu`, `wiredBroadband`, `wirelessBroadband`, `comment.averageScore`, and `comment.source`.
|
|
53
|
+
- Meeting images are under `hotelMeetingInfos[].meetingImages`; do not expect derived size URLs in that node.
|
|
54
|
+
- Room bed info under both `roomBeds` and `livingRoomBeds` uses object `bedInfos[]` with `bedTypeCode`, `bedName`, `bedWidth`, and `bedNum`.
|
|
55
|
+
- `/hotel/increment`
|
|
56
|
+
- Method: `POST`
|
|
57
|
+
- Common body fields: `startTime`, `endTime`, `maxId`, `pageSize`.
|
|
58
58
|
- `/hotel/lowestPrice`
|
|
59
59
|
- Method: `POST`
|
|
60
60
|
- Common body fields: `hotelIds`, `checkInDate`, `checkOutDate`, `checkInType`.
|
|
@@ -67,48 +67,48 @@ Integration mode shortcuts:
|
|
|
67
67
|
|
|
68
68
|
## Search And Booking
|
|
69
69
|
|
|
70
|
-
- `/search/destination`
|
|
71
|
-
- Method: `POST`
|
|
72
|
-
- Common body fields: `keyWord`, `cityCode`, `destinationType`, `source`.
|
|
73
|
-
- Response `data` is an array directly. Destination item fields are flat and include `destinationId`, `destinationType`, `source`, name/code fields, `hotelId`, `latGoogle`, `lngGoogle`, `latBaidu`, and `lngBaidu`.
|
|
74
|
-
- `/search/hotelFilters`
|
|
75
|
-
- Method: `POST`
|
|
76
|
-
- Common body fields: `destinationId`, `language`, `lngGoogle`, `latGoogle`, `distance`.
|
|
77
|
-
- `/search/hotelList`
|
|
78
|
-
- Method: `POST`
|
|
79
|
-
- Common body fields: `destinationId`, `lngGoogle`, `latGoogle`, `checkInDate`, `checkOutDate`, filters, `distance`, `currentPage`, `pageSize`.
|
|
80
|
-
- Response list items use `latBaidu` and `lngBaidu`; items may include `groupName` and `brandName`.
|
|
81
|
-
- `/booking/productDetails`
|
|
82
|
-
- Method: `POST`
|
|
83
|
-
- Required body fields: `hotelId`, `checkInDate`, `checkOutDate`, `roomNum`, `numberOfAdults`.
|
|
84
|
-
- Product response removed `reminder`. `taxAndFeeDetails` and `feeItems` are objects, not arrays. `priceItems[].taxDetail` includes numeric `roomPrice`, `taxFee`, `salesTax`, and `otherTax`.
|
|
85
|
-
- `/booking/availabilityCheck`
|
|
86
|
-
- Method: `POST`
|
|
87
|
-
- Required body fields: `hotelId`, `roomId`, `ratePlanId`, `checkInDate`, `checkOutDate`, `roomNum`, `supplyCode`.
|
|
88
|
-
- Response-level `breakfastNum` and `breakfastType` are outside `priceItems`. `roomTaxDetail` is an object. `priceItems[].taxDetail` contains room and tax breakdown. `roomStatus` is not exposed.
|
|
89
|
-
- `/booking/createOrder`
|
|
90
|
-
- Method: `POST`
|
|
91
|
-
- Required body fields: `hotelId`, `roomId`, `ratePlanId`, `checkInDate`, `checkOutDate`, `roomNum`, `supplyCode`, `totalAmount`, `coOrderCode`, `priceItems`, `guestInfos`, `linkMan`, `linkPhone`, `arriveTime`, `latestArriveTime`.
|
|
92
|
-
- Use `guestInfos[].guestType` for guest type; do not send `guestInfos[].nationality`.
|
|
93
|
-
- `/booking/payOrder`
|
|
94
|
-
- Method: `POST`
|
|
95
|
-
- Common body fields: `coOrderCode`, `fcOrderCode`.
|
|
70
|
+
- `/search/destination`
|
|
71
|
+
- Method: `POST`
|
|
72
|
+
- Common body fields: `keyWord`, `cityCode`, `destinationType`, `source`.
|
|
73
|
+
- Response `data` is an array directly. Destination item fields are flat and include `destinationId`, `destinationType`, `source`, name/code fields, `hotelId`, `latGoogle`, `lngGoogle`, `latBaidu`, and `lngBaidu`.
|
|
74
|
+
- `/search/hotelFilters`
|
|
75
|
+
- Method: `POST`
|
|
76
|
+
- Common body fields: `destinationId`, `language`, `lngGoogle`, `latGoogle`, `distance`.
|
|
77
|
+
- `/search/hotelList`
|
|
78
|
+
- Method: `POST`
|
|
79
|
+
- Common body fields: `destinationId`, `lngGoogle`, `latGoogle`, `checkInDate`, `checkOutDate`, filters, `distance`, `currentPage`, `pageSize`.
|
|
80
|
+
- Response list items use `latBaidu` and `lngBaidu`; items may include `groupName` and `brandName`.
|
|
81
|
+
- `/booking/productDetails`
|
|
82
|
+
- Method: `POST`
|
|
83
|
+
- Required body fields: `hotelId`, `checkInDate`, `checkOutDate`, `roomNum`, `numberOfAdults`.
|
|
84
|
+
- Product response removed `reminder`. `taxAndFeeDetails` and `feeItems` are objects, not arrays. `priceItems[].taxDetail` includes numeric `roomPrice`, `taxFee`, `salesTax`, and `otherTax`.
|
|
85
|
+
- `/booking/availabilityCheck`
|
|
86
|
+
- Method: `POST`
|
|
87
|
+
- Required body fields: `hotelId`, `roomId`, `ratePlanId`, `checkInDate`, `checkOutDate`, `roomNum`, `supplyCode`.
|
|
88
|
+
- Response-level `breakfastNum` and `breakfastType` are outside `priceItems`. `roomTaxDetail` is an object. `priceItems[].taxDetail` contains room and tax breakdown. `roomStatus` is not exposed.
|
|
89
|
+
- `/booking/createOrder`
|
|
90
|
+
- Method: `POST`
|
|
91
|
+
- Required body fields: `hotelId`, `roomId`, `ratePlanId`, `checkInDate`, `checkOutDate`, `roomNum`, `supplyCode`, `totalAmount`, `coOrderCode`, `priceItems`, `guestInfos`, `linkMan`, `linkPhone`, `arriveTime`, `latestArriveTime`.
|
|
92
|
+
- Use `guestInfos[].guestType` for guest type; do not send `guestInfos[].nationality`.
|
|
93
|
+
- `/booking/payOrder`
|
|
94
|
+
- Method: `POST`
|
|
95
|
+
- Common body fields: `coOrderCode`, `fcOrderCode`.
|
|
96
96
|
- `/search/creditBalance`
|
|
97
97
|
- Method: `POST`
|
|
98
98
|
- Required body fields: none; send `{}` or omit body according to the SDK/runtime caller.
|
|
99
99
|
|
|
100
100
|
## Order Info
|
|
101
101
|
|
|
102
|
-
- `/order/orderDetail`
|
|
103
|
-
- Method: `POST`
|
|
104
|
-
- Common body fields: `coOrderCode`, `fcOrderCode`.
|
|
105
|
-
- Response uses `roomGuestNumbers[]` for room-level adult/child counts. It may include `originalAmount`, top-level `nationality`, and `guestInfos[].guestType`.
|
|
106
|
-
- `/order/cancelOrder`
|
|
107
|
-
- Method: `POST`
|
|
108
|
-
- Common body fields: `coOrderCode`, `fcOrderCode`, `cancelReason`.
|
|
109
|
-
- `/order/checkInDetail`
|
|
110
|
-
- Method: `POST`
|
|
111
|
-
- Common body fields: `coOrderCode`, `fcOrderCode`.
|
|
102
|
+
- `/order/orderDetail`
|
|
103
|
+
- Method: `POST`
|
|
104
|
+
- Common body fields: `coOrderCode`, `fcOrderCode`.
|
|
105
|
+
- Response uses `roomGuestNumbers[]` for room-level adult/child counts. It may include `originalAmount`, top-level `nationality`, and `guestInfos[].guestType`.
|
|
106
|
+
- `/order/cancelOrder`
|
|
107
|
+
- Method: `POST`
|
|
108
|
+
- Common body fields: `coOrderCode`, `fcOrderCode`, `cancelReason`.
|
|
109
|
+
- `/order/checkInDetail`
|
|
110
|
+
- Method: `POST`
|
|
111
|
+
- Common body fields: `coOrderCode`, `fcOrderCode`.
|
|
112
112
|
- `/order/invoiceRequest`
|
|
113
113
|
- Method: `POST`
|
|
114
114
|
- Business fields to focus on: `orderCode`, `invoiceTypeInteger`, `invoiceHeader`, `amount`, `applyId`, `invoiceTitleType`, `getMethod`.
|
|
@@ -118,10 +118,10 @@ Integration mode shortcuts:
|
|
|
118
118
|
- `/order/checkoutRequest`
|
|
119
119
|
- Method: `POST`
|
|
120
120
|
- Required body fields: `fcOrderCode`, `supplierRefundNumber`, `checkoutReason`, `refundType`, `checkoutRooms`.
|
|
121
|
-
- `/order/checkoutDetail`
|
|
122
|
-
- Method: `POST`
|
|
123
|
-
- Common body fields: `taskOrderCode`.
|
|
124
|
-
- Response includes hotel/product context, `paymentType`, `refundDetailList[]`, and `checkoutDetailPriceItemList[].originalSalePrice`.
|
|
121
|
+
- `/order/checkoutDetail`
|
|
122
|
+
- Method: `POST`
|
|
123
|
+
- Common body fields: `taskOrderCode`.
|
|
124
|
+
- Response includes hotel/product context, `paymentType`, `refundDetailList[]`, and `checkoutDetailPriceItemList[].originalSalePrice`.
|
|
125
125
|
|
|
126
126
|
## Callback Capabilities
|
|
127
127
|
|
|
@@ -140,9 +140,9 @@ Integration mode shortcuts:
|
|
|
140
140
|
|
|
141
141
|
## Global Notes
|
|
142
142
|
|
|
143
|
-
- Current Glink swagger route count may include outbound request APIs and callback APIs; verify against `docs/swagger/glink-api.json`.
|
|
144
|
-
- Most Glink routes accept plain business JSON bodies with no wrapper objects.
|
|
145
|
-
- For response-shape changes and enum-like values, read `field-and-enum-notes.md` before generating DTOs or examples.
|
|
146
|
-
- Platform error responses can return `401`, `403`, `404`, `500`, `502`, or `504`.
|
|
143
|
+
- Current Glink swagger route count may include outbound request APIs and callback APIs; verify against `docs/swagger/glink-api.json`.
|
|
144
|
+
- Most Glink routes accept plain business JSON bodies with no wrapper objects.
|
|
145
|
+
- For response-shape changes and enum-like values, read `field-and-enum-notes.md` before generating DTOs or examples.
|
|
146
|
+
- Platform error responses can return `401`, `403`, `404`, `500`, `502`, or `504`.
|
|
147
147
|
- Common auth-related `401` codes are `APP_KEY_INVALID`, `SIGN_ERROR`, `TIMESTAMP_EXPIRED`, and `NONCE_REPLAY`.
|
|
148
148
|
- Common `403` cause is `PRODUCT_FORBIDDEN`.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tmc-api
|
|
3
|
+
description: Work with the TMC white-label OpenAPI exposed through the Open Platform runtime gateway. Use when Codex needs to read, verify, explain, test, document, or implement against `docs/swagger/tmc-api.json`; choose exact TMC endpoints; include complete request/response fields and types; generate customer-facing TMC onboarding, organization, employee, traveler, approval, travel policy, flight, hotel, payment, attachment, certificate, webhook, and aftersale workflows; or debug Open Platform signing, `token`, sandbox, and production TMC calls.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TMC API
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
Use this skill when the task is about TMC white-label OpenAPI integration, customer-facing workflow explanation, interface field lookup, signed requests, or implementation against the Open Platform TMC gateway.
|
|
11
|
+
|
|
12
|
+
Start from the smallest reference that answers the request:
|
|
13
|
+
|
|
14
|
+
- Read `references/endpoint-index.md` for the complete 94-operation endpoint map.
|
|
15
|
+
- Read `references/endpoint-details.md` when the answer must include exact request parameters, request body fields, response fields, nested types, examples, or webhook payload fields.
|
|
16
|
+
- Read `references/api-workflows.md` when the user asks for customer process, interaction flow, or test-case-aligned business coverage. It maps the extracted 224 Listify test cases to concrete interfaces.
|
|
17
|
+
- Read `references/auth-and-calling.md` for Open Platform signature rules, runtime path prefixing, token handling, and call validation.
|
|
18
|
+
- Use `scripts/tmc_signed_request.py` to generate headers, inspect the canonical signing string, or send a signed local/sandbox request.
|
|
19
|
+
|
|
20
|
+
## Source Of Truth
|
|
21
|
+
|
|
22
|
+
- Current English swagger: `open-platform-go/docs/swagger/tmc-api.en-US.json`.
|
|
23
|
+
- Simplified Chinese swagger: `open-platform-go/docs/swagger/tmc-api.json`; use it only when the user specifically needs Chinese wording.
|
|
24
|
+
- Customer-facing short paths omit `/openapi/v1/tmc`, for example `/flight/search`.
|
|
25
|
+
- Signing and actual gateway calls must use the full runtime path, for example `/openapi/v1/tmc/flight/search`.
|
|
26
|
+
- The Listify test-case page is Chinese flow evidence, not an interface specification. Preserve source case IDs for traceability, but explain customer workflows in English unless the user asks for Chinese.
|
|
27
|
+
|
|
28
|
+
## Working Rules
|
|
29
|
+
|
|
30
|
+
Follow this workflow:
|
|
31
|
+
|
|
32
|
+
1. Confirm whether the user needs customer documentation, exact field tables, code changes, signed request debugging, or live/local API calls.
|
|
33
|
+
2. Choose the flow area first: identity/org/employee/traveler, approval, travel policy, flight booking, flight aftersale, hotel booking, hotel aftersale, payment, attachments, certificates, or webhook callbacks.
|
|
34
|
+
3. Use `references/api-workflows.md` to connect the business scenario or test case to concrete endpoint paths.
|
|
35
|
+
4. Use `references/endpoint-details.md` for all payload details; do not invent request or response fields.
|
|
36
|
+
5. For signed calls, use `/openapi/v1/tmc` in the canonical path and include `X-OP-App-Key`, `X-OP-Timestamp`, `X-OP-Nonce`, and `X-OP-Sign`.
|
|
37
|
+
6. Call `/auth/token` with `externalUserId` first, then pass the returned TMC `token` header on business APIs.
|
|
38
|
+
7. Evaluate both HTTP status and response envelope `code`; non-zero business `code` is a business failure even when HTTP is 200.
|
|
39
|
+
|
|
40
|
+
## Common Flow Skeletons
|
|
41
|
+
|
|
42
|
+
- Identity and enterprise context: `/auth/token` -> `/departments` -> `/employees` or `/employees/{userId}`.
|
|
43
|
+
- Organization and staff setup: `/departments` -> `/email-domains` -> `/employees` -> `/employees/{userId}` -> certificate APIs when needed.
|
|
44
|
+
- Traveler setup: `/guests/add` -> `/guests` -> `/guests/{id}` -> guest certificate APIs.
|
|
45
|
+
- Approval setup: `/approval-policies` -> `/approval-policies/page` -> `/approval-policies/{policyId}` -> `/approvals/page` -> `/approvals/{approvalNo}` -> `/approvals/audit` or `/approvals/resubmit`.
|
|
46
|
+
- Travel policy setup: hotel and flight policy CRUD/page/enable APIs -> `/travel-policies/users/{employeeId}`.
|
|
47
|
+
- Flight booking: dictionary APIs -> `/booking-users/list` -> `/flight/search` -> `/flight/cabin` -> `/flight/verify` -> `/flight/order/init` -> `/flight/order/policy-check` -> `/flight/order` -> `/payments/payOrder` -> `/flight/orders/{orderCode}`.
|
|
48
|
+
- Flight aftersale: `/flight/aftersale/capability` -> refund or change remaining-query APIs -> apply/detail/confirm-or-cancel APIs.
|
|
49
|
+
- Hotel booking: `/hotel/locations` -> `/hotel/search/filters` -> `/hotel/search` -> `/hotel/{hotelId}` -> `/hotel/products/search` -> `/hotel/check-booking` -> `/hotel/order/policy-check` -> `/hotel/order` -> `/payments/payOrder` -> `/hotel/orders/{orderCode}`.
|
|
50
|
+
- Hotel early checkout: `/hotel/early-checkout/can-apply` -> `/hotel/early-checkout/apply` -> `/hotel/early-checkout/detail`.
|
|
51
|
+
- Attachments: `/attachments/upload` and `/attachments/download`.
|
|
52
|
+
- Webhooks: read the webhook section in `references/endpoint-details.md`; treat callbacks as customer interaction surface even though they are not part of the 94 request operations.
|
|
53
|
+
|
|
54
|
+
## Output Expectations
|
|
55
|
+
|
|
56
|
+
When answering with this skill:
|
|
57
|
+
|
|
58
|
+
- Use concrete method + path pairs, not only abstract process names.
|
|
59
|
+
- Include field names, types, required flags, and nested structures from `endpoint-details.md` when the user asks for parameters.
|
|
60
|
+
- Mention whether a path is a customer-facing short path or a signed runtime path when auth/signing is relevant.
|
|
61
|
+
- Keep test-case-derived process descriptions tied to exact interfaces.
|
|
62
|
+
- State the source used when swagger, local code, and extracted test cases disagree.
|
|
63
|
+
- Never expose or invent credentials, app secrets, tokens, or tenant data.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "TMC API Integration"
|
|
3
|
+
short_description: "TMC white-label OpenAPI auth, fields, workflows, and debugging"
|
|
4
|
+
default_prompt: "Use $tmc-api to explain or implement TMC OpenAPI authentication, endpoint selection, request/response fields, and customer workflows."
|