@mongoui/skills 0.1.4 → 0.1.5
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/dist/commands/install.js +48 -1
- package/dist/products/index.js +4 -2
- package/package.json +1 -1
- package/skills/flink-flight-api/flink-openapi-integration/SKILL.md +58 -0
- package/skills/flink-flight-api/flink-openapi-integration/agents/openai.yaml +4 -0
- package/skills/flink-flight-api/flink-openapi-integration/references/api-workflows.md +104 -0
- package/skills/flink-flight-api/flink-openapi-integration/references/auth-and-credentials.md +136 -0
- package/skills/flink-flight-api/flink-openapi-integration/references/endpoint-index.md +92 -0
- package/skills/flink-flight-api/flink-openapi-integration/scripts/flink_signed_request.py +188 -0
- package/skills/glink-hotel-api/glink-openapi-integration/SKILL.md +56 -0
- package/skills/glink-hotel-api/glink-openapi-integration/agents/openai.yaml +4 -0
- package/skills/glink-hotel-api/glink-openapi-integration/references/api-workflows.md +84 -0
- package/skills/glink-hotel-api/glink-openapi-integration/references/auth-and-credentials.md +157 -0
- package/skills/glink-hotel-api/glink-openapi-integration/references/endpoint-index.md +126 -0
- package/skills/glink-hotel-api/glink-openapi-integration/scripts/glink_signed_request.py +188 -0
- package/skills/flink-flight-api/SKILL.md +0 -8
- package/skills/glink-hotel-api/SKILL.md +0 -175
package/dist/commands/install.js
CHANGED
|
@@ -38,11 +38,33 @@ export async function runInstall(productName, options) {
|
|
|
38
38
|
}
|
|
39
39
|
const installTarget = resolveInstallTarget(options.tool, options.targetDir);
|
|
40
40
|
const sourceSkillFile = path.join(packageRoot, product.skillFile);
|
|
41
|
+
const sourceSkillDir = product.skillDir ? path.join(packageRoot, product.skillDir) : undefined;
|
|
41
42
|
const targetSkillFile = resolveTargetSkillFile(product.name, installTarget);
|
|
43
|
+
const targetSkillDir = resolveTargetSkillDir(sourceSkillDir, installTarget);
|
|
44
|
+
await fs.mkdir(installTarget.targetDir, { recursive: true });
|
|
45
|
+
if (sourceSkillDir && shouldInstallAsDirectory(installTarget.tool)) {
|
|
46
|
+
await fs.access(sourceSkillDir);
|
|
47
|
+
await fs.rm(targetSkillDir, { recursive: true, force: true });
|
|
48
|
+
await fs.rm(targetSkillFile, { force: true });
|
|
49
|
+
await copyDirectory(sourceSkillDir, targetSkillDir);
|
|
50
|
+
console.log("Installed skill:");
|
|
51
|
+
console.log("- command: install");
|
|
52
|
+
console.log(`- product: ${product.name}`);
|
|
53
|
+
console.log(`- display name: ${product.displayName}`);
|
|
54
|
+
console.log(`- tool: ${installTarget.tool}`);
|
|
55
|
+
console.log(`- source skill dir: ${sourceSkillDir}`);
|
|
56
|
+
console.log(`- source skill file: ${sourceSkillFile}`);
|
|
57
|
+
console.log(`- target dir: ${installTarget.targetDir}`);
|
|
58
|
+
console.log(`- target source: ${installTarget.source}`);
|
|
59
|
+
console.log(`- target skill dir: ${targetSkillDir}`);
|
|
60
|
+
console.log(`- target skill file: ${path.join(targetSkillDir, "SKILL.md")}`);
|
|
61
|
+
console.log("- target format: directory");
|
|
62
|
+
console.log("- status: installed");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
42
65
|
await fs.access(sourceSkillFile);
|
|
43
66
|
const sourceSkillContent = await fs.readFile(sourceSkillFile, "utf8");
|
|
44
67
|
const targetSkillContent = renderInstalledContent(installTarget.tool, product.name, product.displayName, sourceSkillContent);
|
|
45
|
-
await fs.mkdir(installTarget.targetDir, { recursive: true });
|
|
46
68
|
await fs.writeFile(targetSkillFile, targetSkillContent, "utf8");
|
|
47
69
|
console.log("Installed skill:");
|
|
48
70
|
console.log("- command: install");
|
|
@@ -62,7 +84,9 @@ export async function runUninstall(productName, options) {
|
|
|
62
84
|
throw new Error(`Missing required option: "--tool <${supportedToolsText()}>".`);
|
|
63
85
|
}
|
|
64
86
|
const installTarget = resolveInstallTarget(options.tool, options.targetDir);
|
|
87
|
+
const targetSkillDir = resolveTargetSkillDir(undefined, installTarget, product);
|
|
65
88
|
const targetSkillFile = resolveTargetSkillFile(product.name, installTarget);
|
|
89
|
+
await fs.rm(targetSkillDir, { recursive: true, force: true });
|
|
66
90
|
await fs.rm(targetSkillFile, { force: true });
|
|
67
91
|
console.log("Uninstalled skill:");
|
|
68
92
|
console.log("- command: uninstall");
|
|
@@ -71,6 +95,7 @@ export async function runUninstall(productName, options) {
|
|
|
71
95
|
console.log(`- tool: ${installTarget.tool}`);
|
|
72
96
|
console.log(`- target dir: ${installTarget.targetDir}`);
|
|
73
97
|
console.log(`- target source: ${installTarget.source}`);
|
|
98
|
+
console.log(`- target skill dir: ${targetSkillDir}`);
|
|
74
99
|
console.log(`- target skill file: ${targetSkillFile}`);
|
|
75
100
|
console.log(`- target format: ${installTarget.fileExtension}`);
|
|
76
101
|
console.log("- status: removed");
|
|
@@ -88,3 +113,25 @@ function requireProduct(productName) {
|
|
|
88
113
|
function resolveTargetSkillFile(productName, installTarget) {
|
|
89
114
|
return path.join(installTarget.targetDir, installTarget.fileName ?? `${productName}.${installTarget.fileExtension}`);
|
|
90
115
|
}
|
|
116
|
+
function resolveTargetSkillDir(sourceSkillDir, installTarget, product) {
|
|
117
|
+
const dirName = sourceSkillDir
|
|
118
|
+
? path.basename(sourceSkillDir)
|
|
119
|
+
: `${product?.name ?? "skill"}`;
|
|
120
|
+
return path.join(installTarget.targetDir, dirName);
|
|
121
|
+
}
|
|
122
|
+
function shouldInstallAsDirectory(tool) {
|
|
123
|
+
return tool === "codex" || tool === "kiro";
|
|
124
|
+
}
|
|
125
|
+
async function copyDirectory(sourceDir, targetDir) {
|
|
126
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
127
|
+
const entries = await fs.readdir(sourceDir, { withFileTypes: true });
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
130
|
+
const targetPath = path.join(targetDir, entry.name);
|
|
131
|
+
if (entry.isDirectory()) {
|
|
132
|
+
await copyDirectory(sourcePath, targetPath);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
await fs.copyFile(sourcePath, targetPath);
|
|
136
|
+
}
|
|
137
|
+
}
|
package/dist/products/index.js
CHANGED
|
@@ -2,12 +2,14 @@ const PRODUCTS = {
|
|
|
2
2
|
"glink-hotel-api": {
|
|
3
3
|
name: "glink-hotel-api",
|
|
4
4
|
displayName: "Glink Hotel API",
|
|
5
|
-
skillFile: "skills/glink-hotel-api/SKILL.md",
|
|
5
|
+
skillFile: "skills/glink-hotel-api/glink-openapi-integration/SKILL.md",
|
|
6
|
+
skillDir: "skills/glink-hotel-api/glink-openapi-integration",
|
|
6
7
|
},
|
|
7
8
|
"flink-flight-api": {
|
|
8
9
|
name: "flink-flight-api",
|
|
9
10
|
displayName: "Flink Flight API",
|
|
10
|
-
skillFile: "skills/flink-flight-api/SKILL.md",
|
|
11
|
+
skillFile: "skills/flink-flight-api/flink-openapi-integration/SKILL.md",
|
|
12
|
+
skillDir: "skills/flink-flight-api/flink-openapi-integration",
|
|
11
13
|
},
|
|
12
14
|
"tmc-whitelabel": {
|
|
13
15
|
name: "tmc-whitelabel",
|
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flink-openapi-integration
|
|
3
|
+
description: Integrate with the Flink flight OpenAPI exposed through the platform runtime gateway. Use when Codex needs to read or implement against `docs/swagger/flink-api.json`, choose the correct Flink ticket endpoint, generate `X-OP-*` signatures, explain sandbox or production credential acquisition and reset, or drive search, booking, change, refund, airport, airline, nationality, and fields workflows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Flink OpenAPI Integration
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
Use this skill when the task is "call Flink through the open platform" rather than "call Flink supplier APIs directly".
|
|
11
|
+
|
|
12
|
+
Start with the smallest reference that answers the request:
|
|
13
|
+
|
|
14
|
+
- Read `references/auth-and-credentials.md` for signing, headers, key acquisition, reset, or auth troubleshooting.
|
|
15
|
+
- Read `references/api-workflows.md` for business sequencing such as search to booking, change, or refund.
|
|
16
|
+
- Read `references/endpoint-index.md` for exact method, path, required fields, and follow-up identifiers.
|
|
17
|
+
- Use `scripts/flink_signed_request.py` to generate headers, inspect the canonical string, or send a signed request.
|
|
18
|
+
|
|
19
|
+
## Working Rules
|
|
20
|
+
|
|
21
|
+
Follow this workflow:
|
|
22
|
+
|
|
23
|
+
1. Confirm the environment: `sandbox` and `production` credentials are separate.
|
|
24
|
+
2. Confirm the public path under `/openapi/v1/flink/*` and the required `lang` path parameter when present.
|
|
25
|
+
3. Build the minimum valid request body from `references/endpoint-index.md`.
|
|
26
|
+
4. Sign the exact request path, sorted query string, and raw body bytes with the platform secret.
|
|
27
|
+
5. Evaluate both HTTP status and response envelope `code`.
|
|
28
|
+
|
|
29
|
+
Do not violate these rules:
|
|
30
|
+
|
|
31
|
+
- Always send `X-OP-App-Key`, `X-OP-Timestamp`, `X-OP-Nonce`, and `X-OP-Sign`.
|
|
32
|
+
- Never send supplier-side `appid`, `timestamp`, or `sign`; the platform injects them downstream.
|
|
33
|
+
- Treat `code=SUCCESS` as success. Treat `code=SUPPLIER_BIZ_ERROR` as a business failure even if HTTP status is `200`.
|
|
34
|
+
- Keep timestamp skew within `+-5` minutes.
|
|
35
|
+
- Reuse of the same nonce under the same app key can trigger `NONCE_REPLAY`.
|
|
36
|
+
- Preserve bridge identifiers across steps:
|
|
37
|
+
- `priceKey` bridges search or cabin to verify and order creation.
|
|
38
|
+
- `orderNo` bridges order detail, cancel, change, refund, and fields lookup.
|
|
39
|
+
- `changeOrderNo` and `refundOrderNo` drive their detail or cancel or confirm calls.
|
|
40
|
+
- For `GET /openapi/v1/flink/fields`, send at least one of `priceKey` or `orderNo`.
|
|
41
|
+
|
|
42
|
+
## Typical Requests
|
|
43
|
+
|
|
44
|
+
Use these patterns by default:
|
|
45
|
+
|
|
46
|
+
- Search and booking: `flight.search` -> `flight.cabin` if needed -> `flight.verify` -> `flight.order.create` -> `flight.order.pay` -> `flight.order.detail`
|
|
47
|
+
- Change: `flight.order.detail` -> `flight.change.search` -> `flight.change.apply` -> `flight.order.pay` with `type=1` if payment is required -> `flight.change.detail`
|
|
48
|
+
- Refund: `flight.order.detail` -> `flight.refund.apply` -> `flight.refund.detail` -> `flight.refund.confirm`
|
|
49
|
+
- Base data: `airports.list`, `airlines.list`, `airports.search`, `nationality.list`, `fields`
|
|
50
|
+
|
|
51
|
+
## Output Expectations
|
|
52
|
+
|
|
53
|
+
When answering or coding with this skill:
|
|
54
|
+
|
|
55
|
+
- Prefer concrete request examples over abstract summaries.
|
|
56
|
+
- State which environment the credential belongs to.
|
|
57
|
+
- State which identifier from the previous step is needed next.
|
|
58
|
+
- Call out auth failures with the likely root cause and the exact header or field to inspect.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Flink API Workflows
|
|
2
|
+
|
|
3
|
+
## Search And Booking
|
|
4
|
+
|
|
5
|
+
Use this sequence for a normal booking flow:
|
|
6
|
+
|
|
7
|
+
1. `flink.flight.search`
|
|
8
|
+
- Search journeys and offer combinations.
|
|
9
|
+
- Save returned `priceKey` values for the next step.
|
|
10
|
+
2. `flink.flight.cabin`
|
|
11
|
+
- Use when a selected offer needs more fare or cabin quotes.
|
|
12
|
+
- Input is `priceKey`.
|
|
13
|
+
3. `flink.flight.verify`
|
|
14
|
+
- Validate the selected offer before order creation.
|
|
15
|
+
- Input is `priceKey`.
|
|
16
|
+
4. `flink.flight.order.create`
|
|
17
|
+
- Create the pre-booking order with contact and passenger data.
|
|
18
|
+
- Input still depends on `priceKey`.
|
|
19
|
+
5. `flink.flight.order.pay`
|
|
20
|
+
- Pay the standard order with `type=0`.
|
|
21
|
+
6. `flink.flight.order.detail`
|
|
22
|
+
- Read status, ticketing progress, and later change or refund context.
|
|
23
|
+
7. `flink.flight.order.cancel`
|
|
24
|
+
- Use only for cancellable standard orders.
|
|
25
|
+
|
|
26
|
+
Keep these state tokens:
|
|
27
|
+
|
|
28
|
+
- `priceKey`: search or cabin -> verify or order creation
|
|
29
|
+
- `orderNo`: order creation or detail -> pay, cancel, change, refund, fields
|
|
30
|
+
|
|
31
|
+
## Change Flow
|
|
32
|
+
|
|
33
|
+
Use this sequence for voluntary or involuntary changes:
|
|
34
|
+
|
|
35
|
+
1. `flink.flight.order.detail`
|
|
36
|
+
- Confirm order status and segment context.
|
|
37
|
+
2. `flink.flight.change.search`
|
|
38
|
+
- Search eligible changed flights for an existing order and passenger or segment scope.
|
|
39
|
+
3. `flink.flight.change.apply`
|
|
40
|
+
- Submit the actual change request with `priceKey`, passenger scope, segment scope, reason, and contact info.
|
|
41
|
+
4. `flink.flight.order.pay`
|
|
42
|
+
- If the change order requires payment, pay with `type=1`.
|
|
43
|
+
5. `flink.flight.change.detail`
|
|
44
|
+
- Track the change request by `changeOrderNo`.
|
|
45
|
+
6. `flink.flight.change.cancel`
|
|
46
|
+
- Cancel a pending change request by `changeOrderNo`.
|
|
47
|
+
|
|
48
|
+
Bridge identifiers:
|
|
49
|
+
|
|
50
|
+
- `orderNo` drives change search and apply.
|
|
51
|
+
- `priceKey` from change search is used in change apply.
|
|
52
|
+
- `changeOrderNo` drives detail and cancel.
|
|
53
|
+
|
|
54
|
+
## Refund Flow
|
|
55
|
+
|
|
56
|
+
Use this sequence for refunds:
|
|
57
|
+
|
|
58
|
+
1. `flink.flight.order.detail`
|
|
59
|
+
- Confirm the refundable order, passenger, and segment scope.
|
|
60
|
+
2. `flink.flight.refund.apply`
|
|
61
|
+
- Submit the refund request with passenger scope, segment scope, contact data, and reason.
|
|
62
|
+
3. `flink.flight.refund.detail`
|
|
63
|
+
- Track the refund request by `refundOrderNo`.
|
|
64
|
+
4. `flink.flight.refund.confirm`
|
|
65
|
+
- Confirm or cancel the refund request.
|
|
66
|
+
|
|
67
|
+
Bridge identifiers:
|
|
68
|
+
|
|
69
|
+
- `orderNo` drives refund apply.
|
|
70
|
+
- `refundOrderNo` drives detail and confirm.
|
|
71
|
+
|
|
72
|
+
## Base Data And Helper Calls
|
|
73
|
+
|
|
74
|
+
Use these APIs outside the booking lifecycle:
|
|
75
|
+
|
|
76
|
+
- `flink.airports.list`
|
|
77
|
+
- Paged airport list with optional keyword filtering.
|
|
78
|
+
- `flink.airlines.list`
|
|
79
|
+
- Paged airline list with optional keyword and code filtering.
|
|
80
|
+
- `flink.airports.search`
|
|
81
|
+
- Lightweight airport search by keyword.
|
|
82
|
+
- `flink.nationality.list`
|
|
83
|
+
- Nationality reference data.
|
|
84
|
+
- `flink.fields`
|
|
85
|
+
- Field translations and baggage or travel notice helpers.
|
|
86
|
+
- Provide either `priceKey` or `orderNo`.
|
|
87
|
+
|
|
88
|
+
## Language Parameter
|
|
89
|
+
|
|
90
|
+
All Flink routes except `flink.fields` require `{lang}` in the path.
|
|
91
|
+
|
|
92
|
+
Common values:
|
|
93
|
+
|
|
94
|
+
- `en`
|
|
95
|
+
- `zh_CN`
|
|
96
|
+
- `zh_TW`
|
|
97
|
+
|
|
98
|
+
Use the same `lang` across related calls unless there is a clear reason to switch.
|
|
99
|
+
|
|
100
|
+
## Business Handling Rules
|
|
101
|
+
|
|
102
|
+
- Do not treat HTTP `200` as enough; inspect `code`.
|
|
103
|
+
- Do not rebuild supplier headers; the runtime gateway handles supplier authentication.
|
|
104
|
+
- Preserve the original upstream identifiers from earlier responses instead of recomputing them.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Flink Auth And Credentials
|
|
2
|
+
|
|
3
|
+
## Required Headers
|
|
4
|
+
|
|
5
|
+
Send these headers on every Flink open-platform request:
|
|
6
|
+
|
|
7
|
+
- `X-OP-App-Key`
|
|
8
|
+
- `X-OP-Timestamp`
|
|
9
|
+
- `X-OP-Nonce`
|
|
10
|
+
- `X-OP-Sign`
|
|
11
|
+
|
|
12
|
+
Optional headers that can help tracing or idempotency:
|
|
13
|
+
|
|
14
|
+
- `X-OP-Client-Request-Id`
|
|
15
|
+
- `X-Trace-Id`
|
|
16
|
+
- `X-Idempotency-Key`
|
|
17
|
+
|
|
18
|
+
`X-OP-App-Key` is the issued `open_app_id`.
|
|
19
|
+
|
|
20
|
+
## Signature Algorithm
|
|
21
|
+
|
|
22
|
+
Build the canonical string in this exact order, separated by newline characters:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
METHOD
|
|
26
|
+
PATH
|
|
27
|
+
CANONICAL_QUERY
|
|
28
|
+
BODY_SHA256
|
|
29
|
+
TIMESTAMP
|
|
30
|
+
NONCE
|
|
31
|
+
APP_KEY
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Rules:
|
|
35
|
+
|
|
36
|
+
- Uppercase `METHOD`.
|
|
37
|
+
- Use the exact public request path, for example `/openapi/v1/flink/zh_CN/flight/search`.
|
|
38
|
+
- Sort query parameters by key and then value before joining them as `k=v&k2=v2`.
|
|
39
|
+
- Hash the raw request body bytes with SHA256 and use the lowercase hex digest.
|
|
40
|
+
- Use the request timestamp exactly as sent in `X-OP-Timestamp`.
|
|
41
|
+
- Use the request nonce exactly as sent in `X-OP-Nonce`.
|
|
42
|
+
- Use the same `open_app_id` that is sent in `X-OP-App-Key`.
|
|
43
|
+
- Sign the canonical string with the plain `open_app_secret` using HMAC-SHA256, then output lowercase hex.
|
|
44
|
+
|
|
45
|
+
Notes:
|
|
46
|
+
|
|
47
|
+
- Timestamp may be Unix seconds, Unix milliseconds, or RFC3339.
|
|
48
|
+
- The platform validates timestamp drift within roughly `+-5` minutes.
|
|
49
|
+
- Nonce must be unique for the same app key in a short time window.
|
|
50
|
+
- For empty bodies, hash the empty byte string.
|
|
51
|
+
|
|
52
|
+
Use `scripts/flink_signed_request.py` when the task needs a deterministic implementation or a quick smoke test.
|
|
53
|
+
|
|
54
|
+
## Credential Acquisition
|
|
55
|
+
|
|
56
|
+
Treat credentials as environment-specific.
|
|
57
|
+
|
|
58
|
+
Sandbox:
|
|
59
|
+
|
|
60
|
+
1. The developer applies for app access.
|
|
61
|
+
2. The operator activates the app access with `env_type=sandbox`.
|
|
62
|
+
3. The platform records sandbox supplier mapping and issues a sandbox `open_app_id/open_app_secret`.
|
|
63
|
+
4. The app access becomes `sandbox_active`.
|
|
64
|
+
|
|
65
|
+
Production:
|
|
66
|
+
|
|
67
|
+
1. The developer submits production access after sandbox work is complete.
|
|
68
|
+
2. The operator approves production with `env_type=production`.
|
|
69
|
+
3. The platform issues a production `open_app_id/open_app_secret`.
|
|
70
|
+
4. The production credential becomes usable only after the app access reaches `production_active`.
|
|
71
|
+
|
|
72
|
+
Important constraints:
|
|
73
|
+
|
|
74
|
+
- Sandbox and production credentials are separate and not interchangeable.
|
|
75
|
+
- Developers can see platform credentials only.
|
|
76
|
+
- Developers cannot see supplier-side secrets.
|
|
77
|
+
|
|
78
|
+
## How To View Or Reset Keys
|
|
79
|
+
|
|
80
|
+
Developer portal APIs:
|
|
81
|
+
|
|
82
|
+
- `GET /api/portal/apps/{app_id}/credentials`
|
|
83
|
+
- Returns the credential list for the app.
|
|
84
|
+
- Includes `open_app_id`, `provider_code`, `env_type`, `open_secret_version`, and masked secret data.
|
|
85
|
+
- Does not return the plain secret in normal list queries.
|
|
86
|
+
- `POST /api/portal/apps/{app_id}/credentials/reset`
|
|
87
|
+
- Resets the platform secret and returns `plain_open_secret`.
|
|
88
|
+
- If the app has more than one credential mapping, pass both `provider_code` and `env_type`.
|
|
89
|
+
|
|
90
|
+
Response fields that matter:
|
|
91
|
+
|
|
92
|
+
- `open_app_id`: the App Key to place into `X-OP-App-Key`
|
|
93
|
+
- `open_secret_masked`: masked secret for display only
|
|
94
|
+
- `open_secret_version`: useful for rotation tracking
|
|
95
|
+
- `plain_open_secret`: returned only on first issuance or reset
|
|
96
|
+
|
|
97
|
+
Practical guidance:
|
|
98
|
+
|
|
99
|
+
- If a developer says "I can only see a masked secret", instruct them to use the reset endpoint or the corresponding portal UI action.
|
|
100
|
+
- If the task is only to call sandbox APIs, do not assume production credentials work.
|
|
101
|
+
- If the app has both sandbox and production mappings, always name the target `env_type` explicitly.
|
|
102
|
+
|
|
103
|
+
## Common Auth Failures
|
|
104
|
+
|
|
105
|
+
- `APP_KEY_INVALID`
|
|
106
|
+
- Wrong `open_app_id`, wrong environment, or the credential does not exist.
|
|
107
|
+
- `SIGN_ERROR`
|
|
108
|
+
- Wrong secret, wrong path, wrong query ordering, wrong body hash, or newline formatting mismatch.
|
|
109
|
+
- `TIMESTAMP_EXPIRED`
|
|
110
|
+
- Clock skew exceeds the allowed window.
|
|
111
|
+
- `NONCE_REPLAY`
|
|
112
|
+
- Nonce was reused under the same app key.
|
|
113
|
+
- `PRODUCT_FORBIDDEN`
|
|
114
|
+
- The app is not enabled for the product, the mapping is not active, or an IP whitelist rule failed.
|
|
115
|
+
|
|
116
|
+
## Response Contract
|
|
117
|
+
|
|
118
|
+
The platform wraps business responses in a common envelope:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"request_id": "req_xxx",
|
|
123
|
+
"trace_id": "trc_xxx",
|
|
124
|
+
"downstream_request_id": "optional",
|
|
125
|
+
"code": "SUCCESS",
|
|
126
|
+
"message": "ok",
|
|
127
|
+
"data": {}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Interpretation:
|
|
132
|
+
|
|
133
|
+
- `request_id` and `trace_id` are platform-side tracing keys.
|
|
134
|
+
- `downstream_request_id` is the supplier request identifier when available.
|
|
135
|
+
- `code=SUCCESS` means the business call succeeded.
|
|
136
|
+
- `code=SUPPLIER_BIZ_ERROR` means the supplier returned a business error and can still arrive with HTTP `200`.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Flink Endpoint Index
|
|
2
|
+
|
|
3
|
+
All routes are public gateway routes. Sign the public path, not the downstream supplier path.
|
|
4
|
+
|
|
5
|
+
## Flight Search
|
|
6
|
+
|
|
7
|
+
- `flink.flight.search`
|
|
8
|
+
- `POST /openapi/v1/flink/{lang}/flight/search`
|
|
9
|
+
- Required body fields: `cabinClass`, `tripType`, `journeys`, `adultNum`
|
|
10
|
+
- Common optional fields: `childNum`, `infantNum`, `airline`, `transferNumber`, `journeyId`, `corporate`
|
|
11
|
+
- Main output to preserve: `priceKey`
|
|
12
|
+
- `flink.flight.cabin`
|
|
13
|
+
- `POST /openapi/v1/flink/{lang}/flight/cabin`
|
|
14
|
+
- Required body fields: `priceKey`
|
|
15
|
+
- Use to expand or refine fare options for a selected result
|
|
16
|
+
- `flink.flight.verify`
|
|
17
|
+
- `POST /openapi/v1/flink/{lang}/flight/verify`
|
|
18
|
+
- Required body fields: `priceKey`
|
|
19
|
+
- Use before order creation
|
|
20
|
+
|
|
21
|
+
## Order Management
|
|
22
|
+
|
|
23
|
+
- `flink.flight.order.create`
|
|
24
|
+
- `POST /openapi/v1/flink/{lang}/flight/order/create`
|
|
25
|
+
- Required body fields: `priceKey`, `contactName`, `contactRegion`, `contactPhone`, `contactEmail`, `passenger`
|
|
26
|
+
- Use after verify or directly after search or cabin when allowed by the business flow
|
|
27
|
+
- `flink.flight.order.pay`
|
|
28
|
+
- `POST /openapi/v1/flink/{lang}/flight/order/pay`
|
|
29
|
+
- Required body fields: `orderNo`, `amount`, `type`
|
|
30
|
+
- `type=0` for standard order, `type=1` for change order
|
|
31
|
+
- `flink.flight.order.detail`
|
|
32
|
+
- `POST /openapi/v1/flink/{lang}/flight/order/detail`
|
|
33
|
+
- Required body fields: `orderNo`
|
|
34
|
+
- `flink.flight.order.cancel`
|
|
35
|
+
- `POST /openapi/v1/flink/{lang}/flight/order/cancel`
|
|
36
|
+
- Required body fields: `orderNo`
|
|
37
|
+
|
|
38
|
+
## Change
|
|
39
|
+
|
|
40
|
+
- `flink.flight.change.search`
|
|
41
|
+
- `POST /openapi/v1/flink/{lang}/flight/change/search`
|
|
42
|
+
- Required body fields: `orderNo`, `cabinClass`, `date`, `passenger`, `segmentId`
|
|
43
|
+
- `flink.flight.change.apply`
|
|
44
|
+
- `POST /openapi/v1/flink/{lang}/flight/change/apply`
|
|
45
|
+
- Required body fields: `orderNo`, `passenger`, `segmentId`, `priceKey`, `changeOrderType`, `changeType`, `contactName`, `contactPhone`, `contactEmail`, `changeReasonType`, `changeReason`
|
|
46
|
+
- `fileList` is required by schema when attachments are involved in involuntary changes
|
|
47
|
+
- `flink.flight.change.cancel`
|
|
48
|
+
- `POST /openapi/v1/flink/{lang}/flight/change/cancel`
|
|
49
|
+
- Required body fields: `changeOrderNo`
|
|
50
|
+
- `flink.flight.change.detail`
|
|
51
|
+
- `POST /openapi/v1/flink/{lang}/flight/change/detail`
|
|
52
|
+
- Required body fields: `changeOrderNo`
|
|
53
|
+
|
|
54
|
+
## Refund
|
|
55
|
+
|
|
56
|
+
- `flink.flight.refund.apply`
|
|
57
|
+
- `POST /openapi/v1/flink/{lang}/flight/refund/apply`
|
|
58
|
+
- Required body fields: `orderNo`, `orderType`, `passenger`, `segmentId`, `refundType`, `reasonType`, `reason`, `fileList`, `contactName`, `contactRegion`, `contactPhone`, `contactEmail`
|
|
59
|
+
- `flink.flight.refund.detail`
|
|
60
|
+
- `POST /openapi/v1/flink/{lang}/flight/refund/detail`
|
|
61
|
+
- Required body fields: `refundOrderNo`
|
|
62
|
+
- `flink.flight.refund.confirm`
|
|
63
|
+
- `POST /openapi/v1/flink/{lang}/flight/refund/confirm`
|
|
64
|
+
- Required body fields: `refundOrderNo`, `confirm`
|
|
65
|
+
|
|
66
|
+
## Basic Data
|
|
67
|
+
|
|
68
|
+
- `flink.airports.list`
|
|
69
|
+
- `POST /openapi/v1/flink/{lang}/airports/list`
|
|
70
|
+
- Required body fields: `page`, `pageSize`
|
|
71
|
+
- Common optional fields: `keyword`
|
|
72
|
+
- `flink.airlines.list`
|
|
73
|
+
- `POST /openapi/v1/flink/{lang}/airlines/list`
|
|
74
|
+
- Required body fields: `page`, `pageSize`
|
|
75
|
+
- Common optional fields: `keyword`, `code`
|
|
76
|
+
- `flink.airports.search`
|
|
77
|
+
- `POST /openapi/v1/flink/{lang}/airports/search`
|
|
78
|
+
- Common body field: `keyword`
|
|
79
|
+
- `flink.nationality.list`
|
|
80
|
+
- `POST /openapi/v1/flink/{lang}/nationality/list`
|
|
81
|
+
- No required body fields in the current schema
|
|
82
|
+
- `flink.fields`
|
|
83
|
+
- `GET /openapi/v1/flink/fields`
|
|
84
|
+
- Query parameters: `priceKey` optional, `orderNo` optional
|
|
85
|
+
- Send at least one of `priceKey` or `orderNo`
|
|
86
|
+
|
|
87
|
+
## Global Notes
|
|
88
|
+
|
|
89
|
+
- `{lang}` is required on every route except `flink.fields`.
|
|
90
|
+
- Platform error responses can return `401`, `403`, `404`, `500`, `502`, or `504`.
|
|
91
|
+
- Common auth-related `401` codes are `APP_KEY_INVALID`, `SIGN_ERROR`, `TIMESTAMP_EXPIRED`, and `NONCE_REPLAY`.
|
|
92
|
+
- Common `403` cause is `PRODUCT_FORBIDDEN`.
|