init: mipu-open 对外开放项目统一管理仓库
- 添加 mipu-api 作为 git submodule (Claude Code Skill) - 迁移 API 文档源文件到 docs/ 目录统一维护 - 添加 Gitea Actions 工作流:tag推送自动打包docs并发布Release - Skill 运行时自动从 mipu-open Release 下载最新文档 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
58
.gitea/workflows/release-docs.yml
Normal file
58
.gitea/workflows/release-docs.yml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
name: Release Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Package docs
|
||||||
|
run: |
|
||||||
|
if [ ! -d "docs" ]; then
|
||||||
|
echo "Error: docs directory not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
TAG=${GITHUB_REF#refs/tags/}
|
||||||
|
echo "$TAG" > "docs/.version"
|
||||||
|
tar -czf /tmp/docs.tar.gz docs/
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
run: |
|
||||||
|
TAG=${GITHUB_REF#refs/tags/}
|
||||||
|
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
||||||
|
|
||||||
|
# Create release
|
||||||
|
curl -sf -X POST "${API}/releases" \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"tag_name\": \"${TAG}\",
|
||||||
|
\"name\": \"API文档 ${TAG}\",
|
||||||
|
\"body\": \"米普云航司API文档更新 ${TAG}\"
|
||||||
|
}"
|
||||||
|
|
||||||
|
# Get release ID
|
||||||
|
RELEASE_ID=$(curl -sf "${API}/releases/tags/${TAG}" \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
| jq -r '.id')
|
||||||
|
|
||||||
|
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
|
||||||
|
echo "Error: failed to create release"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Upload docs.tar.gz
|
||||||
|
curl -sf -X POST "${API}/releases/${RELEASE_ID}/assets?name=docs.tar.gz" \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: multipart/form-data" \
|
||||||
|
-F "attachment=@/tmp/docs.tar.gz"
|
||||||
|
|
||||||
|
echo "Release ${TAG} created with docs.tar.gz"
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "mipu-api"]
|
||||||
|
path = mipu-api
|
||||||
|
url = https://git.addhh.com/willow/mipu-api.git
|
||||||
58
README.md
Normal file
58
README.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Mipu Open
|
||||||
|
|
||||||
|
米普对外开放项目的统一管理仓库。
|
||||||
|
|
||||||
|
## 子项目
|
||||||
|
|
||||||
|
| 子项目 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| [mipu-api](./mipu-api/) | Claude Code 开发 Skill,辅助外部开发者快速对接米普 API |
|
||||||
|
| docs/ | API 文档源文件(本仓库维护,通过 Release 发布 tar 包) |
|
||||||
|
| mipu-sdk | 开发 SDK(待添加) |
|
||||||
|
|
||||||
|
## 文档发布流程
|
||||||
|
|
||||||
|
文档源文件在 `docs/` 目录维护。发布新版本:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 修改 docs/ 下的文档
|
||||||
|
# 2. 提交并打 tag
|
||||||
|
git add docs/
|
||||||
|
git commit -m "更新API文档"
|
||||||
|
git tag v1.1.0
|
||||||
|
git push && git push --tags
|
||||||
|
|
||||||
|
# Gitea Actions 自动:
|
||||||
|
# - 打包 docs/ 为 docs.tar.gz
|
||||||
|
# - 创建 Release 并附加 docs.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Skill 端会在每次调用时自动检查 Release 版本并下载更新。
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
克隆主仓库及所有子模块:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recurse-submodules <this-repo-url>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果已经克隆了主仓库:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule update --init --recursive
|
||||||
|
```
|
||||||
|
|
||||||
|
## 更新子模块
|
||||||
|
|
||||||
|
拉取所有子模块的最新更新:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule update --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
## 添加新子模块
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule add <repo-url> <directory-name>
|
||||||
|
```
|
||||||
144
docs/02-01_cache-search.md
Normal file
144
docs/02-01_cache-search.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
<!-- mipuyun-api-doc: cache-search -->
|
||||||
|
# cache/search - 查询航司缓存数据
|
||||||
|
|
||||||
|
# 缓存票价搜索(cache/search)API 说明文档
|
||||||
|
|
||||||
|
## 用户使用场景
|
||||||
|
|
||||||
|
> 用户希望以低成本,高性能的模式获取航司的价格数据,该数据源为我司缓存库内容,非实时提取航司数据。
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 本接口不会与航司产生任何交互,无法保障在响应时刻价格/库存与航司完全一致。
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 航司路线&旅行日期覆盖率:按航司提供,平均值为180天内>90%。
|
||||||
|
> - 价格准确率(验价变价率):<85%
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/cache/search |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | Header必须带压缩请求。 |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝。 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
注灰色背景为高级特性,默认不不填写,根据需要进行开发。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"agent": "u2web"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| journeyType | String | 是 | "OW" | 行程为单程还是往返程OW:单程OneWayRT:往返RoundTrip |
|
||||||
|
| origin | String | 是 | "CJJ" | 出发地,为IATA 3字码兼容城市或者机场3字码 |
|
||||||
|
| originAirport | String | 否 | | |
|
||||||
|
| destination | String | 是 | "SHA" | 到达地,为IATA3字码兼容城市或者机场3字码 |
|
||||||
|
| destinationAirport | String | 否 | | |
|
||||||
|
| departureDate | String | 是 | 20240326 | 出发日期,格式为 `YYYYMMDD`(如 2024 年 5 月 1 日为 20240501) |
|
||||||
|
| returnDate | String | 否 | 20240423(仅 RT 必填) | 返程日期,格式同 departureDate,仅当 journeyType=RT 时必传,OW 时可传空 |
|
||||||
|
| adults | Integer | 是 | 2 | 成人,乘机人数量 |
|
||||||
|
| children | Integer | 是 | 1 | 儿童,乘机人数量 |
|
||||||
|
| infants | Integer | 是 | 0 | 婴儿,乘机人数量 |
|
||||||
|
| agent | String | 是 | "F9-web" | 你自行定义的F9执行器编码(Agent Code) |
|
||||||
|
| proxy | String | 是 | | 本次获取航司数据采用的代理方式。如果需要指定代理国家请在代理用户后面加上国家二字码。如myproxy-USUS代表美国 |
|
||||||
|
| acceptCacheMinutes | Integer | 否 | 5 | 默认值:5**如无特殊情况,本参数不建议设置或调整。**为了避免频繁请求航司设置的缓存,用户可以指定缓存时长,不填写为5。 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
探索一个返回参数json,https://jsonhero.io/j/XmTLWK94Ae5X
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 示例值 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| itineraries | Array<Itinerary> | - | 航线组合列表,包含不同航班拼接的行程方案 |
|
||||||
|
| code | Integer | 0 | 系统状态码:0 = 成功,非 0 为失败 |
|
||||||
|
| msg | String | null | 系统消息:成功时为 null,失败时返回具体系统提示信息 |
|
||||||
|
| sessionId | String | 66d807b0-abbc-4b57-aeff-bbf4fc29fb75 | UUID: 与航司通信的session值,可以用于加速后续动作,如继续获取包裹,选座,下单。 |
|
||||||
|
|
||||||
|
# 常见问题
|
||||||
|
|
||||||
|
## origin/originAirport的区别是什么?
|
||||||
|
|
||||||
|
origin:出发地,建议传入IATA规定的城市码,必填
|
||||||
|
|
||||||
|
originAirport:出发机场,非必填
|
||||||
|
|
||||||
|
由于各个数据源对于城市码/机场码的需求场景不一致,服务端做了兼容处理。
|
||||||
|
|
||||||
|
一般情况只需要传入Origin(城市码),我们会自动将Origin翻译为机场码,并对航司进行轮询获取所有数据。
|
||||||
|
|
||||||
|
部分特殊情况,如只需要搜索单个机场码,或者直接搜索城市码,不希望服务端转换为机场码,请将需要搜索的三字码直接放入OriginAirport。
|
||||||
|
|
||||||
|
**举例:**
|
||||||
|
|
||||||
|
入参:origin: LON。
|
||||||
|
|
||||||
|
不传入originAirport, 服务端发送给航司originAirport: LCY, LGW, LHR, LTN, SEN, STN
|
||||||
|
|
||||||
|
传入originAirport: LCY, 服务端实际发送给航司originAirport: LCY
|
||||||
|
|
||||||
|
传入originAirport: LON, 服务端实际发送给航司 originAirport: LON
|
||||||
|
|
||||||
|
**destination/destinationAirport逻辑同origin/originAirport**
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
# 业务案例
|
||||||
|
|
||||||
|
## 单人单程搜索
|
||||||
|
|
||||||
|
### 请求(Request)
|
||||||
|
|
||||||
|
```objective-c
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 请求(Response)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 转机行程搜索
|
||||||
|
|
||||||
|
### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "BOM",
|
||||||
|
"destination": "CNX",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应(Response)
|
||||||
|
|
||||||
|
在线查看:https://jsonhero.io/j/J0LMhczR0bJM/editor
|
||||||
|
|
||||||
192
docs/03-01_shopping-search.md
Normal file
192
docs/03-01_shopping-search.md
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
<!-- mipuyun-api-doc: shopping-search -->
|
||||||
|
# shopping/search - 运价报价
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
航班搜索(Flight Search)API 用于驱动 Agent 去数据源(航司)获取对应数据。
|
||||||
|
|
||||||
|
### 用户使用场景
|
||||||
|
|
||||||
|
本接口一般用于:
|
||||||
|
- 查询单家航司报价
|
||||||
|
- 建立航司数据本地缓存
|
||||||
|
|
||||||
|
### 错误场景(不建议使用)
|
||||||
|
|
||||||
|
本接口不适合以下场景:
|
||||||
|
|
||||||
|
- **秒级搜索响应**:本接口为实时调用接口,响应时间依赖数据源(航司),一般响应时间在10秒左右。如需秒级搜索响应,请参考缓存搜索接口(cache/search)。
|
||||||
|
- **验价**:验价请使用 shopping/select(8秒内响应,成功率98%)。
|
||||||
|
|
||||||
|
### 性能指标
|
||||||
|
|
||||||
|
| 指标 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 响应速度 | 依赖数据源(航司)响应,根据大数据统计90%的请求在10秒内 |
|
||||||
|
| 成功率 | >90% |
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| **请求地址** | `https://${endpoint}/shopping/search` |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | Header 必须带压缩请求 |
|
||||||
|
|
||||||
|
### Header 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
### 请求体参数
|
||||||
|
|
||||||
|
> 注:灰色背景为高级特性,默认不填写,根据需要进行开发。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"agent": "u2web",
|
||||||
|
"proxy": "myproxy-us"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值(默认值) | 说明 |
|
||||||
|
|----------|------|----------|-----------------|------|
|
||||||
|
| journeyType | String | 是 | "OW" | 行程类型:OW=单程(OneWay),RT=往返(RoundTrip) |
|
||||||
|
| origin | String | 是 | "CJJ" | 出发地,为IATA 3字码兼容城市或者机场3字码 |
|
||||||
|
| originAirport | String | 否 | - | 出发机场 |
|
||||||
|
| destination | String | 是 | "SHA" | 到达地,为IATA 3字码兼容城市或者机场3字码 |
|
||||||
|
| destinationAirport | String | 否 | - | 到达机场 |
|
||||||
|
| departureDate | String | 是 | 20240326 | 出发日期,格式为 `YYYYMMDD`(如2024年5月1日为20240501) |
|
||||||
|
| returnDate | String | 否 | 20240423 | 返程日期,格式同 departureDate,仅当 journeyType=RT 时必传 |
|
||||||
|
| adults | Integer | 是 | 2 | 成人乘机人数量 |
|
||||||
|
| children | Integer | 是 | 1 | 儿童乘机人数量 |
|
||||||
|
| infants | Integer | 是 | 0 | 婴儿乘机人数量 |
|
||||||
|
| agent | String | 是 | "F9-web" | 你自行定义的执行器编码(Agent Code) |
|
||||||
|
| proxy | String | 是 | - | 本次获取航司数据采用的代理方式。如需指定代理国家请在代理用户后面加上国家二字码,如 myproxy-US 代表美国 |
|
||||||
|
| currency | String | 否 | - | 航司所支持的货币类型,如航司不支持对应货币,接口会进行报错 |
|
||||||
|
| acceptCacheMinutes | Integer | 否 | 5 | 默认值:5。**如无特殊情况,本参数不建议设置或调整。**为了避免频繁请求航司设置的缓存,用户可以指定缓存时长,不填写为5分钟 |
|
||||||
|
| async | Boolean | 是 | false | 是否启用 Webhook 异步模式。<br>- **false**: 同步模式,等待完整结果返回<br>- **true**: 异步模式,立即返回 202,结果通过 Webhook 回调<br><br>**异步模式说明**:<br>1. 系统会同步检查是否有新鲜缓存(acceptCacheMinutes),如有则立即返回<br>2. 无缓存时返回 202 Accepted,包含 requestId 用于追踪<br>3. 航司数据返回后,通过预先配置的 Webhook 回调通知<br><br>**注意**:使用异步模式需提前配置 `shopping_response` 类型的 Webhook |
|
||||||
|
| callbackId | String | 否 | - | 异步模式下的业务回调标识,用于客户自行匹配业务。建议格式:`search_{origin}_{destination}_{departureDate}_{adults}-{children}-{infants}`,最大 50 个字符 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
在线查看返回参数示例:https://jsonhero.io/j/XmTLWK94Ae5X
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 示例值 | 说明 |
|
||||||
|
|----------|------|--------|------|
|
||||||
|
| itineraries | Array\<Itinerary\> | - | 航线组合列表,包含不同航班拼接的行程方案。详见 [Itinerary 实体定义](08-01_itinerary.md) |
|
||||||
|
| code | Integer | 0 | 系统状态码:0=成功,非0为失败 |
|
||||||
|
| msg | String | null | 系统消息:成功时为 null,失败时返回具体系统提示信息 |
|
||||||
|
| sessionId | String | 66d807b0-abbc-4b57-aeff-bbf4fc29fb75 | UUID:与航司通信的 session 值,可以用于加速后续动作,如继续获取包裹、选座、下单 |
|
||||||
|
|
||||||
|
### 异步模式响应(async=true)
|
||||||
|
|
||||||
|
当 `async=true` 且无可用缓存时,系统立即返回 202 Accepted:
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| code | Integer | 202(表示请求已接受,正在处理中) |
|
||||||
|
| msg | String | "Accepted. Please wait for the webhook callback" |
|
||||||
|
| requestId | String | 请求ID(UUID),用于追踪和关联 Webhook 回调 |
|
||||||
|
| status | String | "PROCESSING"(处理中) |
|
||||||
|
|
||||||
|
完整结果将通过预先配置的 Webhook 回调返回。
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### origin/originAirport 的区别是什么?
|
||||||
|
|
||||||
|
**origin**:出发地,建议传入 IATA 规定的城市码,必填
|
||||||
|
|
||||||
|
**originAirport**:出发机场,非必填
|
||||||
|
|
||||||
|
由于各个数据源对于城市码/机场码的需求场景不一致,服务端做了兼容处理。
|
||||||
|
|
||||||
|
一般情况只需要传入 Origin(城市码),我们会自动将 Origin 翻译为机场码,并对航司进行轮询获取所有数据。
|
||||||
|
|
||||||
|
部分特殊情况,如只需要搜索单个机场码,或者直接搜索城市码不希望服务端转换为机场码,请将需要搜索的三字码直接放入 originAirport。
|
||||||
|
|
||||||
|
**举例:**
|
||||||
|
|
||||||
|
- 入参:`origin: LON`
|
||||||
|
- 不传入 originAirport,服务端发送给航司:`originAirport: LCY, LGW, LHR, LTN, SEN, STN`
|
||||||
|
- 传入 originAirport: LCY,服务端实际发送给航司:`originAirport: LCY`
|
||||||
|
- 传入 originAirport: LON,服务端实际发送给航司:`originAirport: LON`
|
||||||
|
|
||||||
|
**destination/destinationAirport 逻辑同 origin/originAirport**
|
||||||
|
|
||||||
|
### 这个接口会使用缓存吗?
|
||||||
|
|
||||||
|
默认情况本接口会读取一个 5 分钟短效缓存,如果你在 5 分钟重复请求同一个路线,那么第二次会直接返回缓存数据。
|
||||||
|
|
||||||
|
你也可以通过 `acceptCacheMinutes` 自己控制缓存时效。
|
||||||
|
|
||||||
|
## 响应实体介绍
|
||||||
|
|
||||||
|
### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": null,
|
||||||
|
"sessionId": "66d807b0-abbc-4b57-aeff-bbf4fc29fb75",
|
||||||
|
"itineraries": [
|
||||||
|
{
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"carrier": "VJ",
|
||||||
|
"flightNumber": "VJ884",
|
||||||
|
"operatingCarrier": "",
|
||||||
|
"operatingFlightnumber": "",
|
||||||
|
"originAirport": "BOM",
|
||||||
|
"destinationAirport": "SGN",
|
||||||
|
"departureTime": "202510270040",
|
||||||
|
"arrivalTime": "202510270705",
|
||||||
|
"departureTerminal": "",
|
||||||
|
"arrivalTerminal": "",
|
||||||
|
"stopCities": "",
|
||||||
|
"duration": 295,
|
||||||
|
"aircraftCode": "330",
|
||||||
|
"codeShare": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inboundSegments": [],
|
||||||
|
"fares": [
|
||||||
|
{
|
||||||
|
"fareBasis": "",
|
||||||
|
"rtnFareBasis": "",
|
||||||
|
"fareFamily": "Lion Economy",
|
||||||
|
"rtnFareFamily": "",
|
||||||
|
"currency": "USD",
|
||||||
|
"adultFare": 100.00,
|
||||||
|
"adultTax": 50.00,
|
||||||
|
"bookingCode": "Y",
|
||||||
|
"availableSeats": 7,
|
||||||
|
"flightPolicy": {
|
||||||
|
"airlineCode": "SL",
|
||||||
|
"fareFamilyType": "Lion Economy",
|
||||||
|
"freeAncillaryList": [
|
||||||
|
{ "categoryCode": "CabinBaggageOverheadLocker", "segmentIndex": 1, "paxType": "ADT", "piece": 1, "weight": 7, "size": "" },
|
||||||
|
{ "categoryCode": "StandardCheckedBaggage", "segmentIndex": 1, "paxType": "ADT", "piece": 1, "weight": 20 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **提示**:`itineraries` 数组中的每个元素是一个完整的行程方案,详见 [Itinerary 实体定义](08-01_itinerary.md)
|
||||||
206
docs/03-02_shopping-select.md
Normal file
206
docs/03-02_shopping-select.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<!-- mipuyun-api-doc: shopping-select -->
|
||||||
|
# shopping/select - 验价/确定航班
|
||||||
|
|
||||||
|
# 确定航班(shopping/select)API 说明文档
|
||||||
|
|
||||||
|
## 用户使用场景
|
||||||
|
|
||||||
|
> 本接口目的是:
|
||||||
|
> 验价:可满足8秒内响应,>95%成功率。
|
||||||
|
> 进一步获取免费行李/退改规则信息(对于无法再shopping/search获取的航司场景)
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 如航司在点选行程后占位,本接口需谨慎使用,防止航司侧异常。
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:95%的请求<8秒。
|
||||||
|
> - 请求频率QPS:根据你的商务合同确定
|
||||||
|
> - 接口成功率:>95%
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/shopping/select |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | Header必须带压缩请求。 |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝。 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionId": "66d807b0-abbc-4b57-aeff-bbf4fc29fb75",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"agent": "u2web",
|
||||||
|
"proxy": "myproxy-us",
|
||||||
|
"outboundFareFamily": "promo",
|
||||||
|
"inboundFareFamily": "",
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"carrier": "SL",
|
||||||
|
"originAirport": "PHS",
|
||||||
|
"destinationAirport": "DMK",
|
||||||
|
"flightNumber": "SL557",
|
||||||
|
"departureDate": "20251119"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inboundSegments": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| sessionId | String | 否 | 66d807b0-abbc-4b57-aeff-bbf4fc29fb75 | 目的是为了复用前一步的shopping/search的session,提升速度&成功率。如带入session,请务必保障:1. 出发到达/旅行日期/人数与前一步保持一致。 |
|
||||||
|
| journeyType | String | 是 | "OW" | 行程为单程还是往返程OW:单程OneWayRT:往返RoundTrip |
|
||||||
|
| origin | String | 是 | "CJJ" | 出发地,为IATA 3字码兼容城市或者机场3字码 |
|
||||||
|
| destination | String | 是 | "SHA" | 到达地,为IATA3字码兼容城市或者机场3字码 |
|
||||||
|
| departureDate | String | 是 | 20240326 | 出发日期,格式为 `YYYYMMDD`(如 2024 年 5 月 1 日为 20240501) |
|
||||||
|
| returnDate | String | 否 | 20240423(仅 RT 必填) | 返程日期,格式同 departureDate,仅当 journeyType=RT 时必传,OW 时可传空 |
|
||||||
|
| adults | Integer | 是 | 2 | 成人,乘机人数量 |
|
||||||
|
| children | Integer | 是 | 1 | 儿童,乘机人数量 |
|
||||||
|
| infants | Integer | 是 | 0 | 婴儿,乘机人数量 |
|
||||||
|
| outboundSegments | Array<FlightSegmentRequest> | 是 | | 去程航段信息,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| inboundSegments | Array<FlightSegmentRequest> | 否 | | 返程航段信息往返行程为必须,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| outboundFareFamily | String | 是 | | 去程FareFamily的名字 |
|
||||||
|
| inboundFareFamily | String | 否 | | 回程FareFamily的名字仅往返程有值 |
|
||||||
|
| agent | String | 是 | "u2web" | 你自行定义的执行器编码(Agent Code) |
|
||||||
|
| proxy | String | 是 | | 本次获取航司数据采用的代理方式。如果需要指定代理国家请在代理用户后面加上国家二字码。如myproxy-USUS代表美国 |
|
||||||
|
| acceptCacheMinutes | Integer | 否 | 5 | 默认值:5**如无特殊情况,本参数不建议设置或调整。**为了避免频繁请求航司设置的缓存,用户可以指定缓存时长,不填写为5。 |
|
||||||
|
| async | Boolean | 是 | false | 是否启用 Webhook 异步模式。<br>- **false**: 同步模式,等待完整结果返回<br>- **true**: 异步模式,立即返回 202,结果通过 Webhook 回调<br><br>**异步模式说明**:<br>1. 系统会同步检查是否有新鲜缓存(acceptCacheMinutes),如有则立即返回<br>2. 无缓存时返回 202 Accepted,包含 requestId 用于追踪<br>3. 航司数据返回后,通过预先配置的 Webhook 回调通知<br><br>**注意**:使用异步模式需提前配置 `shopping_response` 类型的 Webhook |
|
||||||
|
| callbackId | String | 否 | - | 异步模式下的业务回调标识,用于客户自行匹配业务。建议格式:`select_{origin}_{destination}_{departureDate}_{adults}-{children}-{infants}_{flightNumber}`,最大 50 个字符 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
探索一个返回参数json(同shopping/search),https://jsonhero.io/j/XmTLWK94Ae5X
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 示例值 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| itineraries | Array<Itinerary> | - | 航线组合列表,包含不同航班拼接的行程方案 |
|
||||||
|
| baggageList | | | |
|
||||||
|
| | | | |
|
||||||
|
| code | Integer | 0 | 系统状态码:0 = 成功,非 0 为失败 |
|
||||||
|
| msg | String | null | 系统消息:成功时为 null,失败时返回具体系统提示信息 |
|
||||||
|
| sessionId | String | 66d807b0-abbc-4b57-aeff-bbf4fc29fb75 | UUID: 与航司通信的session值,可以用于加速后续动作,如继续获取包裹,选座,下单。 |
|
||||||
|
|
||||||
|
### 异步模式响应(async=true)
|
||||||
|
|
||||||
|
当 `async=true` 且无可用缓存时,系统立即返回 202 Accepted:
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| code | Integer | 202(表示请求已接受,正在处理中) |
|
||||||
|
| msg | String | "Accepted. Please wait for the webhook callback" |
|
||||||
|
| requestId | String | 请求ID(UUID),用于追踪和关联 Webhook 回调 |
|
||||||
|
| status | String | "PROCESSING"(处理中) |
|
||||||
|
|
||||||
|
完整结果将通过预先配置的 Webhook 回调返回。
|
||||||
|
|
||||||
|
## 响应实体介绍
|
||||||
|
|
||||||
|
### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": null,
|
||||||
|
"sessionId": "66d807b0-abbc-4b57-aeff-bbf4fc29fb75",
|
||||||
|
"itineraries": [
|
||||||
|
{
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"carrier": "SL",
|
||||||
|
"flightNumber": "SL557",
|
||||||
|
"operatingCarrier": "",
|
||||||
|
"operatingFlightnumber": "",
|
||||||
|
"originAirport": "PHS",
|
||||||
|
"destinationAirport": "DMK",
|
||||||
|
"departureTime": "202511190800",
|
||||||
|
"arrivalTime": "202511191130",
|
||||||
|
"departureTerminal": "",
|
||||||
|
"arrivalTerminal": "",
|
||||||
|
"stopCities": "",
|
||||||
|
"duration": 210,
|
||||||
|
"aircraftCode": "320",
|
||||||
|
"codeShare": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inboundSegments": [],
|
||||||
|
"fares": [
|
||||||
|
{
|
||||||
|
"fareBasis": "",
|
||||||
|
"rtnFareBasis": "",
|
||||||
|
"fareFamily": "promo",
|
||||||
|
"rtnFareFamily": "",
|
||||||
|
"currency": "USD",
|
||||||
|
"adultFare": 80.00,
|
||||||
|
"adultTax": 30.00,
|
||||||
|
"bookingCode": "Y",
|
||||||
|
"availableSeats": 9,
|
||||||
|
"flightPolicy": {
|
||||||
|
"airlineCode": "SL",
|
||||||
|
"fareFamilyType": "promo",
|
||||||
|
"freeAncillaryList": [
|
||||||
|
{ "categoryCode": "CabinBaggageOverheadLocker", "segmentIndex": 1, "paxType": "ADT", "piece": 1, "weight": 7, "size": "" },
|
||||||
|
{ "categoryCode": "StandardCheckedBaggage", "segmentIndex": 1, "paxType": "ADT", "piece": 0, "weight": 0 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"baggageList": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **提示**:`itineraries` 数组中的每个元素是一个完整的行程方案,详见 [Itinerary 实体定义](08-01_itinerary.md)
|
||||||
|
|
||||||
|
# 常见问题
|
||||||
|
|
||||||
|
## 航司不稳定的时候,如何保障成功率>95%
|
||||||
|
|
||||||
|
我们支持多个通过proxy入参实现并发请求。
|
||||||
|
|
||||||
|
**案例1:竖线分隔,随机挑选**
|
||||||
|
|
||||||
|
proxy= myproxy-us|myproxy-uk
|
||||||
|
|
||||||
|
行为:随机从myproxy-us中挑选一个
|
||||||
|
|
||||||
|
**案例2:加号分隔**
|
||||||
|
|
||||||
|
proxy= myproxy-us+myproxy-uk
|
||||||
|
|
||||||
|
行为:启动两个进程对数据源(航司)做并发访问,确保成功率。
|
||||||
|
|
||||||
|
**案例3:组合**
|
||||||
|
|
||||||
|
proxy= myproxy1-us|myproxy2-au+myproxy1-uk|myproxy2-de
|
||||||
|
|
||||||
|
行为:随机挑选myproxy1|myproxy2的代理,并启动两个进程对数据源做并发访问。
|
||||||
|
|
||||||
|
## 如果航司侧响应大于8秒,这个请求会被抛弃吗?
|
||||||
|
|
||||||
|
不会,为了兼容异常场景,该接口我们最大等待航司响应的时长为15秒。
|
||||||
|
|
||||||
264
docs/03-03_shopping-baggage.md
Normal file
264
docs/03-03_shopping-baggage.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
<!-- mipuyun-api-doc: shopping-baggage -->
|
||||||
|
# shopping/baggage - 行李报价
|
||||||
|
|
||||||
|
## 用户使用场景
|
||||||
|
|
||||||
|
> 获取行程可支持的收费行李规格,以及各个规格的行李价格
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 通过sessionId访问,或者sessionId有效,响应时间<8秒。
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/shopping/baggage |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | Header必须带压缩请求。 |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝。 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionId": "66d807b0-abbc-4b57-aeff-bbf4fc29fb75",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"agent": "u2web",
|
||||||
|
"proxy": "myproxy-us",
|
||||||
|
"outboundFareFamily": "promo",
|
||||||
|
"inboundFareFamily": "",
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"carrier": "SL",
|
||||||
|
"originAirport": "PHS",
|
||||||
|
"destinationAirport": "DMK",
|
||||||
|
"flightNumber": "SL557",
|
||||||
|
"departureDate": "20251119"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inboundSegments": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意**:本接口的请求参数与 [shopping/select](03-02_shopping-select.md) 完全一致,详细的参数说明请参考 shopping/select 文档。
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| sessionId | String | 否 | 66d807b0-abbc-4b57-aeff-bbf4fc29fb75 | 目的是为了复用前一步的shopping/search的session,提升速度&成功率。如带入session,请务必保障:1. 出发到达/旅行日期/人数与前一步保持一致。 |
|
||||||
|
| journeyType | String | 是 | "OW" | 行程为单程还是往返程OW:单程OneWayRT:往返RoundTrip |
|
||||||
|
| origin | String | 是 | "CJJ" | 出发地,为IATA 3字码兼容城市或者机场3字码 |
|
||||||
|
| destination | String | 是 | "SHA" | 到达地,为IATA3字码兼容城市或者机场3字码 |
|
||||||
|
| departureDate | String | 是 | 20240326 | 出发日期,格式为 `YYYYMMDD`(如 2024 年 5 月 1 日为 20240501) |
|
||||||
|
| returnDate | String | 否 | 20240423(仅 RT 必填) | 返程日期,格式同 departureDate,仅当 journeyType=RT 时必传,OW 时可传空 |
|
||||||
|
| adults | Integer | 是 | 2 | 成人,乘机人数量 |
|
||||||
|
| children | Integer | 是 | 1 | 儿童,乘机人数量 |
|
||||||
|
| infants | Integer | 是 | 0 | 婴儿,乘机人数量 |
|
||||||
|
| outboundSegments | Array<FlightSegmentRequest> | 是 | | 去程航段信息,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| inboundSegments | Array<FlightSegmentRequest> | 否 | | 返程航段信息往返行程为必须,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| outboundFareFamily | String | 是 | | 去程FareFamily的名字 |
|
||||||
|
| inboundFareFamily | String | 否 | | 回程FareFamily的名字仅往返程有值 |
|
||||||
|
| agent | String | 是 | "u2web" | 你自行定义的执行器编码(Agent Code) |
|
||||||
|
| proxy | String | 是 | | 本次获取航司数据采用的代理方式。如果需要指定代理国家请在代理用户后面加上国家二字码。如myproxy-USUS代表美国 |
|
||||||
|
| acceptCacheMinutes | Integer | 否 | 5 | 默认值:5**如无特殊情况,本参数不建议设置或调整。**为了避免频繁请求航司设置的缓存,用户可以指定缓存时长,不填写为5。 |
|
||||||
|
| async | Boolean | 是 | false | 是否启用 Webhook 异步模式。<br>- **false**: 同步模式,等待完整结果返回<br>- **true**: 异步模式,立即返回 202,结果通过 Webhook 回调<br><br>**异步模式说明**:<br>1. 系统会同步检查是否有新鲜缓存(acceptCacheMinutes),如有则立即返回<br>2. 无缓存时返回 202 Accepted,包含 requestId 用于追踪<br>3. 航司数据返回后,通过预先配置的 Webhook 回调通知<br><br>**注意**:使用异步模式需提前配置 `shopping_response` 类型的 Webhook |
|
||||||
|
| callbackId | String | 否 | - | 异步模式下的业务回调标识,用于客户自行匹配业务。建议格式:`baggage_{origin}_{destination}_{departureDate}_{adults}-{children}-{infants}_{flightNumber}`,最大 50 个字符 |
|
||||||
|
|
||||||
|
> **参数一致性说明**:本接口的所有请求参数(Header 和 请求体)与 [shopping/select](03-02_shopping-select.md) 完全相同。如果您已经熟悉 shopping/select 接口,可以直接使用相同的参数格式调用本接口。
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 示例值 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| code | Integer | 0 | 系统状态码:0 = 成功,非 0 为失败 |
|
||||||
|
| msg | String | null | 系统消息:成功时为 null,失败时返回具体系统提示信息 |
|
||||||
|
| sessionId | String | 66d807b0-abbc-4b57-aeff-bbf4fc29fb75 | UUID: 与航司通信的session值,可以用于加速后续动作,如继续获取包裹,选座,下单。 |
|
||||||
|
| itineraries | Array\<Itinerary\> | - | 航线组合列表。由于在本接口已确定路线和FareFamily,数组长度 ≤ 1 |
|
||||||
|
| ancillaries | Array\<[AncillaryGroup](#ancillarygroup)\> | {json实体} | 辅营产品分组列表(新结构,三级嵌套) |
|
||||||
|
| ancillaryList | Array | {json实体} | *(兼容旧结构)* 当 `ancillaries` 为空时可能存在,建议优先使用 `ancillaries` |
|
||||||
|
|
||||||
|
### 异步模式响应(async=true)
|
||||||
|
|
||||||
|
当 `async=true` 且无可用缓存时,系统立即返回 202 Accepted:
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| code | Integer | 202(表示请求已接受,正在处理中) |
|
||||||
|
| msg | String | "Accepted. Please wait for the webhook callback" |
|
||||||
|
| requestId | String | 请求ID(UUID),用于追踪和关联 Webhook 回调 |
|
||||||
|
| status | String | "PROCESSING"(处理中) |
|
||||||
|
|
||||||
|
完整结果将通过预先配置的 Webhook 回调返回。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 响应实体介绍
|
||||||
|
|
||||||
|
响应采用三级嵌套结构:**AncillaryGroup** → **AncillaryCategory** → **BaggageOption**
|
||||||
|
|
||||||
|
```
|
||||||
|
ancillaries (Array)
|
||||||
|
└─ AncillaryGroup ← 按航程方向 + 运价家族分组
|
||||||
|
└─ categoryList (Array)
|
||||||
|
└─ AncillaryCategory ← 按行李类别分组
|
||||||
|
└─ categoryDetail (Array)
|
||||||
|
└─ BaggageOption ← 具体行李选项及价格
|
||||||
|
```
|
||||||
|
|
||||||
|
### AncillaryGroup(最外层)
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| currency | String | 售价币种(ISO 4217),如 `CAD`、`EUR`、`USD` |
|
||||||
|
| fareFamilyType | String | 运价家族类型,如 `BASIC`、`SMART`、`PROMO` |
|
||||||
|
| journeyDirection | String | 航程方向:`outbound`(去程)/ `inbound`(回程) |
|
||||||
|
| categoryList | Array\<[AncillaryCategory](#ancillarycategory)\> | 辅营类别列表 |
|
||||||
|
|
||||||
|
### AncillaryCategory(中间层)
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| categoryCode | String | 类别代码,见 [categoryCode 说明](#categorycode-说明) |
|
||||||
|
| maxPieces | String | 该类别最多可购买件数 |
|
||||||
|
| pricingMode | String | 定价模式,见 [pricingMode 说明](#pricingmode-说明) |
|
||||||
|
| categoryDetail | Array\<[BaggageOption](#baggageoption)\> | 选项列表 |
|
||||||
|
|
||||||
|
### BaggageOption(最内层)
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| pieceNo | Integer | 第 N 件。STEP 模式下为序号(1, 2, 3...),FLAT/TIERED 模式下为 1 |
|
||||||
|
| weight | BigDecimal | 行李额重量(KG) |
|
||||||
|
| size | String | 尺寸限制,如 `"55x40x23cm"` |
|
||||||
|
| price | BigDecimal | 该选项/该件价格 |
|
||||||
|
| maxPieces | Integer | 该选项可购买数量 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 响应示例
|
||||||
|
|
||||||
|
#### 示例1:FLAT + STEP 混合
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": null,
|
||||||
|
"sessionId": "NYW34327-f212fbacdd054dda8a509e846e300ebf",
|
||||||
|
"itineraries": [],
|
||||||
|
"ancillaries": [
|
||||||
|
{
|
||||||
|
"currency": "CAD",
|
||||||
|
"fareFamilyType": "BASIC",
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"categoryList": [
|
||||||
|
{
|
||||||
|
"categoryCode": "CabinBaggageOverheadLocker",
|
||||||
|
"maxPieces": "1",
|
||||||
|
"pricingMode": "FLAT",
|
||||||
|
"categoryDetail": [
|
||||||
|
{ "pieceNo": 1, "weight": 10, "size": "55x40x23cm", "price": 39.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 1, "weight": 23, "size": "55x40x23cm", "price": 64.00, "maxPieces": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"categoryCode": "StandardCheckedBaggage",
|
||||||
|
"maxPieces": "5",
|
||||||
|
"pricingMode": "STEP",
|
||||||
|
"categoryDetail": [
|
||||||
|
{ "pieceNo": 1, "weight": 10, "size": "", "price": 39.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 1, "weight": 23, "size": "", "price": 64.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 2, "weight": 23, "size": "", "price": 64.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 3, "weight": 23, "size": "", "price": 99.00, "maxPieces": 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "CAD",
|
||||||
|
"fareFamilyType": "BASIC",
|
||||||
|
"journeyDirection": "inbound",
|
||||||
|
"categoryList": [
|
||||||
|
{
|
||||||
|
"categoryCode": "CabinBaggageOverheadLocker",
|
||||||
|
"maxPieces": "1",
|
||||||
|
"pricingMode": "FLAT",
|
||||||
|
"categoryDetail": [
|
||||||
|
{ "pieceNo": 1, "weight": 10, "size": "55x40x23cm", "price": 35.00, "maxPieces": 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例2:TIERED 模式(按重量档位)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": null,
|
||||||
|
"sessionId": "...",
|
||||||
|
"ancillaries": [
|
||||||
|
{
|
||||||
|
"currency": "CNY",
|
||||||
|
"fareFamilyType": "ECONOMY",
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"categoryList": [
|
||||||
|
{
|
||||||
|
"categoryCode": "StandardCheckedBaggage",
|
||||||
|
"maxPieces": "1",
|
||||||
|
"pricingMode": "TIERED",
|
||||||
|
"categoryDetail": [
|
||||||
|
{ "pieceNo": 1, "weight": 20, "size": "", "price": 300.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 1, "weight": 25, "size": "", "price": 500.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 1, "weight": 30, "size": "", "price": 800.00, "maxPieces": 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### categoryCode 说明
|
||||||
|
|
||||||
|
| categoryCode | 说明 |
|
||||||
|
|--------------|------|
|
||||||
|
| CabinBaggageOverheadLocker | 手提行李(头顶行李架) |
|
||||||
|
| CabinBaggageUnderSeat | 手提行李(座椅下) |
|
||||||
|
| StandardCheckedBaggage | 托运行李 |
|
||||||
|
|
||||||
|
### pricingMode 说明
|
||||||
|
|
||||||
|
| pricingMode | 说明 | 渲染建议 |
|
||||||
|
|-------------|------|----------|
|
||||||
|
| FLAT | 固定单价,每件独立产品 | 卡片网格展示,每个选项一张卡片 |
|
||||||
|
| STEP | 逐件定价,第 N 件对应不同价格 | 表格展示,按 pieceNo 分组,同 pieceNo 行用背景色合并 |
|
||||||
|
| TIERED | 按总重量档位选择,不计件 | 单选列表展示,互斥选项 |
|
||||||
|
|
||||||
|
> **提示**:
|
||||||
|
> - `ancillaries` 数组按 `journeyDirection`(outbound/inbound)和 `fareFamilyType` 分组
|
||||||
|
> - 优先使用 `ancillaries`(新三级结构),`ancillaryList` 为兼容旧结构
|
||||||
|
> - 同一 `pricingMode` 内,`categoryDetail` 按 `pieceNo` 升序排列
|
||||||
|
> - STEP 模式下,相同 `pieceNo` 可能有多个重量/价格选项(如第 1 件可选 10kg 或 23kg)
|
||||||
354
docs/03-04_shopping-seat.md
Normal file
354
docs/03-04_shopping-seat.md
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
<!-- mipuyun-api-doc: shopping-seat -->
|
||||||
|
# shopping/seat - 选座报价
|
||||||
|
|
||||||
|
## 用户使用场景
|
||||||
|
|
||||||
|
> 获取航班座位图信息,包括每个座位的位置、价格、状态(可用/已占)、以及座位特性(靠窗、靠过道、紧急出口等)
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 通过 sessionId 访问,或者 sessionId 有效,响应时间 < 10 秒
|
||||||
|
> - 接口成功率:> 90%
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/shopping/seat |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | Header 必须带压缩请求 |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionId": "743768c1-8bdc-46ed-a586-94fdbd0ce24a",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "OTP",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20260116",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"agent": "AXZ",
|
||||||
|
"proxy": "res_mipu_bookxWdyg-it",
|
||||||
|
"outboundFareFamily": "BASIC",
|
||||||
|
"inboundFareFamily": "",
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"carrier": "XZ",
|
||||||
|
"originAirport": "OTP",
|
||||||
|
"destinationAirport": "FCO",
|
||||||
|
"flightNumber": "XZ3115",
|
||||||
|
"departureDate": "20260116"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"carrier": "XZ",
|
||||||
|
"originAirport": "FCO",
|
||||||
|
"destinationAirport": "CAG",
|
||||||
|
"flightNumber": "XZ2341",
|
||||||
|
"departureDate": "20260116"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inboundSegments": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| sessionId | String | 否 | 743768c1-8bdc-46ed-a586-94fdbd0ce24a | 目的是为了复用前一步的 shopping/search 或 shopping/select 的 session,提升速度 & 成功率。如带入 session,请务必保障:1. 出发到达/旅行日期/人数与前一步保持一致 |
|
||||||
|
| journeyType | String | 是 | "OW" | 行程为单程还是往返程<br>OW:单程 OneWay<br>RT:往返 RoundTrip |
|
||||||
|
| origin | String | 是 | "OTP" | 出发地,为 IATA 3 字码兼容城市或者机场 3 字码 |
|
||||||
|
| destination | String | 是 | "CAG" | 到达地,为 IATA 3 字码兼容城市或者机场 3 字码 |
|
||||||
|
| departureDate | String | 是 | 20260116 | 出发日期,格式为 `YYYYMMDD`(如 2024 年 5 月 1 日为 20240501) |
|
||||||
|
| returnDate | String | 否 | 20240423(仅 RT 必填) | 返程日期,格式同 departureDate,仅当 journeyType=RT 时必传,OW 时可传空 |
|
||||||
|
| adults | Integer | 是 | 1 | 成人,乘机人数量 |
|
||||||
|
| children | Integer | 是 | 0 | 儿童,乘机人数量 |
|
||||||
|
| infants | Integer | 是 | 0 | 婴儿,乘机人数量 |
|
||||||
|
| agent | String | 是 | "AXZ" | Agent 代码 |
|
||||||
|
| proxy | String | 是 | "res_mipu_bookxWdyg-it" | 本次获取航司数据采用的代理方式。如果需要指定代理国家请在代理用户后面加上国家二字码。如 myproxy-US,US 代表美国 |
|
||||||
|
| outboundSegments | Array<FlightSegmentRequest> | 是 | 见示例 | 去程航段信息,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| inboundSegments | Array<FlightSegmentRequest> | 否 | | 返程航段信息,往返行程为必须,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| outboundFareFamily | String | 是 | "BASIC" | 去程 FareFamily 的名字 |
|
||||||
|
| inboundFareFamily | String | 否 | | 回程 FareFamily 的名字,仅往返程有值 |
|
||||||
|
| acceptCacheMinutes | Integer | 否 | 5 | 默认值:5<br>**如无特殊情况,本参数不建议设置或调整。**为了避免频繁请求航司设置的缓存,用户可以指定缓存时长,不填写为 5 |
|
||||||
|
| async | Boolean | 是 | false | 是否启用 Webhook 异步模式。<br>- **false**: 同步模式,等待完整结果返回<br>- **true**: 异步模式,立即返回 202,结果通过 Webhook 回调<br><br>**异步模式说明**:<br>1. 系统会同步检查是否有新鲜缓存(acceptCacheMinutes),如有则立即返回<br>2. 无缓存时返回 202 Accepted,包含 requestId 用于追踪<br>3. 航司数据返回后,通过预先配置的 Webhook 回调通知<br><br>**注意**:使用异步模式需提前配置 `shopping_response` 类型的 Webhook |
|
||||||
|
| callbackId | String | 否 | - | 异步模式下的业务回调标识,用于客户自行匹配业务。建议格式:`seat_{origin}_{destination}_{departureDate}_{adults}-{children}-{infants}_{flightNumber}`,最大 50 个字符 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cached": false,
|
||||||
|
"code": 0,
|
||||||
|
"itineraries": [],
|
||||||
|
"msg": "success",
|
||||||
|
"seatMapList": [
|
||||||
|
{
|
||||||
|
"segmentIndex": 1,
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"segment": {
|
||||||
|
"flightNumber": "DM200",
|
||||||
|
"dptAirport": "AUA",
|
||||||
|
"arrAirport": "CUR",
|
||||||
|
"departureTime": "202604261100",
|
||||||
|
"arrivalTime": "202604261150"
|
||||||
|
},
|
||||||
|
"cabins": [
|
||||||
|
{
|
||||||
|
"deck": "main",
|
||||||
|
"cabinType": "Business",
|
||||||
|
"cabinLayout": {
|
||||||
|
"columns": [
|
||||||
|
{ "designator": "A", "characteristics": "W" },
|
||||||
|
{ "designator": "C", "characteristics": "A" },
|
||||||
|
{ "designator": "D", "characteristics": "A" },
|
||||||
|
{ "designator": "G", "characteristics": "A" },
|
||||||
|
{ "designator": "J", "characteristics": "W" }
|
||||||
|
],
|
||||||
|
"rows": { "first": 1, "last": 8 },
|
||||||
|
"exitRowPositions": []
|
||||||
|
},
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"number": 1,
|
||||||
|
"seats": [
|
||||||
|
{
|
||||||
|
"column": "A",
|
||||||
|
"currency": "EUR",
|
||||||
|
"price": 120.0,
|
||||||
|
"seatCharacteristics": ["W", "L"],
|
||||||
|
"seatStatus": "F"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"deck": "main",
|
||||||
|
"cabinType": "Economy",
|
||||||
|
"cabinLayout": {
|
||||||
|
"columns": [
|
||||||
|
{ "designator": "A", "characteristics": "W" },
|
||||||
|
{ "designator": "B", "characteristics": "M" },
|
||||||
|
{ "designator": "C", "characteristics": "A" },
|
||||||
|
{ "designator": "D", "characteristics": "A" },
|
||||||
|
{ "designator": "E", "characteristics": "M" },
|
||||||
|
{ "designator": "F", "characteristics": "W" }
|
||||||
|
],
|
||||||
|
"rows": { "first": 9, "last": 32 },
|
||||||
|
"exitRowPositions": [
|
||||||
|
{ "first": 16, "last": 16 },
|
||||||
|
{ "first": 17, "last": 17 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"number": 9,
|
||||||
|
"seats": [
|
||||||
|
{
|
||||||
|
"column": "A",
|
||||||
|
"currency": "EUR",
|
||||||
|
"price": 21.0,
|
||||||
|
"seatCharacteristics": ["W", "IE", "E", "L"],
|
||||||
|
"seatStatus": "F"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sessionId": "shopping-seat-fa149f406bcd4df9a1a318d230afc422"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应字段说明
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| code | Integer | 系统状态码:0 = 成功,非 0 为失败 |
|
||||||
|
| msg | String | 系统消息:成功时为 null,失败时返回具体系统提示信息 |
|
||||||
|
| cached | Boolean | 是否使用缓存数据 |
|
||||||
|
| sessionId | String | UUID:与航司通信的 session 值,可以用于加速后续动作,如下单 |
|
||||||
|
| itineraries | Array<Itinerary> | 航线组合列表(本接口通常为空数组) |
|
||||||
|
| seatMapList | Array<SeatMap> | **座位图列表,按航段返回每个航段的座位信息** |
|
||||||
|
|
||||||
|
### 异步模式响应(async=true)
|
||||||
|
|
||||||
|
当 `async=true` 且无可用缓存时,系统立即返回 202 Accepted:
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| code | Integer | 202(表示请求已接受,正在处理中) |
|
||||||
|
| msg | String | "Accepted. Please wait for the webhook callback" |
|
||||||
|
| requestId | String | 请求ID(UUID),用于追踪和关联 Webhook 回调 |
|
||||||
|
| status | String | "PROCESSING"(处理中) |
|
||||||
|
|
||||||
|
完整结果将通过预先配置的 Webhook 回调返回。
|
||||||
|
|
||||||
|
### SeatMap(座位图)对象说明
|
||||||
|
|
||||||
|
seatMapList 数组中的每个元素代表一个航段的座位图,结构如下:
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| segmentIndex | Integer | 航段索引(从 1 开始),对应 outboundSegments 或 inboundSegments 中的位置 |
|
||||||
|
| journeyDirection | String | 行程方向:`outbound`(去程)/ `inbound`(返程) |
|
||||||
|
| segment | Object | 航段信息对象,包含航班号、出发/到达机场和时间 |
|
||||||
|
| cabins | Array\<Cabin\> | 客舱信息列表,按舱位等级排列(如商务舱在前、经济舱在后) |
|
||||||
|
|
||||||
|
#### Segment(航段)对象
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| flightNumber | String | 航班号,如 "DM200" |
|
||||||
|
| dptAirport | String | 出发机场 IATA 三字码,如 "AUA" |
|
||||||
|
| arrAirport | String | 到达机场 IATA 三字码,如 "CUR" |
|
||||||
|
| departureTime | String | 出发时间,格式 `YYYYMMDDHHmm`,如 "202604261100" |
|
||||||
|
| arrivalTime | String | 到达时间,格式 `YYYYMMDDHHmm`,如 "202604261150" |
|
||||||
|
|
||||||
|
#### Cabin(机舱)对象
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| deck | String | 甲板类型,如 "main" 表示主甲板 |
|
||||||
|
| cabinType | String | 客舱类型,可选值:`Economy`(经济舱)、`Business`(商务舱)、`FirstClass`(头等舱)、`PremiumEconomy`(高端经济舱) |
|
||||||
|
| cabinLayout | Object | 机舱布局信息 |
|
||||||
|
| rows | Array\<Row\> | 座位行列表 |
|
||||||
|
|
||||||
|
#### CabinLayout(机舱布局)对象
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| columns | Array<Column> | 列信息数组,描述每列的座位特性 |
|
||||||
|
| rows | Object | 行范围,包含 `first`(起始行号)和 `last`(结束行号) |
|
||||||
|
| exitRowPositions | Array<Object> | 紧急出口行位置数组,每个对象包含 `first` 和 `last` 行号 |
|
||||||
|
|
||||||
|
#### Column(列)对象
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| designator | String | 列标识符,如 "A"、"B"、"C" 等 |
|
||||||
|
| characteristics | String | 列特性代码(见座位特性说明) |
|
||||||
|
|
||||||
|
#### Row(座位行)对象
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| number | Integer | 行号 |
|
||||||
|
| seats | Array<Seat> | 该行的座位列表 |
|
||||||
|
|
||||||
|
#### Seat(座位)对象
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 示值 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| column | String | "A" | 列标识符(A、B、C 等) |
|
||||||
|
| seatStatus | String | "F" | 座位状态<br>**F**:Free(可用)<br>**O**:Occupied(已占) |
|
||||||
|
| seatCharacteristics | Array<String> | ["W", "I"] | 座位特性数组(见下文座位特性说明) |
|
||||||
|
| price | BigDecimal | 15.0 | 座位价格(该座位选座费用) |
|
||||||
|
| currency | String | "EUR" | 价格币种 |
|
||||||
|
|
||||||
|
### 座位特性说明
|
||||||
|
|
||||||
|
seatCharacteristics 数组中的特性代码:
|
||||||
|
|
||||||
|
| 代码 | 英文 | 中文说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| W | Window | 靠窗座位 |
|
||||||
|
| A | Aisle | 靠过道座位 |
|
||||||
|
| M | Middle | 中间座位 |
|
||||||
|
| I | Standard | 标准座位 |
|
||||||
|
| IE | ExitRow | 紧急出口排 |
|
||||||
|
| E | ExtraLegroom | 额外腿部空间 |
|
||||||
|
| L | LimitedRecline | 有限后倾 |
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 如何理解 seatMapList 的结构?
|
||||||
|
|
||||||
|
每个航段(Segment)都有一个独立的座位图,每个座位图可包含多个舱位(cabins)。例如:
|
||||||
|
- 单程直飞:seatMapList 长度为 1,该航段可能包含 1 个或多个 cabins(如商务舱 + 经济舱)
|
||||||
|
- 单程转机(2 个航段):seatMapList 长度为 2,每个航段各有独立的 cabins
|
||||||
|
- 往返程直飞:seatMapList 长度为 2(去程 + 回程),每个航段各有独立的 cabins
|
||||||
|
|
||||||
|
segmentIndex 从 1 开始,与请求中的 outboundSegments/inboundSegments 数组索引对应。cabins 数组中每个 Cabin 对象代表一个舱位区域,通过 cabinType 区分舱位等级。
|
||||||
|
|
||||||
|
### 座位状态有哪些?
|
||||||
|
|
||||||
|
- **F (Free)**:座位可选,未被占用
|
||||||
|
- **O (Occupied)**:座位已被占用,不可选择
|
||||||
|
|
||||||
|
### 如何识别靠窗/靠过道座位?
|
||||||
|
|
||||||
|
通过 seatCharacteristics 数组判断:
|
||||||
|
- 包含 "W":靠窗座位
|
||||||
|
- 包含 "A":靠过道座位
|
||||||
|
- 包含 "M":中间座位(通常在 3-3 或 3-4-3 布局的中间列)
|
||||||
|
|
||||||
|
### 紧急出口座位如何识别?
|
||||||
|
|
||||||
|
包含以下特性的座位通常是紧急出口排:
|
||||||
|
- **IE (ExitRow)**:紧急出口排
|
||||||
|
- **E (ExtraLegroom)**:额外腿部空间
|
||||||
|
|
||||||
|
这些座位通常价格更高,腿部空间更大,但可能有年龄限制(如 14 岁以上)。
|
||||||
|
|
||||||
|
### 价格为 0 的座位是什么意思?
|
||||||
|
|
||||||
|
价格为 0 表示该座位免费可选,不需要额外付费。这种情况常见于:
|
||||||
|
- 高端舱位(商务舱、头等舱)
|
||||||
|
- 航司促销活动
|
||||||
|
- 某些会员权益
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 单人单程选座查询
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "OTP",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20260116",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"agent": "AXZ",
|
||||||
|
"outboundFareFamily": "BASIC",
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"carrier": "XZ",
|
||||||
|
"originAirport": "OTP",
|
||||||
|
"destinationAirport": "CAG",
|
||||||
|
"flightNumber": "XZ3115",
|
||||||
|
"departureDate": "20260116"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
响应包含完整的座位图,每个座位都有:
|
||||||
|
- 位置信息(行号 + 列号)
|
||||||
|
- 价格信息(price + currency)
|
||||||
|
- 状态信息(seatStatus:F/O)
|
||||||
|
- 特性信息(seatCharacteristics:靠窗/靠过道/紧急出口等)
|
||||||
|
|
||||||
|
在线查看完整示例:https://jsonhero.io/j/XmTLWK94Ae5X
|
||||||
187
docs/03-05_async-query.md
Normal file
187
docs/03-05_async-query.md
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<!-- mipuyun-api-doc: async-query -->
|
||||||
|
# async/query - 异步查询
|
||||||
|
|
||||||
|
# 异步查询(async/query)API 说明文档
|
||||||
|
|
||||||
|
## 用户使用场景
|
||||||
|
|
||||||
|
> 本接口目的是:
|
||||||
|
> 当异步调用API返回code:202时,通过本接口查询异步请求的结果。
|
||||||
|
|
||||||
|
## 使用时机
|
||||||
|
|
||||||
|
> 当异步调用API返回 `code: 202` 时,表示请求已接收并正在后台处理。
|
||||||
|
> 此时响应中会包含 `requestId`,使用本接口查询处理结果。
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:毫秒级(直接从缓存读取)
|
||||||
|
> - 请求频率QPS:无限制
|
||||||
|
> - 数据保留时间:24小时
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/async/query/{requestId} |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | GET |
|
||||||
|
| **注意事项** | Header 必须带认证信息。 |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
### 路径参数
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| requestId | String | 是 | abc123-def456 | 异步请求返回的 requestId |
|
||||||
|
|
||||||
|
## 响应说明
|
||||||
|
|
||||||
|
### 有结果(请求已处理完成)
|
||||||
|
|
||||||
|
当异步请求已处理完成,**直接返回原始响应数据**(不包裹在统一响应结构中)。
|
||||||
|
|
||||||
|
**判断方式**:响应体中直接包含业务数据字段(如 `itineraries`、`bookingId` 等),无 `code` 字段包裹。
|
||||||
|
|
||||||
|
**示例 - 有结果(搜索)**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"itineraries": [
|
||||||
|
{
|
||||||
|
"itineraryId": "xxx",
|
||||||
|
"outbound": {
|
||||||
|
"segments": [...]
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"total": 1200.00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sessionId": "session-xxx"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例 - 有结果(预订)**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"bookingId": "BK123456",
|
||||||
|
"status": "HOLD",
|
||||||
|
"expiryTime": "2025-01-20T12:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 无结果(请求未找到或已过期)
|
||||||
|
|
||||||
|
当异步请求不存在或已过期时,返回 404 错误。
|
||||||
|
|
||||||
|
**判断方式**:响应体中 `code: 404`
|
||||||
|
|
||||||
|
**示例 - 无结果**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 404,
|
||||||
|
"msg": "Not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**可能原因**:
|
||||||
|
1. `requestId` 不存在
|
||||||
|
2. 请求已过期(超过 24 小时)
|
||||||
|
3. 请求属于其他租户(clientCode 不匹配)
|
||||||
|
|
||||||
|
### 请求仍在处理中
|
||||||
|
|
||||||
|
当异步请求仍在处理中时,会返回处理中的状态。
|
||||||
|
|
||||||
|
**示例 - 处理中**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 202,
|
||||||
|
"msg": "Processing",
|
||||||
|
"requestId": "abc123-def456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 完整示例
|
||||||
|
|
||||||
|
### 请求示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET "https://api.example.com/async/query/abc123-def456" \
|
||||||
|
-H "client-key: your-client-key" \
|
||||||
|
-H "client-secret: your-client-secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应示例(有结果)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"itineraries": [
|
||||||
|
{
|
||||||
|
"itineraryId": "itinerary-001",
|
||||||
|
"outbound": {
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"carrier": "CA",
|
||||||
|
"flightNumber": "CA123",
|
||||||
|
"origin": "PEK",
|
||||||
|
"destination": "SHA",
|
||||||
|
"departureTime": "2025-01-20T08:00:00",
|
||||||
|
"arrivalTime": "2025-01-20T10:00:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"currency": "CNY",
|
||||||
|
"total": 1200.00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sessionId": "session-xxx"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应示例(无结果)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 404,
|
||||||
|
"msg": "Not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q: 如何获取 requestId?
|
||||||
|
|
||||||
|
A: 当异步调用API返回 `code: 202` 时,响应中会包含 `requestId` 字段。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 202,
|
||||||
|
"msg": "Async request accepted",
|
||||||
|
"requestId": "abc123-def456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: 结果会保留多久?
|
||||||
|
|
||||||
|
A: 异步请求的结果会保留 24 小时,超时后自动删除。
|
||||||
|
|
||||||
|
### Q: 可以查询其他租户的请求吗?
|
||||||
|
|
||||||
|
A: 不可以。接口会根据认证信息中的 clientCode 进行租户隔离,只能查询本租户的请求。
|
||||||
|
|
||||||
|
### Q: 建议的轮询策略是什么?
|
||||||
|
|
||||||
|
A: 建议每隔 2-5 秒查询一次,最多查询 10 次。如果 10 次后仍未获取结果,可能是航司响应较慢,建议稍后重试。
|
||||||
163
docs/04-01_booking-hold.md
Normal file
163
docs/04-01_booking-hold.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
<!-- mipuyun-api-doc: booking-hold -->
|
||||||
|
# booking/hold - 下单
|
||||||
|
|
||||||
|
# 下单(booking/hold) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 用户在航班验价通过后,确认预订意向,提交乘客与联系人信息以生成正式订单
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 未通过验价接口(checkRoute)获取有效 offerId 时(此场景需先调用验价接口,确保价格与航线有效性)
|
||||||
|
> 1. 验价接口返回的 offerId 已过期(通常与支付截止时间关联,过期后需重新验价获取新 offerId)
|
||||||
|
> 1. 乘客信息、证件信息未完整填写或格式错误时(应先校验信息合法性,避免接口调用失败)
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 15000ms(因需实时对接航司数据,响应速度明显慢于搜索接口)
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/booking/hold |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝。 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"agent": "u2web",
|
||||||
|
"proxy": "myproxy-us",
|
||||||
|
"outboundFareFamily": "promo",
|
||||||
|
"inboundFareFamily": "",
|
||||||
|
"maximumFareThreshold": 15009.69,
|
||||||
|
"currency": "THB",
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"carrier": "SL",
|
||||||
|
"originAirport": "PHS",
|
||||||
|
"destinationAirport": "DMK",
|
||||||
|
"flightNumber": "SL557",
|
||||||
|
"departureDate": "20251119"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inboundSegments": [
|
||||||
|
],
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"firstName": "first",
|
||||||
|
"lastName": "last",
|
||||||
|
"passengerType": "ADT",
|
||||||
|
"dateOfBirth": "19970616",
|
||||||
|
"gender": "M",
|
||||||
|
"documentNumber": "E12343214",
|
||||||
|
"documentType": "PP",
|
||||||
|
"documentIssuePlace": "CN",
|
||||||
|
"documentExpirationDate": "20260731",
|
||||||
|
"nationality": "CN",
|
||||||
|
"mobile": "0086-18923726222",
|
||||||
|
"frequentFlyerNumber": "",
|
||||||
|
"frequentFlyerCarrier": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contactInfo": {
|
||||||
|
"firstName": "san",
|
||||||
|
"lastName": "zhang",
|
||||||
|
"address": "dfdsaqqq",
|
||||||
|
"phoneCountryCode": "0086",
|
||||||
|
"phone": "18912345678",
|
||||||
|
"email": "san.zhang@gmail.com",
|
||||||
|
"postCode": "310006",
|
||||||
|
"city": "hangzhou",
|
||||||
|
"province": "zejiang",
|
||||||
|
"country": "CN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| orderId | String | 是 | abbc4b57fb75 | 你系统内的订单号,返回的有效报价唯一标识,用于关联待下单的航线与价格 |
|
||||||
|
| journeyType | String | 是 | "OW" | 行程为单程还是往返程OW:单程OneWayRT:往返RoundTrip |
|
||||||
|
| origin | String | 是 | "CJJ" | 出发地,为IATA 3字码兼容城市或者机场3字码 |
|
||||||
|
| destination | String | 是 | "SHA" | 到达地,为IATA3字码兼容城市或者机场3字码 |
|
||||||
|
| departureDate | String | 是 | 20240326 | 出发日期,格式为 `YYYYMMDD`(如 2024 年 5 月 1 日为 20240501) |
|
||||||
|
| returnDate | String | 否 | 20240423(仅 RT 必填) | 返程日期,格式同 departureDate,仅当 journeyType=RT 时必传,OW 时可传空 |
|
||||||
|
| adults | Integer | 是 | 2 | 成人,乘机人数量 |
|
||||||
|
| children | Integer | 是 | 1 | 儿童,乘机人数量 |
|
||||||
|
| infants | Integer | 是 | 0 | 婴儿,乘机人数量 |
|
||||||
|
| outboundSegments | Array<FlightSegmentRequest> | 是 | | 去程航段信息,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| inboundSegments | Array<FlightSegmentRequest> | 否 | | 返程航段信息往返行程为必须,详见 [FlightSegmentRequest](07-01_flight-segment-request.md) |
|
||||||
|
| outboundFareFamily | String | 是 | | 去程FareFamily的名字 |
|
||||||
|
| inboundFareFamily | String | 否 | | 回程FareFamily的名字仅往返程有值 |
|
||||||
|
| maximumFareThreshold | Number | **是** | 15009.69 | 最高票价阈值,超过此价格的报价将不会被接受(用于限制订单金额) |
|
||||||
|
| currency | String | **是** | "THB" | 出票币种代码,遵循ISO 4217标准,如:USD、CNY、THB、EUR等。<br>**注意**:必须为出票币种,系统不会进行任何汇率转换 |
|
||||||
|
| proxy | String | 是 | | 本次获取航司数据采用的代理方式。如果需要指定代理国家请在代理用户后面加上国家二字码。如myproxy-US,US代表美国 |
|
||||||
|
| passengers | Array | 是 | 请查看实体定义([Passenger](07-02_passenger.md)) | 乘客信息列表,支持 1-9 名乘客(具体数量受航司限制),每个数组元素为单个乘客详情 |
|
||||||
|
| contactInfo | Object | 是 | 请查看实体定义([ContactInfo](07-03_contact-info.md)) | 联系人信息,用于接收订单通知、行程单等 |
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
探索一个响应实体:https://jsonhero.io/j/pPOhukgKMcln/editor
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| code | Integer | 0 | 系统状态码:0 = 成功,非 0 = 失败 |
|
||||||
|
| msg | String | null | 系统消息:成功时为 null,失败时返回具体错误提示(如 “证件有效期不足”“航司订单创建超时”) |
|
||||||
|
| pnr | String | 000000 | 仅同步模式会响应PNR信息注意对于不支持Hold的航司,我们也会实施与航司进行交互,并将动作完成在支付前一步,这种情况也可以返回000000 |
|
||||||
|
| pnrExpiryTime | String | YYYYMMDDHHMMSS20251225121212 | hold到的PNR有效期,此处时间为UTC 0时区格式。 |
|
||||||
|
| status | String | | * 异步模式,且进行中为进行中,失败,成功 * 同步模式,为完成,失败,成功 |
|
||||||
|
| orderId | String | | 入参给的orderId |
|
||||||
|
| feeItems | Array | 参考Feeitems实体 | 从航司处获取的报价细项拆分[feeItems 实体定义](08-06_fee-items.md) |
|
||||||
|
|
||||||
|
## 实体定义说明
|
||||||
|
|
||||||
|
本接口涉及的实体对象定义如下:
|
||||||
|
|
||||||
|
### 请求参数实体
|
||||||
|
|
||||||
|
| 实体名称 | 说明 | 链接 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| FlightSegmentRequest | 航段请求对象,用于描述单段航班的核心信息 | [查看详情](07-01_flight-segment-request.md) |
|
||||||
|
| Passenger | 乘客信息对象,包括身份信息、证件信息、常旅客信息等 | [查看详情](07-02_passenger.md) |
|
||||||
|
| ContactInfo | 联系人信息对象,用于接收订单通知、行程单等 | [查看详情](07-03_contact-info.md) |
|
||||||
|
|
||||||
|
### 返回参数实体
|
||||||
|
|
||||||
|
| 实体名称 | 说明 | 链接 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Itinerary | 行程组合信息,包含去程和返程航段列表 | [查看详情](08-01_itinerary.md) |
|
||||||
|
| FlightFare | 票价信息对象,描述不同乘客类型的费用构成 | [查看详情](08-02_flight-fare.md) |
|
||||||
|
| SegmentElement | 航段响应对象,描述单段航班的详细信息 | [查看详情](08-03_segment-element.md) |
|
||||||
|
| FreeBaggage (freeAncillaryList) | 免费行李额元素,描述每个航段每种乘客类型的免费行李配额 | [查看详情](08-04_flight-policy.md) |
|
||||||
|
| RefundRule (refundRules) | 退改规则对象,描述航班的退改签政策(预留字段,暂未提供) | [查看详情](08-04_flight-policy.md) |
|
||||||
|
| FlightPolicy | 航班政策对象,包含行李、退改等政策信息 | [查看详情](08-04_flight-policy.md) |
|
||||||
|
| AncillaryProduct | 附加产品对象,描述付费行李等附加服务 | [查看详情](08-05_ancillary-product.md) |
|
||||||
|
| feeItems | 费用明细对象,拆分航班预订的各类费用 | [查看详情](08-06_fee-items.md) |
|
||||||
|
|
||||||
302
docs/04-02_booking-payment.md
Normal file
302
docs/04-02_booking-payment.md
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
<!-- mipuyun-api-doc: booking-payment -->
|
||||||
|
# booking/payment - 支付
|
||||||
|
|
||||||
|
# 更新支付信息(booking/payment) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 客户完成 booking/hold 下单后,需要更新订单的支付信息(如支付方式、信用卡信息等)
|
||||||
|
> 2. 用于在支付流程中记录或更新支付相关信息
|
||||||
|
> 3. 使用 Apple Pay 支付时,可指定设备标签来选择执行任务的设备
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 未完成 booking/hold 下单,订单不存在时
|
||||||
|
> 2. orderId 为空或未提供时
|
||||||
|
> 3. 订单不属于当前客户(clientCode 不匹配)时
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 2000ms
|
||||||
|
> - 接口成功率:> 99%
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/booking/payment |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝。 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"proxy": "myproxy-us",
|
||||||
|
"paymentMethod": "CREDIT_CARD",
|
||||||
|
"retryCount": 0,
|
||||||
|
"creditCard": {
|
||||||
|
"number": "4111111111111111",
|
||||||
|
"CVV": "123",
|
||||||
|
"expiryMonth": "12",
|
||||||
|
"expiryYear": "25",
|
||||||
|
"lastName": "Doe",
|
||||||
|
"firstName": "John",
|
||||||
|
"country": "US"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| orderId | String | **是** | abbc4b57fb75 | 客户的订单号,必须是通过 booking/hold 创建的订单 |
|
||||||
|
| proxy | String | 是 | | 本次获取航司数据采用的代理方式。如果需要指定代理国家请在代理用户后面加上国家二字码。如myproxy-US,US代表美国 |
|
||||||
|
| paymentMethod | String | 否 | "CREDIT_CARD" | 支付方式代码:<br>**BALANCE**:余额支付<br>**CREDIT_CARD**:信用卡<br>**APPLE_PAY**:Apple Pay(支持设备标签) |
|
||||||
|
| retryCount | Integer | 否 | 0 | 支付重试次数,默认为 0(不重试) |
|
||||||
|
| creditCard | Object | 条件必填 | | 信用卡信息对象,当 paymentMethod 为 CREDIT_CARD 时必填 |
|
||||||
|
| ├─ number | String | **条件必填** | "4111111111111111" | 信用卡号(13-19 位数字) |
|
||||||
|
| ├─ CVV | String | **条件必填** | "123" | CVV 安全码(3-4 位数字) |
|
||||||
|
| ├─ expiryMonth | String | **条件必填** | "12" | 有效期月份(1-2 位数字) |
|
||||||
|
| ├─ expiryYear | String | **条件必填** | "25" | 有效期年份(2 或 4 位数字) |
|
||||||
|
| ├─ lastName | String | **条件必填** | "Doe" | 持卡人姓 |
|
||||||
|
| ├─ firstName | String | **条件必填** | "John" | 持卡人名 |
|
||||||
|
| ├─ country | String | **条件必填** | "US" | 持卡人国家(二字码) |
|
||||||
|
| ├─ province | String | 否 | | 持卡人省份/州 |
|
||||||
|
| ├─ city | String | 否 | | 持卡人城市 |
|
||||||
|
| ├─ postCode | String | 否 | | 持卡人邮编 |
|
||||||
|
| ├─ address | String | 否 | | 持卡人地址 |
|
||||||
|
| ├─ phone | String | 否 | | 持卡人电话(实体卡时使用) |
|
||||||
|
| ├─ email | String | 否 | | 持卡人邮箱(实体卡时使用) |
|
||||||
|
| ├─ maximumPaymentAmount | BigDecimal | 否 | | 最大支付金额 |
|
||||||
|
| └─ reusable | Boolean | 否 | false | 是否为多次卡(默认单次卡) |
|
||||||
|
| deviceTag | String | 否 | "EUR" | 设备标签,仅当 paymentMethod 为 APPLE_PAY 时可选,用于指定执行任务的设备 |
|
||||||
|
|
||||||
|
### 设备标签说明 (deviceTag)
|
||||||
|
|
||||||
|
- **适用场景**:仅当 `paymentMethod` 为 `APPLE_PAY` 时有效
|
||||||
|
- **作用**:指定执行任务的设备标签,系统会优先分配有对应标签的设备
|
||||||
|
- **可选性**:留空则自动分配设备
|
||||||
|
- **示例**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"paymentMethod": "APPLE_PAY",
|
||||||
|
"deviceTag": "EUR"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
### 成功响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Payment info updated successfully",
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 失败响应
|
||||||
|
|
||||||
|
#### 缺少 orderId
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"msg": "orderId is required"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 订单不存在
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 404,
|
||||||
|
"msg": "Booking not found",
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 更新失败
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 500,
|
||||||
|
"msg": "Failed to update payment info",
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应字段说明
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| code | Integer | 0 | 系统状态码<br>**0**:成功<br>**400**:缺少必填参数(orderId)<br>**404**:订单不存在或不属于当前客户<br>**500**:更新支付信息失败 |
|
||||||
|
| msg | String | "Payment info updated successfully" | 系统消息:成功时返回成功提示,失败时返回具体错误信息 |
|
||||||
|
| orderId | String | "abbc4b57fb75" | 客户的订单号,与请求中的 orderId 一致 |
|
||||||
|
|
||||||
|
## 业务流程
|
||||||
|
|
||||||
|
### 支付信息更新流程
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 客户完成航班搜索(shopping/search)
|
||||||
|
↓
|
||||||
|
2. 客户选择航班并验价(shopping/select)
|
||||||
|
↓
|
||||||
|
3. 客户提交订单(booking/hold)→ 获取 orderId
|
||||||
|
↓
|
||||||
|
4. 客户选择支付方式,调用支付接口(booking/payment)
|
||||||
|
↓
|
||||||
|
5. 支付完成
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 为什么 orderId 是必填的?
|
||||||
|
|
||||||
|
orderId 是订单的唯一标识符,系统需要通过它来:
|
||||||
|
1. 定位到具体的订单
|
||||||
|
2. 验证订单是否属于当前客户(通过 clientCode)
|
||||||
|
3. 确保只有合法的订单才能更新支付信息
|
||||||
|
|
||||||
|
### paymentMethod 支持哪些支付方式?
|
||||||
|
|
||||||
|
系统支持三种支付方式:**BALANCE**(余额支付)、**CREDIT_CARD**(信用卡)、**APPLE_PAY**(Apple Pay,支持设备标签)。详见上方参数表格中的 paymentMethod 说明。
|
||||||
|
|
||||||
|
### Apple Pay 中的 deviceTag 是什么?
|
||||||
|
|
||||||
|
`deviceTag` 是设备标签,用于指定执行 Apple Pay 支付任务的设备:
|
||||||
|
- 仅在 `paymentMethod` 为 `APPLE_PAY` 时有效
|
||||||
|
- 可以指定有特定标签的设备执行任务
|
||||||
|
- 留空则系统自动分配可用设备
|
||||||
|
- 示例:`"deviceTag": "EUR"` 表示优先使用欧洲地区的设备
|
||||||
|
|
||||||
|
### 信用卡信息安全吗?
|
||||||
|
|
||||||
|
本接口仅用于记录支付信息到系统中。实际的支付处理通常由第三方支付网关完成,建议:
|
||||||
|
1. 在前端不要存储真实的完整信用卡号
|
||||||
|
2. 使用 PCI DSS 合规的支付网关处理实际支付
|
||||||
|
3. 仅存储支付网关返回的支付令牌(token)
|
||||||
|
|
||||||
|
### 如果订单不存在会怎样?
|
||||||
|
|
||||||
|
接口会返回 `code: 404` 和 `msg: "Booking not found"`。这种情况通常由以下原因造成:
|
||||||
|
1. orderId 错误或不存在
|
||||||
|
2. 订单属于其他客户(clientCode 不匹配)
|
||||||
|
3. 订单已过期或被删除
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 更新信用卡支付信息
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"paymentMethod": "CREDIT_CARD",
|
||||||
|
"creditCard": {
|
||||||
|
"number": "4111111111111111",
|
||||||
|
"CVV": "123",
|
||||||
|
"expiryMonth": "12",
|
||||||
|
"expiryYear": "25",
|
||||||
|
"lastName": "Doe",
|
||||||
|
"firstName": "John",
|
||||||
|
"country": "US"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Payment info updated successfully",
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 使用 Apple Pay 并指定设备标签
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"paymentMethod": "APPLE_PAY",
|
||||||
|
"deviceTag": "EUR"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Payment info updated successfully",
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 缺少 orderId 的错误请求
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"paymentMethod": "CREDIT_CARD"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"msg": "orderId is required"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 订单不存在的错误请求
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "nonexistent-order-id",
|
||||||
|
"paymentMethod": "CREDIT_CARD"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 404,
|
||||||
|
"msg": "Booking not found",
|
||||||
|
"orderId": "nonexistent-order-id"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
| 错误码 | 说明 | 处理建议 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 0 | 成功 | 支付信息已成功更新 |
|
||||||
|
| 400 | 请求参数错误 | 检查是否提供了必填的 orderId |
|
||||||
|
| 404 | 订单不存在 | 确认订单 ID 是否正确,且订单属于当前客户 |
|
||||||
|
| 500 | 服务器内部错误 | 系统处理异常,请稍后重试或联系技术支持 |
|
||||||
424
docs/04-03_booking-query.md
Normal file
424
docs/04-03_booking-query.md
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
<!-- mipuyun-api-doc: booking-query -->
|
||||||
|
# booking/query - 订单查询
|
||||||
|
|
||||||
|
# 订单查询(booking/query) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 查询订单的详细信息和当前状态
|
||||||
|
> 2. 在支付完成后查询订单确认状态
|
||||||
|
> 3. 在客服系统中查询订单详情
|
||||||
|
> 4. 获取订单的完整行程、乘客和费用信息
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 查询不存在的订单 ID
|
||||||
|
> 2. 查询不属于当前客户的订单(clientCode 不匹配)
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 500ms
|
||||||
|
> - 接口成功率:> 99.5%
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/booking/query |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| orderId | String | **是** | abbc4b57fb75 | 客户的订单号,用于查询订单详情 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
### 成功响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"requestId": "req-12345",
|
||||||
|
"agentCode": "u2web",
|
||||||
|
"status": "CONFIRMED",
|
||||||
|
"payStatus": "PAID",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"pnr": "ABC123",
|
||||||
|
"pnrExpiryTime": "2025-12-25T12:00:00Z",
|
||||||
|
"feeItems": {
|
||||||
|
"baseFare": 100.00,
|
||||||
|
"taxes": 50.50,
|
||||||
|
"total": 150.50,
|
||||||
|
"currency": "EUR"
|
||||||
|
},
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"lastName": "Rossi",
|
||||||
|
"firstName": "Mario",
|
||||||
|
"passengerType": "ADT",
|
||||||
|
"adult": true,
|
||||||
|
"child": false,
|
||||||
|
"infant": false,
|
||||||
|
"dateOfBirth": "1980-01-15",
|
||||||
|
"gender": "M",
|
||||||
|
"documentType": "PASSPORT",
|
||||||
|
"documentNumber": "AA1234567",
|
||||||
|
"ancillaries": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"airline": "AZ",
|
||||||
|
"flightNo": "AZ1234",
|
||||||
|
"dptAirport": "MIL",
|
||||||
|
"arrAirport": "CAG",
|
||||||
|
"dptTime": "2025-11-18T10:30:00Z",
|
||||||
|
"arrTime": "2025-11-18T12:15:00Z",
|
||||||
|
"equipment": "A320"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"credential": null,
|
||||||
|
"promoCode": "SAVE10",
|
||||||
|
"createTime": "2024-11-15T10:00:00Z",
|
||||||
|
"updateTime": "2024-11-15T10:30:00Z",
|
||||||
|
"retryCount": 3,
|
||||||
|
"retriedCount": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
本接口可能返回以下错误码:
|
||||||
|
|
||||||
|
| **错误码** | **错误名称** | **说明** | **处理建议** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 42005 | BOOKING_NOT_FOUND | 订单不存在 | 请检查 orderId 是否正确,或订单是否属于当前客户 |
|
||||||
|
| 41003 | PRICE_CHANGED | 票价高于预期 | 航司侧价格已变动,请检查响应中的 feeItems 获取最新价格,引导用户确认是否继续 |
|
||||||
|
|
||||||
|
### 失败响应
|
||||||
|
|
||||||
|
#### 订单不存在 (42005)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 42005,
|
||||||
|
"msg": "Booking not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 票价变动 (41003)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 41003,
|
||||||
|
"msg": "Price changed. Please check the latest price in feeItems.",
|
||||||
|
"data": {
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"feeItems": {
|
||||||
|
"baseFare": 110.00,
|
||||||
|
"taxes": 52.50,
|
||||||
|
"total": 162.50,
|
||||||
|
"currency": "EUR"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应字段说明
|
||||||
|
|
||||||
|
#### 基本字段
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| orderId | String | 客户的订单号 |
|
||||||
|
| requestId | String | 请求 ID |
|
||||||
|
| agentCode | String | 代理商代码 |
|
||||||
|
| status | String | 订单状态(见下方状态说明) |
|
||||||
|
| payStatus | String | 支付状态(见下方支付状态说明) |
|
||||||
|
| origin | String | 出发地 IATA 3 字码 |
|
||||||
|
| destination | String | 到达地 IATA 3 字码 |
|
||||||
|
| journeyType | String | 行程类型<br>**OW**:单程<br>**RT**:往返 |
|
||||||
|
|
||||||
|
#### PNR 相关
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| pnr | String | 航司 PNR 码(订座记录编号) |
|
||||||
|
| pnrExpiryTime | String | PNR 有效期,ISO 8601 格式(UTC 0 时区) |
|
||||||
|
|
||||||
|
#### 费用信息
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| feeItems | Map | 费用明细(原始 JSON 对象)<br>详见:[feeItems 实体定义](/api-doc?doc=entity-fee-items) |
|
||||||
|
|
||||||
|
#### 乘客和航班
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| passengers | Array\<BookingPassenger\> | 乘客信息列表(见 BookingPassenger 定义) |
|
||||||
|
| segments | Array\<BookingSegment\> | 航班段列表(见 BookingSegment 定义) |
|
||||||
|
|
||||||
|
#### 其他信息
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| credential | Object | 订单凭据信息 |
|
||||||
|
| promoCode | String | 促销码 |
|
||||||
|
| createTime | DateTime | 订单创建时间,ISO 8601 格式 |
|
||||||
|
| updateTime | DateTime | 订单最后更新时间,ISO 8601 格式 |
|
||||||
|
| retryCount | Integer | 可重试的次数 |
|
||||||
|
| retriedCount | Integer | 已经重试的次数 |
|
||||||
|
|
||||||
|
## 状态说明
|
||||||
|
|
||||||
|
### 订单状态 (status)
|
||||||
|
|
||||||
|
| **状态** | **说明** |
|
||||||
|
| --- | --- |
|
||||||
|
| PENDING | 订单处理中,等待航司确认 |
|
||||||
|
| CONFIRMED | 订单已确认,PNR 已生成 |
|
||||||
|
| CANCELLED | 订单已取消 |
|
||||||
|
| FAILED | 订单失败 |
|
||||||
|
|
||||||
|
### 支付状态 (payStatus)
|
||||||
|
|
||||||
|
| **状态** | **说明** |
|
||||||
|
| --- | --- |
|
||||||
|
| UNPAID | 未支付 |
|
||||||
|
| PENDING | 支付处理中 |
|
||||||
|
| PAID | 已支付 |
|
||||||
|
| REFUNDED | 已退款 |
|
||||||
|
| FAILED | 支付失败 |
|
||||||
|
|
||||||
|
## 数据来源说明
|
||||||
|
|
||||||
|
本接口返回的数据优先从 `responseJson` 字段解析,如果 `responseJson` 为空或解析失败(code 不是 0 且 feeItems/passengers/segments 均为空),则从 `holdResponse` 字段回退获取。
|
||||||
|
|
||||||
|
## 业务流程
|
||||||
|
|
||||||
|
### 订单查询场景
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 客户下单(booking/hold)→ 获取 orderId
|
||||||
|
↓
|
||||||
|
2. 客户选择支付方式并支付(booking/payment)
|
||||||
|
↓
|
||||||
|
3. 查询订单状态(booking/query)→ 确认订单状态
|
||||||
|
↓
|
||||||
|
4. 如需要,可以取消订单(booking/cancel)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 如果订单不存在会返回什么?
|
||||||
|
|
||||||
|
接口会返回错误响应,code 为 40401,msg 为 "Booking not found"。这种情况通常由以下原因造成:
|
||||||
|
1. orderId 错误或不存在
|
||||||
|
2. 订单属于其他客户(clientCode 不匹配)
|
||||||
|
3. 订单已过期或被删除
|
||||||
|
|
||||||
|
### status 和 payStatus 有什么区别?
|
||||||
|
|
||||||
|
- **status**:订单的整体状态(PENDING/CONFIRMED/CANCELLED/FAILED)
|
||||||
|
- **payStatus**:订单的支付状态(UNPAID/PENDING/PAID/REFUNDED/FAILED)
|
||||||
|
|
||||||
|
### feeItems 返回什么结构?
|
||||||
|
|
||||||
|
`feeItems` 是一个原始的 Map 对象,直接从航司响应的 JSON 中解析。
|
||||||
|
|
||||||
|
详细的字段说明请参考:[feeItems 实体定义](/api-doc?doc=entity-fee-items)
|
||||||
|
|
||||||
|
### passengers 和 segments 的详细定义是什么?
|
||||||
|
|
||||||
|
#### BookingPassenger(乘客信息)
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| lastName | String | 乘客姓 |
|
||||||
|
| firstName | String | 乘客名 |
|
||||||
|
| passengerType | String | 乘客类型(ADT/CHD/INF) |
|
||||||
|
| adult | Boolean | 是否为成人 |
|
||||||
|
| child | Boolean | 是否为儿童 |
|
||||||
|
| infant | Boolean | 是否为婴儿 |
|
||||||
|
| dateOfBirth | String | 出生日期 |
|
||||||
|
| gender | String | 性别(M/F) |
|
||||||
|
| documentType | String | 证件类型(如 PASSPORT) |
|
||||||
|
| documentNumber | String | 证件号码 |
|
||||||
|
| ancillaries | Array | 附加服务列表 |
|
||||||
|
|
||||||
|
#### BookingSegment(航班段信息)
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| airline | String | 航司代码(IATA 2 字码) |
|
||||||
|
| flightNo | String | 航班号(如 AZ1234) |
|
||||||
|
| dptAirport | String | 出发机场 IATA 3 字码 |
|
||||||
|
| arrAirport | String | 到达机场 IATA 3 字码 |
|
||||||
|
| dptTime | String | 出发时间,ISO 8601 格式 |
|
||||||
|
| arrTime | String | 到达时间,ISO 8601 格式 |
|
||||||
|
| equipment | String | 机型(如 A320、B737) |
|
||||||
|
|
||||||
|
### 什么时候会从 holdResponse 回退数据?
|
||||||
|
|
||||||
|
当 `responseJson` 满足以下任一条件时,会从 `holdResponse` 回退 feeItems/passengers/segments:
|
||||||
|
1. `responseJson` 为空
|
||||||
|
2. `responseJson` 解析失败
|
||||||
|
3. `code` 不是 0 且 feeItems/passengers/segments 均为空
|
||||||
|
|
||||||
|
这确保了即使订单最终状态失败,也能获取到 hold 阶段的数据。
|
||||||
|
|
||||||
|
### 遇到票价变动错误 (PRICE_CHANGED) 怎么办?
|
||||||
|
|
||||||
|
当接口返回错误码 41003 (PRICE_CHANGED) 时,表示航司侧票价高于预期。这种情况通常发生在:
|
||||||
|
|
||||||
|
1. 下单后到支付前,航司调整了票价
|
||||||
|
2. 库存紧张导致票价上涨
|
||||||
|
3. 促销活动价格已过期
|
||||||
|
|
||||||
|
**处理流程:**
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 接收到 41003 错误响应
|
||||||
|
↓
|
||||||
|
2. 从响应的 data.feeItems 中获取最新价格
|
||||||
|
↓
|
||||||
|
3. 向用户展示价格变动信息
|
||||||
|
↓
|
||||||
|
4. 询问用户是否继续
|
||||||
|
↓
|
||||||
|
5a. 用户同意 → 重新调用 booking/hold 使用新价格
|
||||||
|
↓
|
||||||
|
5b. 用户拒绝 → 取消订单流程
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键点:**
|
||||||
|
|
||||||
|
- 错误响应中的 `feeItems` 包含最新的价格明细
|
||||||
|
- 需要用户明确确认后才能继续交易
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 查询已确认的订单
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"agentCode": "u2web",
|
||||||
|
"status": "CONFIRMED",
|
||||||
|
"payStatus": "PAID",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"pnr": "ABC123",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"lastName": "Rossi",
|
||||||
|
"firstName": "Mario",
|
||||||
|
"passengerType": "ADT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"airline": "AZ",
|
||||||
|
"flightNo": "AZ1234",
|
||||||
|
"dptAirport": "MIL",
|
||||||
|
"arrAirport": "CAG",
|
||||||
|
"dptTime": "2025-11-18T10:30:00Z",
|
||||||
|
"arrTime": "2025-11-18T12:15:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"createTime": "2024-11-15T10:00:00Z",
|
||||||
|
"updateTime": "2024-11-15T10:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查询往返程订单
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "rt-order-12345"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "rt-order-12345",
|
||||||
|
"journeyType": "RT",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"status": "CONFIRMED",
|
||||||
|
"payStatus": "PAID",
|
||||||
|
"pnr": "XYZ789",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"lastName": "Rossi",
|
||||||
|
"firstName": "Mario",
|
||||||
|
"passengerType": "ADT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lastName": "Bianchi",
|
||||||
|
"firstName": "Luca",
|
||||||
|
"passengerType": "ADT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"airline": "AZ",
|
||||||
|
"flightNo": "AZ1234",
|
||||||
|
"dptAirport": "MIL",
|
||||||
|
"arrAirport": "CAG",
|
||||||
|
"dptTime": "2025-11-18T10:30:00Z",
|
||||||
|
"arrTime": "2025-11-18T12:15:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"airline": "AZ",
|
||||||
|
"flightNo": "AZ5678",
|
||||||
|
"dptAirport": "CAG",
|
||||||
|
"arrAirport": "MIL",
|
||||||
|
"dptTime": "2025-11-25T14:00:00Z",
|
||||||
|
"arrTime": "2025-11-25T15:45:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"createTime": "2024-11-15T10:00:00Z",
|
||||||
|
"updateTime": "2024-11-15T10:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
343
docs/04-04_booking-cancel.md
Normal file
343
docs/04-04_booking-cancel.md
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
<!-- mipuyun-api-doc: booking-cancel -->
|
||||||
|
# booking/cancel - 取消订单
|
||||||
|
|
||||||
|
# 取消订单(booking/cancel) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 客户主动取消未支付的订单
|
||||||
|
> 2. 客户因行程变更取消已确认的订单(需符合退改规则)
|
||||||
|
> 3. 系统自动取消过期未支付的订单
|
||||||
|
> 4. 客服代客取消订单
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 订单已不可取消(如已起飞航班)
|
||||||
|
> 1. 订单不属于当前客户(clientCode 不匹配)
|
||||||
|
> 1. 重复取消已取消的订单
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 2000ms
|
||||||
|
> - 接口成功率:> 95%
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/booking/cancel |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝。 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"cancelReason": "Customer request - flight change"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| orderId | String | **是** | abbc4b57fb75 | 客户的订单号,用于取消订单 |
|
||||||
|
| cancelReason | String | **是** | "Customer request" | 取消原因,用于记录和审计<br>**客户主动取消**:Customer request<br>**行程变更**:Flight change<br>**重复订单**:Duplicate booking<br>**支付超时**:Payment timeout<br>**其他**:Other reason |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
### 成功响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Booking cancelled successfully",
|
||||||
|
"historyId": 789
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 失败响应
|
||||||
|
|
||||||
|
#### 订单不存在
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 1,
|
||||||
|
"msg": "Failed to cancel booking"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应字段说明
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| code | Integer | 0 | 系统状态码<br>**0**:取消成功<br>**1**:取消失败 |
|
||||||
|
| msg | String | "Booking cancelled successfully" | 系统消息:成功或失败的详细信息 |
|
||||||
|
| historyId | Long | 789 | 历史记录 ID,用于追踪取消操作记录 |
|
||||||
|
|
||||||
|
## 业务流程
|
||||||
|
|
||||||
|
### 订单取消流程
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 客户下单(booking/hold)→ 获取 orderId
|
||||||
|
↓
|
||||||
|
2. 订单状态变化
|
||||||
|
├─ 未支付超时 → 系统自动取消
|
||||||
|
├─ 客户主动取消 → 调用取消接口
|
||||||
|
└─ 行程变更取消 → 调用取消接口
|
||||||
|
↓
|
||||||
|
3. 调用取消接口(booking/cancel)→ 提供取消原因
|
||||||
|
↓
|
||||||
|
4a. 成功:code=0,订单状态更新为 CANCELLED
|
||||||
|
↓
|
||||||
|
4b. 失败:code=1,返回错误信息
|
||||||
|
```
|
||||||
|
|
||||||
|
### 取消后状态变化
|
||||||
|
|
||||||
|
```
|
||||||
|
取消前:
|
||||||
|
- 状态:PENDING / CONFIRMED
|
||||||
|
- PNR:已生成(如已确认)
|
||||||
|
|
||||||
|
取消后:
|
||||||
|
- 状态:CANCELLED
|
||||||
|
- PNR:被航司释放
|
||||||
|
- 历史记录:保存取消操作记录
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 取消订单后可以恢复吗?
|
||||||
|
|
||||||
|
通常**不可以**。订单一旦取消:
|
||||||
|
1. PNR 被释放,座位被释放回库存
|
||||||
|
2. 如果需要恢复,需要重新下单
|
||||||
|
3. 某些航司可能支持恢复,但需要联系客服处理
|
||||||
|
|
||||||
|
### 哪些订单可以取消?
|
||||||
|
|
||||||
|
可以取消的订单:
|
||||||
|
1. **状态为 PENDING**:处理中的订单
|
||||||
|
2. **状态为 CONFIRMED**:已确认但未起飞的订单
|
||||||
|
3. **符合退改规则**:在退改规则允许的时间范围内
|
||||||
|
|
||||||
|
不可取消的订单:
|
||||||
|
1. **已起飞**:航班已经起飞
|
||||||
|
2. **已取消**:订单已经被取消过
|
||||||
|
3. **已使用**:乘客已办理登机
|
||||||
|
|
||||||
|
### cancelReason 有什么用?
|
||||||
|
|
||||||
|
cancelReason 用于:
|
||||||
|
1. **审计追踪**:记录取消原因,便于后续分析
|
||||||
|
2. **统计分析**:统计取消原因分布,优化产品
|
||||||
|
3. **客服支持**:客服可以查看取消原因
|
||||||
|
4. **退款处理**:根据取消原因判断是否退款及退款金额
|
||||||
|
|
||||||
|
### 取消成功后如何退款?
|
||||||
|
|
||||||
|
取消成功后:
|
||||||
|
1. 系统会自动触发退款流程
|
||||||
|
2. 退款金额根据**退改规则**和**取消时间**决定
|
||||||
|
3. 退款通常需要 3-7 个工作日到账
|
||||||
|
4. 可以通过 **booking/query** 查询退款状态
|
||||||
|
|
||||||
|
### 重复取消会怎样?
|
||||||
|
|
||||||
|
如果订单已经是 CANCELLED 状态:
|
||||||
|
1. 再次调用取消接口会返回失败(code=1)
|
||||||
|
2. 不会重复处理退款
|
||||||
|
3. 建议取消前先通过 **booking/query** 查询订单状态
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 客户主动取消订单
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"cancelReason": "Customer request - flight change"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Booking cancelled successfully",
|
||||||
|
"historyId": 789
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 行程变更取消订单
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"cancelReason": "Itinerary change - customer requested new dates"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Booking cancelled successfully",
|
||||||
|
"historyId": 790
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 重复订单取消
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"cancelReason": "Duplicate booking - same itinerary booked twice"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Booking cancelled successfully",
|
||||||
|
"historyId": 791
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 取消不存在的订单
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "nonexistent-order-id",
|
||||||
|
"cancelReason": "Test cancellation"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 1,
|
||||||
|
"msg": "Failed to cancel booking"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 取消原因建议
|
||||||
|
|
||||||
|
### 标准取消原因
|
||||||
|
|
||||||
|
| 场景 | 建议的 cancelReason | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 客户主动取消 | "Customer request" | 客户主动要求取消 |
|
||||||
|
| 行程变更 | "Flight change" | 客户需要更改行程 |
|
||||||
|
| 重复预订 | "Duplicate booking" | 同一航班重复预订 |
|
||||||
|
| 支付超时 | "Payment timeout" | 支付时间超过限制 |
|
||||||
|
| 价格问题 | "Price issue" | 客户认为价格不合理 |
|
||||||
|
| 个人原因 | "Personal reason" | 客户个人原因 |
|
||||||
|
| 系统错误 | "System error" | 系统导致的错误 |
|
||||||
|
| 其他原因 | "Other reason" | 其他未列出的原因 |
|
||||||
|
|
||||||
|
### 详细取消原因
|
||||||
|
|
||||||
|
建议在标准原因后添加详细说明:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"cancelReason": "Customer request - found better price elsewhere"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 取消最佳实践
|
||||||
|
|
||||||
|
### 1. 取消前先查询状态
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 1. 先查询订单状态
|
||||||
|
const order = await bookingQuery({ orderId: "xxx" });
|
||||||
|
|
||||||
|
// 2. 确认订单可以取消后再取消
|
||||||
|
if (order.status === "CONFIRMED" || order.status === "PENDING") {
|
||||||
|
const result = await bookingCancel({
|
||||||
|
orderId: "xxx",
|
||||||
|
cancelReason: "Customer request"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log("取消成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 记录取消原因
|
||||||
|
|
||||||
|
始终提供清晰、准确的取消原因:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cancelReason": "Customer request - passenger name change needed"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
而不是:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cancelReason": "Cancel"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 处理取消失败
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const result = await bookingCancel({
|
||||||
|
orderId: "xxx",
|
||||||
|
cancelReason: "Customer request"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.code !== 0) {
|
||||||
|
// 记录错误日志
|
||||||
|
console.error("取消失败:", result.msg);
|
||||||
|
|
||||||
|
// 联系客服处理
|
||||||
|
await contactSupport({
|
||||||
|
orderId: "xxx",
|
||||||
|
issue: "Cancel failed",
|
||||||
|
message: result.msg
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
### 常见错误及处理方式
|
||||||
|
|
||||||
|
| 错误场景 | code | msg | 处理建议 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 订单不存在 | 1 | "Failed to cancel booking" | 确认 orderId 是否正确 |
|
||||||
|
| 订单已取消 | 1 | "Failed to cancel booking" | 先查询订单状态 |
|
||||||
|
| 订单不可取消 | 1 | "Failed to cancel booking" | 检查退改规则和航班状态 |
|
||||||
|
| 系统错误 | 1 | "Failed to cancel booking" | 稍后重试或联系技术支持 |
|
||||||
342
docs/04-05_booking-retry.md
Normal file
342
docs/04-05_booking-retry.md
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
<!-- mipuyun-api-doc: booking-retry -->
|
||||||
|
# booking/retry - 订单重试
|
||||||
|
|
||||||
|
# 订单重试(booking/retry) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 当订单创建失败时,可以通过本接口重试订单
|
||||||
|
> 2. 用于自动或手动恢复失败的订单
|
||||||
|
> 3. 支持指定重试次数,避免无限重试
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 订单已成功时(status=CONFIRMED)不需要重试
|
||||||
|
> 1. 订单已取消时不能重试
|
||||||
|
> 1. 重试次数已达上限时继续重试
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 3000ms(包含重试处理时间)
|
||||||
|
> - 接口成功率:> 95%
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/booking/retry |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝。 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"retryCount": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值(默认值)** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| orderId | String | **是** | abbc4b57fb75 | 客户的订单号,用于重试失败的订单 |
|
||||||
|
| retryCount | Integer | 否 | 1 | 重试次数,用于追踪当前是第几次重试<br>**不提供**:系统将自动重试<br>**提供**:使用指定的重试次数 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
### 成功响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 12345,
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"returnDate": null,
|
||||||
|
"adults": 1,
|
||||||
|
"children": 0,
|
||||||
|
"infants": 0,
|
||||||
|
"status": "PENDING",
|
||||||
|
"pnr": null,
|
||||||
|
"pnrExpiryTime": null,
|
||||||
|
"agent": "u2web",
|
||||||
|
"outboundFareFamily": "promo",
|
||||||
|
"inboundFareFamily": null,
|
||||||
|
"totalPrice": 150.50,
|
||||||
|
"currency": "EUR",
|
||||||
|
"createTime": "20241115100000",
|
||||||
|
"updateTime": "20241115101500",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"firstName": "first",
|
||||||
|
"lastName": "last",
|
||||||
|
"passengerType": "ADT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contactInfo": {
|
||||||
|
"firstName": "san",
|
||||||
|
"lastName": "zhang",
|
||||||
|
"email": "san.zhang@gmail.com",
|
||||||
|
"phone": "0086-18912345678"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 失败响应
|
||||||
|
|
||||||
|
#### 订单不存在
|
||||||
|
```json
|
||||||
|
null
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应字段说明
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| id | Long | 12345 | 系统内部订单 ID(仅用于调试) |
|
||||||
|
| orderId | String | "abbc4b57fb75" | 客户的订单号 |
|
||||||
|
| journeyType | String | "OW" | 行程类型<br>**OW**:单程<br>**RT**:往返 |
|
||||||
|
| origin | String | "MIL" | 出发地 IATA 3 字码 |
|
||||||
|
| destination | String | "CAG" | 到达地 IATA 3 字码 |
|
||||||
|
| departureDate | String | "20251118" | 出发日期,格式 YYYYMMDD |
|
||||||
|
| returnDate | String/null | null | 返程日期,格式 YYYYMMDD(仅往返程有值) |
|
||||||
|
| adults | Integer | 1 | 成人数量 |
|
||||||
|
| children | Integer | 0 | 儿童数量 |
|
||||||
|
| infants | Integer | 0 | 婴儿数量 |
|
||||||
|
| status | String | "PENDING" | 订单状态<br>**PENDING**:处理中(重试中)<br>**CONFIRMED**:已确认<br>**FAILED**:失败 |
|
||||||
|
| pnr | String/null | null | 航司 PNR 码(订座记录编号),重试中可能为空 |
|
||||||
|
| pnrExpiryTime | String/null | null | PNR 有效期,格式 YYYYMMDDHHmmss(UTC 0 时区) |
|
||||||
|
| agent | String | "u2web" | Agent 代码 |
|
||||||
|
| outboundFareFamily | String | "promo" | 去程票价族 |
|
||||||
|
| inboundFareFamily | String/null | null | 回程票价族(仅往返程有值) |
|
||||||
|
| totalPrice | BigDecimal | 150.50 | 订单总价 |
|
||||||
|
| currency | String | "EUR" | 币种代码 |
|
||||||
|
| createTime | String | "20241115100000" | 订单创建时间,格式 YYYYMMDDHHmmss |
|
||||||
|
| updateTime | String | "20241115101500" | 订单最后更新时间,格式 YYYYMMDDHHmmss |
|
||||||
|
| passengers | Array<PassengerInfo> | | 乘客信息列表 |
|
||||||
|
| contactInfo | Object | | 联系人信息 |
|
||||||
|
|
||||||
|
## 业务流程
|
||||||
|
|
||||||
|
### 订单重试流程
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 客户下单(booking/hold)→ 订单创建失败
|
||||||
|
↓
|
||||||
|
2. 系统或客户检测到失败状态
|
||||||
|
↓
|
||||||
|
3. 调用重试接口(booking/retry)→ 指定 retryCount
|
||||||
|
↓
|
||||||
|
4. 系统重新处理订单
|
||||||
|
↓
|
||||||
|
5a. 成功:status=CONFIRMED,返回订单详情
|
||||||
|
↓
|
||||||
|
5b. 失败:status=FAILED,可以再次重试
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自动重试策略
|
||||||
|
|
||||||
|
建议的自动重试策略:
|
||||||
|
|
||||||
|
```
|
||||||
|
第 1 次重试(retryCount=1):立即重试
|
||||||
|
第 2 次重试(retryCount=2):等待 30 秒
|
||||||
|
第 3 次重试(retryCount=3):等待 60 秒
|
||||||
|
第 4 次重试(retryCount=4):等待 120 秒
|
||||||
|
超过 4 次:停止重试,联系客服
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 什么时候应该使用重试接口?
|
||||||
|
|
||||||
|
当订单状态为 **FAILED** 时,可以考虑使用重试接口:
|
||||||
|
1. 航司系统临时不可用
|
||||||
|
2. 网络超时
|
||||||
|
3. 航司返回临时错误
|
||||||
|
|
||||||
|
### retryCount 的作用是什么?
|
||||||
|
|
||||||
|
retryCount 用于:
|
||||||
|
1. **追踪重试次数**:记录当前是第几次重试
|
||||||
|
2. **防止无限重试**:可以设置最大重试次数上限
|
||||||
|
3. **系统监控**:用于监控重试频率和成功率
|
||||||
|
|
||||||
|
### 如果订单不存在会返回什么?
|
||||||
|
|
||||||
|
接口会返回 `null`。这种情况通常由以下原因造成:
|
||||||
|
1. orderId 错误或不存在
|
||||||
|
2. 订单属于其他客户(clientCode 不匹配)
|
||||||
|
|
||||||
|
### 重试后订单状态仍然是 FAILED 怎么办?
|
||||||
|
|
||||||
|
如果多次重试后仍然失败:
|
||||||
|
1. 检查错误信息和日志
|
||||||
|
2. 确认订单参数是否正确
|
||||||
|
3. 检查航司系统是否正常
|
||||||
|
4. 联系技术支持
|
||||||
|
|
||||||
|
### 可以重试已确认的订单吗?
|
||||||
|
|
||||||
|
不建议。如果订单状态已经是 **CONFIRMED**,重试没有意义。建议先调用 **booking/query** 查询订单状态,确认订单确实失败后再重试。
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 第 1 次重试失败的订单
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"retryCount": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 12345,
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"journeyType": "OW",
|
||||||
|
"origin": "MIL",
|
||||||
|
"destination": "CAG",
|
||||||
|
"departureDate": "20251118",
|
||||||
|
"adults": 1,
|
||||||
|
"status": "PENDING",
|
||||||
|
"pnr": null,
|
||||||
|
"totalPrice": 150.50,
|
||||||
|
"currency": "EUR",
|
||||||
|
"createTime": "20241115100000",
|
||||||
|
"updateTime": "20241115101500"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第 2 次重试(等待后)
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"retryCount": 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 12345,
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"status": "CONFIRMED",
|
||||||
|
"pnr": "ABC123",
|
||||||
|
"pnrExpiryTime": "20251225120000",
|
||||||
|
"updateTime": "20241115102000"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 重试不存在的订单
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "nonexistent-order-id",
|
||||||
|
"retryCount": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
null
|
||||||
|
```
|
||||||
|
|
||||||
|
### 不指定 retryCount 的重试
|
||||||
|
|
||||||
|
#### 请求(Request)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应(Response)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"status": "PENDING",
|
||||||
|
"updateTime": "20241115103000"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明**:不提供 retryCount 时,系统将自动管理重试次数。
|
||||||
|
|
||||||
|
## 重试最佳实践
|
||||||
|
|
||||||
|
### 1. 指数退避策略
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"retryCount": 1,
|
||||||
|
"waitTime": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
→ 失败后立即重试
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"retryCount": 2,
|
||||||
|
"waitTime": 30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
→ 失败后等待 30 秒
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"retryCount": 3,
|
||||||
|
"waitTime": 60
|
||||||
|
}
|
||||||
|
```
|
||||||
|
→ 失败后等待 60 秒
|
||||||
|
|
||||||
|
### 2. 最大重试次数限制
|
||||||
|
|
||||||
|
建议设置最大重试次数为 **3-5 次**,超过后:
|
||||||
|
- 停止自动重试
|
||||||
|
- 通知客服介入
|
||||||
|
- 记录错误日志
|
||||||
|
|
||||||
|
### 3. 重试前先查询状态
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 1. 先查询订单状态
|
||||||
|
const order = await bookingQuery({ orderId: "xxx" });
|
||||||
|
|
||||||
|
// 2. 确认订单失败后再重试
|
||||||
|
if (order.status === "FAILED") {
|
||||||
|
await bookingRetry({
|
||||||
|
orderId: "xxx",
|
||||||
|
retryCount: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
23
docs/07-01_flight-segment-request.md
Normal file
23
docs/07-01_flight-segment-request.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!-- mipuyun-api-doc: flight-segment-request -->
|
||||||
|
# FlightSegmentRequest
|
||||||
|
|
||||||
|
# FlightSegmentRequest对象定义
|
||||||
|
|
||||||
|
Segment 对象用于描述单段航班的核心信息(告知我们定位到具体的行程),定义如下:
|
||||||
|
|
||||||
|
| **字段名** | **数据类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| carrier | String | "VJ" | 承运航司 IATA 二字码(如 VJ = 越南航空),**与 flightNumber 前缀的航司码一致**(示例中 flightNumber="VJ884",carrier="VJ" 符合规则) |
|
||||||
|
| flightNumber | String | "VJ884" | 航班号,格式为 "航司二字码 + 数字": |
|
||||||
|
| originAirport | String | "BOM" / "SGN" | 出发机场 IATA 三字码(如 BOM = 孟买贾特拉帕蒂・希瓦吉国际机场,SGN = 胡志明市新山一国际机场) |
|
||||||
|
| destinationAirport | String | "SGN" / "SYD" | 到达机场 IATA 三字码(如 SYD = 悉尼金斯福德・史密斯机场) |
|
||||||
|
| stopCities | String | "CDG/MAD" | 经停地城市三字码,多个城市用 `/` 分隔(可选字段,用于支持包含经停点的航班查询) |
|
||||||
|
| departureDate | String | "20251027" | 起飞日期日期,固定格式 `YYYYMMDD`(20251027表示 2025 年 10 月 27 日) |
|
||||||
|
|
||||||
|
# 备注
|
||||||
|
|
||||||
|
1. **请求体内的旅行时间是departureDate,不同于响应体的departureTime**:原因是航司会出现出发时间的调整,为了保障成功率,请求只需要告知日期即可。
|
||||||
|
1. 本实体兼容FlightSegmentResponse, 你可以把shopping/search中获得实体直接引用。
|
||||||
|
1. 如入参为departureTime,我们会抛弃时间,只采用日期。
|
||||||
|
1. **stopCities 为可选字段**,仅在航班包含经停点时需要填写。格式为多个城市三字码用 `/` 分隔,例如 "CDG/MAD" 表示经停巴黎和马德里。
|
||||||
|
|
||||||
24
docs/07-02_passenger.md
Normal file
24
docs/07-02_passenger.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<!-- mipuyun-api-doc: passenger -->
|
||||||
|
# Passenger
|
||||||
|
|
||||||
|
# Passenger 实体定义
|
||||||
|
|
||||||
|
Passenger 实体用于描述航班预订中单个乘客的核心信息,包括身份信息、证件信息、常旅客信息及附加服务选择,是订单创建、值机办理等流程的关键数据依据。
|
||||||
|
|
||||||
|
| **字段名** | **数据类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| firstName | String | San | 乘客名,需与证件名完全一致,国际航司不可填入中文 |
|
||||||
|
| lastName | String | Zhang | 乘客姓,需与证件姓完全一致,国际航司不可填入中文 |
|
||||||
|
| passengerType | String | "ADT"、"CHD"、"INF" | 乘客类型,固定枚举值,用于区分票价规则与服务权益:- "ADT" = 成人(Adult,通常指 12 周岁及以上乘客)- "CHD" = 儿童(Child,通常指 2-11 周岁乘客,需单独购票,部分航司可享折扣)- "INF" = 婴儿(Infant,通常指 2 周岁以下乘客,需与成人乘客绑定预订,票价规则特殊) |
|
||||||
|
| dateOfBirth | String | "20251017" | 乘客出生日期,固定格式为 **YYYYMMDD**(如 "20180520" 表示 2018 年 5 月 20 日) |
|
||||||
|
| gender | String | "M"、"F" | 乘客性别,固定枚举值:- "M" = 男(Male)- "F" = 女(Female) |
|
||||||
|
| documentNumber | String | "E12345678" | 证件号码,需与证件类型(documentType)匹配 |
|
||||||
|
| documentType | String | "PP"、"ID" | 证件类型,固定枚举值,需与航司支持的证件类型一致:- "PP" = 护照(Passport),国际航班必填- "ID" = 身份证(Identity Card) |
|
||||||
|
| documentIssuePlace | String | "CN"、"US" | 证件签发国家 / 地区代码,遵循 **ISO 3166-1 alpha-2** 标准(2 位字母编码):- "CN" = 中国内地- "US" = 美国 |
|
||||||
|
| documentExpirationDate | String | "20281030" | 证件有效期截止日期,固定格式为 **YYYYMMDD**(如 "20301231" 表示 2030 年 12 月 31 日),需满足 “有效期截止日期> 航班返程日期”(单程航班需满足 “> 出发日期”),否则会导致预订失败 |
|
||||||
|
| nationality | String | "CN"、"US" | 乘客国籍代码,遵循 **ISO 3166-1 alpha-2** 标准,与乘客护照 / 身份证上的国籍信息一致,用于航司核验出入境资格,不可为空 |
|
||||||
|
| mobile | String | 0086-13200112233 | 乘客手机号码注意格式采用xxxx-xxxxxxxxxxx前面4位为国家码。 |
|
||||||
|
| frequentFlyerCarrier | String | "CA"、"MU" | 常旅客所属航司代码,遵循 IATA 二字码标准,需与 ffpCardNo 对应的航司一致:- "CA" = 中国国际航空- "MU" = 中国东方航空无会员卡时填写 null,非必选 |
|
||||||
|
| frequentFlyerNumber | String | "CA1234567890" | 常旅客卡号(Frequent Flyer Program Card Number),即乘客在某航司的会员卡编号(如国航 “凤凰知音” 卡号 "CA1234567890"),无会员卡时填写 null,非必选 |
|
||||||
|
| ancillaries | Array | Ancillary | 复用shopping/baggage中的行李响应字段,详见 [Ancillary 实体定义](07-04_ancillary.md) |
|
||||||
|
|
||||||
37
docs/07-03_contact-info.md
Normal file
37
docs/07-03_contact-info.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<!-- mipuyun-api-doc: contact-info -->
|
||||||
|
# ContanctInfo
|
||||||
|
|
||||||
|
# ContactInfo 实体定义
|
||||||
|
|
||||||
|
Contact 实体用于描述航班订单的联系人信息,是航司与用户沟通的核心渠道,用于发送订单确认通知、电子行程单、航班变动提醒等关键信息。
|
||||||
|
|
||||||
|
```objective-c
|
||||||
|
"contactInfo": {
|
||||||
|
"firstName": "san",
|
||||||
|
"lastName": "zhang",
|
||||||
|
"address": "dfdsaqqq",
|
||||||
|
"phoneCountryCode": "0086",
|
||||||
|
"phone": "18912345678",
|
||||||
|
"email": "san.zhang@gmail.com",
|
||||||
|
"postCode": "310006",
|
||||||
|
"city": "hangzhou",
|
||||||
|
"province": "zejiang",
|
||||||
|
"country": "CN"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| **字段名** | **数据类型** | 是否必选 | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| firstName | String | 是 | San | 乘客名,需与证件名完全一致,国际航司不可填入中文 |
|
||||||
|
| lastName | String | 是 | Zhang | 乘客姓,需与证件姓完全一致,国际航司不可填入中文 |
|
||||||
|
| address | String | 否 | No. 88 Jianguo Road, Chaoyang District, Beijing | 联系人详细地址,用英语(字母)填写。是否必选取决于航司是否需要这个信息。 |
|
||||||
|
| phoneCountryCode | String | 是 | 0086 | 国家码 |
|
||||||
|
| phone | String | 是 | 18912345678 | 联系电话号码 |
|
||||||
|
| postcode | String | 否 | "100022" | 联系人地址对应的邮编(邮政编码)是否必选取决于航司是否需要这个信息。 |
|
||||||
|
| email | String | 是 | "name@emaildomain.com" | 联系人邮箱地址,需符合标准邮箱格式(如 "用户名 @域名"),用于接收电子行程单(ETicket)、订单确认邮件、航班变动通知,是订单关键凭证的主要发送渠道,不可为空且需确保邮箱可正常接收邮件 |
|
||||||
|
| city | String | 否 | hangzhou | 联系地址城市 |
|
||||||
|
| province | String | 否 | zhejiang | 联系地址省/州 |
|
||||||
|
| country | String | 否 | CN | 联系地址国家码 |
|
||||||
|
|
||||||
174
docs/07-04_ancillary.md
Normal file
174
docs/07-04_ancillary.md
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<!-- mipuyun-api-doc: ancillary -->
|
||||||
|
# Ancillary
|
||||||
|
|
||||||
|
# Ancillary 实体定义
|
||||||
|
|
||||||
|
## 重要约定
|
||||||
|
|
||||||
|
| **字段名** | **数据类型** | **示例值** | **说明** |
|
||||||
|
|------------------| --- | --- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| journeyDirection | String | outbound | **行程方向**:- outbound: 去程- inbound: 回程<br>**用途**:区分往返行程的去程和回程方向 |
|
||||||
|
| categoryCode | String | StandardCheckedBaggage | 值举例:<BR> - 托运行李:StandardCheckedBaggage <BR> - 随身行李:CabinBaggageOverheadLocker <BR> - 选座产品:Seat |
|
||||||
|
| productCode | String | SCI_BAG_20KG | 值举例:<BR> - 托运行李:SCI_BAG_20KG <BR> - 随身行李:CBOL_BAG_15KG <BR> - 选座产品:SEAT_16A |
|
||||||
|
| price | Number | 21.22 | 预计采购价格,选填 |
|
||||||
|
| currency | String | USD | 预计采购价对应的货币,选填 |
|
||||||
|
| baggage | Object | {"piece":0,"weight":20,"size":"","allWeight":true} | 行李附加信息:仅当行李类产品时非空,描述行李的重量、件数等属性 |
|
||||||
|
| ├─ piece | Integer | 1 | 行李最多件数:1:最多限一件2:最多限两件 |
|
||||||
|
| ├─ weight | Integer | 20 | 行李总重量限制:单位为公斤(KG),允许的行李总总量。20表示为:20KG |
|
||||||
|
| ├─ size | String | "" | 行李尺寸限制:格式为 "长*宽*高"(如 "56*36***23cm"),空字符串表示无特殊尺寸限制(需遵循航司通用规则) |
|
||||||
|
| seat | Object | {"segmentIndex":1,"row":"12","column":"A"} | 座位附加信息:仅当`categoryCode=Seat`(座位类产品)时非空,描述座位的位置信息 |
|
||||||
|
| ├─ segmentIndex | Integer | 1 | **航段序号**:从 1 开始,在整个行程中连续编号<br>• 单程(OW):去程从 1 开始<br>• 往返(RT):去程从 1 开始,**回程 = 去程航段数 + 1**<br>**示例**:<br>- 单程直飞:segmentIndex=1<br>- 单程2段转机:segmentIndex=1, 2<br>- 往返直飞:去程 segmentIndex=1,回程 segmentIndex=2<br>- 往返2段转机:去程 segmentIndex=1,2,回程 segmentIndex=3,4 |
|
||||||
|
| ├─ row | String | "12" | 座位行号:标识座位所在的行(如 "12" 表示第12排) |
|
||||||
|
| ├─ column | String | "A" | 座位列号:标识座位所在的列(如 "A"、"B"、"C" 等) |
|
||||||
|
|
||||||
|
# 二、行李与选座的行程处理规则
|
||||||
|
|
||||||
|
## 1. segmentIndex 的计算规则
|
||||||
|
|
||||||
|
**重要**:seat 对象中的 `segmentIndex` 在整个行程中**连续编号**,不是每个方向重新从 1 开始。
|
||||||
|
|
||||||
|
**计算规则:**
|
||||||
|
- **单程(OW)**:去程从 1 开始连续编号
|
||||||
|
- 直飞:segmentIndex = 1
|
||||||
|
- 2段转机:segmentIndex = 1, 2
|
||||||
|
- 3段转机:segmentIndex = 1, 2, 3
|
||||||
|
|
||||||
|
- **往返(RT)**:去程从 1 开始,回程紧接去程的编号
|
||||||
|
- 往返直飞:去程 segmentIndex = 1,回程 segmentIndex = 2
|
||||||
|
- 去程2段+回程1段:去程 segmentIndex = 1, 2,回程 segmentIndex = 3
|
||||||
|
- 去程2段+回程2段:去程 segmentIndex = 1, 2,回程 segmentIndex = 3, 4
|
||||||
|
|
||||||
|
**计算公式:**
|
||||||
|
- 去程第 N 段:segmentIndex = N
|
||||||
|
- 回程第 M 段:segmentIndex = 去程航段数 + M
|
||||||
|
|
||||||
|
## 2. 往返行程的区分
|
||||||
|
|
||||||
|
往返行程通过 `journeyDirection` 字段来区分:
|
||||||
|
- **outbound**:去程
|
||||||
|
- **inbound**:回程
|
||||||
|
|
||||||
|
对于选座产品(`categoryCode=Seat`),每个座位通过 `segmentIndex` 标识其对应的航段。
|
||||||
|
|
||||||
|
## 3. 行李产品的特殊规则
|
||||||
|
|
||||||
|
### 转机行程的行李规格要求
|
||||||
|
|
||||||
|
在单向的转机行程中(即同一个 `journeyDirection` 下有多个航段),行李规格(重量、件数)**必须保持一致**。
|
||||||
|
|
||||||
|
### 规则说明
|
||||||
|
|
||||||
|
- 如果去程有3个航段(BOM→SGN→SYD→MEL),整个去程购买的行李规格必须相同
|
||||||
|
- 例如:不能第1段购买20KG,第2段购买25KG
|
||||||
|
- 必须所有航段都购买20KG,或都购买25KG
|
||||||
|
|
||||||
|
### 为什么需要相同规格?
|
||||||
|
|
||||||
|
- 转机时行李会自动转运到下一航段,不需要重新托运
|
||||||
|
- 航司系统要求整个行程使用相同的行李规格,以确保行李正常转运
|
||||||
|
|
||||||
|
### 往返行程的行李
|
||||||
|
|
||||||
|
- 去程和回程(不同的 `journeyDirection`)可以购买不同规格的行李
|
||||||
|
- 例如:去程购买20KG,回程购买25KG是允许的
|
||||||
|
|
||||||
|
## 4. 选座产品的特殊规则
|
||||||
|
|
||||||
|
### 每个航段独立选座
|
||||||
|
|
||||||
|
与行李不同,选座是**每个航段独立进行的**。
|
||||||
|
|
||||||
|
### 规则说明
|
||||||
|
|
||||||
|
- 每个航段都需要单独选择座位(通过 seat 对象中的 segmentIndex 区分)
|
||||||
|
- 即使是转机行程,不同航段可以选择不同的座位
|
||||||
|
- 例如:第1段选 12A,第2段选 15F
|
||||||
|
|
||||||
|
### 为什么需要独立选座?
|
||||||
|
|
||||||
|
- 每个航段的航班座位图不同
|
||||||
|
- 机型、座位布局可能不同
|
||||||
|
- 乘客可能希望在不同航段选择不同位置(如去程靠窗,回程靠过道)
|
||||||
|
|
||||||
|
### 选座对象中的字段
|
||||||
|
|
||||||
|
- `segmentIndex`:标识选座对应的航段(seat 专用字段)
|
||||||
|
- `row`:座位行号(如 "12")
|
||||||
|
- `column`:座位列号(如 "A"、"F")
|
||||||
|
|
||||||
|
**示例 - 转机行程选座:**
|
||||||
|
|
||||||
|
往返直飞(去程1段+回程1段):
|
||||||
|
```json
|
||||||
|
// 去程座位
|
||||||
|
{
|
||||||
|
"categoryCode": "Seat",
|
||||||
|
"productCode": "SEAT_12A",
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"seat": {
|
||||||
|
"segmentIndex": 1,
|
||||||
|
"row": "12",
|
||||||
|
"column": "A"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 回程座位
|
||||||
|
{
|
||||||
|
"categoryCode": "Seat",
|
||||||
|
"productCode": "SEAT_8F",
|
||||||
|
"journeyDirection": "inbound",
|
||||||
|
"seat": {
|
||||||
|
"segmentIndex": 2,
|
||||||
|
"row": "8",
|
||||||
|
"column": "F"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
往返转机(去程2段+回程2段):
|
||||||
|
```json
|
||||||
|
// 去程第1段座位
|
||||||
|
{
|
||||||
|
"categoryCode": "Seat",
|
||||||
|
"productCode": "SEAT_12A",
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"seat": {
|
||||||
|
"segmentIndex": 1,
|
||||||
|
"row": "12",
|
||||||
|
"column": "A"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 去程第2段座位
|
||||||
|
{
|
||||||
|
"categoryCode": "Seat",
|
||||||
|
"productCode": "SEAT_15F",
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"seat": {
|
||||||
|
"segmentIndex": 2,
|
||||||
|
"row": "15",
|
||||||
|
"column": "F"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 回程第1段座位(segmentIndex = 去程航段数 + 1 = 3)
|
||||||
|
{
|
||||||
|
"categoryCode": "Seat",
|
||||||
|
"productCode": "SEAT_8A",
|
||||||
|
"journeyDirection": "inbound",
|
||||||
|
"seat": {
|
||||||
|
"segmentIndex": 3,
|
||||||
|
"row": "8",
|
||||||
|
"column": "A"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 回程第2段座位(segmentIndex = 去程航段数 + 2 = 4)
|
||||||
|
{
|
||||||
|
"categoryCode": "Seat",
|
||||||
|
"productCode": "SEAT_10F",
|
||||||
|
"journeyDirection": "inbound",
|
||||||
|
"seat": {
|
||||||
|
"segmentIndex": 4,
|
||||||
|
"row": "10",
|
||||||
|
"column": "F"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
76
docs/08-01_itinerary.md
Normal file
76
docs/08-01_itinerary.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!-- mipuyun-api-doc: itinerary -->
|
||||||
|
# Itinerary - 行程实体对象
|
||||||
|
|
||||||
|
Itinerary 实体(行程组合信息,与实际响应字段一致)
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **说明** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| outboundSegments | Array<[SegmentElement](08-03_segment-element.md)> | 去程航段列表:单程(OW)和往返(RT)场景均返回,按行程顺序排列 |
|
||||||
|
| inboundSegments | Array<[SegmentElement](08-03_segment-element.md)> | 返程航段列表:仅往返(RT)场景返回,字段含义同 outboundSegments;单程(OW)场景为空数组 |
|
||||||
|
| fares | Array<[FlightFare](08-02_flight-fare.md)> | 该行程下的可选票价方案列表,每个方案包含去程/回程的票价、税费、座位数、舱位类型及航班政策信息 |
|
||||||
|
|
||||||
|
## 实体轮廓
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"outboundSegments": [
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"carrier": "VJ",
|
||||||
|
"flightNumber": "VJ884",
|
||||||
|
"operatingCarrier": "",
|
||||||
|
"operatingFlightnumber": "",
|
||||||
|
"originAirport": "BOM",
|
||||||
|
"destinationAirport": "SGN",
|
||||||
|
"departureTime": "202510270040",
|
||||||
|
"arrivalTime": "202510270705",
|
||||||
|
"departureTerminal": "",
|
||||||
|
"arrivalTerminal": "",
|
||||||
|
"stopCities": "",
|
||||||
|
"duration": 295,
|
||||||
|
"aircraftCode": "330",
|
||||||
|
"codeShare": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inboundSegments": [
|
||||||
|
{
|
||||||
|
// 同 outboundSegments 结构
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fares": [
|
||||||
|
{
|
||||||
|
"fareBasis": "",
|
||||||
|
"rtnFareBasis": "",
|
||||||
|
"fareFamily": "Lion Economy",
|
||||||
|
"rtnFareFamily": "Lion Promo",
|
||||||
|
"currency": "USD",
|
||||||
|
"bookingCode": "Y,Y",
|
||||||
|
"rtnBookingCode": "Y,Y",
|
||||||
|
"availableSeats": 7,
|
||||||
|
"rtnAvailableSeats": 2,
|
||||||
|
"flightPolicy": {
|
||||||
|
"airlineCode": "SL",
|
||||||
|
"fareFamilyType": "Lion Economy",
|
||||||
|
"description": "",
|
||||||
|
"freeAncillaryList": [
|
||||||
|
{
|
||||||
|
"categoryCode": "CabinBaggageOverheadLocker",
|
||||||
|
"segmentIndex": 1,
|
||||||
|
"paxType": "ADT",
|
||||||
|
"piece": 1,
|
||||||
|
"weight": 7,
|
||||||
|
"size": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refundRules": [], // 预留字段,暂未提供
|
||||||
|
"changeRules": [] // 预留字段,暂未提供
|
||||||
|
},
|
||||||
|
"rtnFlightPolicy": {
|
||||||
|
// 同 flightPolicy 结构
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> `RuleElement` 结构详见 [FlightPolicy](08-04_flight-policy.md)
|
||||||
32
docs/08-02_flight-fare.md
Normal file
32
docs/08-02_flight-fare.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<!-- mipuyun-api-doc: flight-fare -->
|
||||||
|
# FlightFare
|
||||||
|
|
||||||
|
FlightFare 实体用于描述不同乘客类型(成人 / 儿童 / 婴儿)的费用构成,拆分基础票价与税费等明细项,同时包含去程和返程的价格、政策信息,字段与实际响应完全对应。
|
||||||
|
|
||||||
|
> **说明**:带 `rtn` 前缀的字段为回程字段,仅往返程有值。
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| fareBasis | String | | 去 fareBasis 信息(如有) |
|
||||||
|
| rtnFareBasis | String | | 回程 fareBasis 信息(如有) |
|
||||||
|
| fareFamily | String | "Lion Economy" | 去程票价舱/产品类型名称 |
|
||||||
|
| rtnFareFamily | String | "Lion Promo" | 回程票价舱/产品类型名称 |
|
||||||
|
| currency | String | "USD" | 币种编码,遵循 ISO 4217 标准(如 USD = 美元,CNY = 人民币) |
|
||||||
|
| adultFare | BigDecimal | 6115.00 | 去程成人票价(不含税) |
|
||||||
|
| rtnAdultFare | BigDecimal | 6100.00 | 回程成人票价(不含税) |
|
||||||
|
| adultTax | BigDecimal | 13714.00 | 去程成人税费 |
|
||||||
|
| rtnAdultTax | BigDecimal | 8540.00 | 回程成人税费 |
|
||||||
|
| childFare | BigDecimal | 0.00 | 去程儿童票价(不含税),儿童定义为 2-12 周岁 |
|
||||||
|
| rtnChildFare | BigDecimal | 0.00 | 回程儿童票价(不含税) |
|
||||||
|
| childTax | BigDecimal | 0.00 | 去程儿童税费 |
|
||||||
|
| rtnChildTax | BigDecimal | 0.00 | 回程儿童税费 |
|
||||||
|
| infantFare | BigDecimal | 0.00 | 去程婴儿票价(不含税),婴儿定义为 0-2 周岁(无独立座位) |
|
||||||
|
| rtnInfantFare | BigDecimal | 0.00 | 回程婴儿票价(不含税) |
|
||||||
|
| infantTax | BigDecimal | 0.00 | 去程婴儿税费 |
|
||||||
|
| rtnInfantTax | BigDecimal | 0.00 | 回程婴儿税费 |
|
||||||
|
| bookingCode | String | "Y,Y" | 去程舱位代码(如 Y、B、M、W 等),廉航领域不一定存在,可通过系统设置-参数设置-默认舱位编码指定默认值。<br>**格式说明**:<br>- 单程直飞:单个代码,如 `"Y"`<br>- 单程转机:逗号分隔多段,如 `"B,Y"` 表示第一段 B 舱,第二段 Y 舱 |
|
||||||
|
| rtnBookingCode | String | "Y,Y" | 回程舱位代码(如 Y、B、M、W 等),廉航领域不一定存在。<br>**格式说明**:同 bookingCode,单段为单个代码,多段用逗号分隔 |
|
||||||
|
| availableSeats | int | 7 | 去程剩余座位数 |
|
||||||
|
| rtnAvailableSeats | int | 2 | 回程剩余座位数 |
|
||||||
|
| flightPolicy | [FlightPolicy](08-04_flight-policy.md) | | 去程航班政策(包含去程免费行李额、退改规则等) |
|
||||||
|
| rtnFlightPolicy | [FlightPolicy](08-04_flight-policy.md) | | 回程航班政策(包含回程免费行李额、退改规则等) |
|
||||||
30
docs/08-03_segment-element.md
Normal file
30
docs/08-03_segment-element.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<!-- mipuyun-api-doc: segment-element -->
|
||||||
|
# FlightSegmentResponse
|
||||||
|
|
||||||
|
# FlightSegment 对象定义
|
||||||
|
|
||||||
|
Segment 对象用于描述单段航班的核心信息(如在搜索结果中的去程航段 `outboundSegments`、返程航段 `inboundSegments`),具体定义如下:
|
||||||
|
|
||||||
|
| **字段名** | **数据类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| index | Integer | 1 / 2 | 航段序号,按行程顺序递增(一般用于转机行程,第一段去程为 1,第二段去程为 2),非空且唯一 |
|
||||||
|
| carrier | String | "VJ" | 承运航司 IATA 二字码(如 VJ = 越南航空),**与 flightNumber 前缀的航司码一致**(示例中 flightNumber="VJ884",carrier="VJ" 符合规则) |
|
||||||
|
| flightNumber | String | "VJ884" | 航班号,格式为 “航司二字码 + 数字”: |
|
||||||
|
| operatingFlightnumber | String | "" | 实际承运航班号:- 代码共享航班时,填写实际承运航司的航班号- 非代码共享航班时,空字符串或与 flightNumber 一致(示例中为非代码共享,故为空) |
|
||||||
|
| operatingCarrier | String | "" | 实际承运航司 IATA 二字码:- 代码共享航班(codeShare=true)时,需填写实际承运航司(如 carrier="CA",operatingCarrier="MU")- 非代码共享航班(codeShare=false)时,空字符串或与 carrier 一致(示例中为非代码共享,故为空) |
|
||||||
|
| originAirport | String | "BOM" / "SGN" | 出发机场 IATA 三字码(如 BOM = 孟买贾特拉帕蒂・希瓦吉国际机场,SGN = 胡志明市新山一国际机场) |
|
||||||
|
| departureTime | String | "202510270040" | 起飞日期时间,固定格式 `YYYYMMDDHHMM`(202510270040 表示 2025 年 10 月 27 日 00:40) |
|
||||||
|
| destinationAirport | String | "SGN" / "SYD" | 到达机场 IATA 三字码(如 SYD = 悉尼金斯福德・史密斯机场) |
|
||||||
|
| arrivalTime | String | "202510270705" | 到达日期时间,格式同 depTime(202510280805 表示 2025 年 10 月 28 日 08:05) |
|
||||||
|
| stopCities | String | "" | 经停地,空字符串表示直飞 |
|
||||||
|
| duration | int | 295 / 515 | 飞行时长,单位为分钟(295 分钟 = 4 小时 55 分钟,515 分钟 = 8 小时 35 分钟) |
|
||||||
|
| codeShare | boolean | false | 代码共享标识:- true = 代码共享航班(由其他航司实际承运)- false = 非代码共享航班(由 carrier 航司直接承运) |
|
||||||
|
| cabin | String | "" | 舱位等级代码(如 "Y"= 经济舱、"C"= 公务舱),空字符串表示未明确具体舱位代码 |
|
||||||
|
| aircraftCode | String | "330" | 机型编码(如 "330"= 空客 A330,"738"= 波音 737-800),用于标识执飞客机型号 |
|
||||||
|
| departureTerminal | String | "T1" | 起飞机场航站楼(如 "T2"=2 号航站楼),空字符串表示未明确航站楼信息(需以机场实时通知为准) |
|
||||||
|
| arrivalTerminal | String | "T1" | 到达机场航站楼,规则同 departureTerminal |
|
||||||
|
|
||||||
|
# 特殊业务规则备注
|
||||||
|
|
||||||
|
1. **航班号前 0 规则**:响应体内的航班号会按照航司接口中获取数据原样返回,请注意处理是否带0的情况。
|
||||||
|
|
||||||
43
docs/08-04_flight-policy.md
Normal file
43
docs/08-04_flight-policy.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<!-- mipuyun-api-doc: flight-policy -->
|
||||||
|
# FlightPolicy
|
||||||
|
|
||||||
|
# FlightPolicy 实体定义(基于实际响应)
|
||||||
|
|
||||||
|
该实体用于描述航班的附加产品信息(如免费行李额、退改规则等),字段与最新响应数据完全对齐。
|
||||||
|
|
||||||
|
> **注意**:去程和回程的免费行李额分别存储在 `FlightFare.flightPolicy` 和 `FlightFare.rtnFlightPolicy` 中,因此 `freeBaggageList` 不再包含 `journeyDirection` 字段来区分方向。
|
||||||
|
|
||||||
|
| **字段名** | **数据类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| airlineCode | String | "SL" | 航司代码 |
|
||||||
|
| fareFamilyType | String | "Lion Economy" | 舱位/子舱位类型名称 |
|
||||||
|
| description | String | | 政策描述 |
|
||||||
|
| freeAncillaryList | List\<FreeAncillary\> | | 免费行李额列表(详见下方说明) |
|
||||||
|
| refundRules | List\<RefundRule\> | | 退票规则列表(预留字段,暂未提供) |
|
||||||
|
| changeRules | List\<ChangeRule\> | | 改签规则列表(预留字段,暂未提供) |
|
||||||
|
|
||||||
|
## freeAncillaryList(FreeAncillary)
|
||||||
|
|
||||||
|
免费行李额元素,描述每个航段、每种乘客类型的免费行李配额。
|
||||||
|
|
||||||
|
| **字段名** | **数据类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| categoryCode | String | "StandardCheckedBaggage" | 辅营类型代码:`StandardCheckedBaggage` = 托运行李,`CabinBaggageUnderSeat` = 客舱行李(座椅下),`CabinBaggageOverheadLocker` = 客舱行李(行李架) |
|
||||||
|
| segmentIndex | Integer | 1 | 航段序号,从 1 开始 |
|
||||||
|
| paxType | String | "ADT" | 乘客类型:`ADT` = 成人,`CHD` = 儿童,`INF` = 婴儿 |
|
||||||
|
| piece | Integer | 1 | 行李件数(PC) |
|
||||||
|
| weight | Integer | 20 | 行李重量(KG) |
|
||||||
|
| size | String | | 行李尺寸 |
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"freeAncillaryList": [
|
||||||
|
{ "categoryCode": "CabinBaggageOverheadLocker", "segmentIndex": 1, "paxType": "ADT", "piece": 1, "weight": 7 },
|
||||||
|
{ "categoryCode": "StandardCheckedBaggage", "segmentIndex": 1, "paxType": "ADT", "piece": 1, "weight": 20 },
|
||||||
|
{ "categoryCode": "CabinBaggageOverheadLocker", "segmentIndex": 2, "paxType": "ADT", "piece": 1, "weight": 7 },
|
||||||
|
{ "categoryCode": "StandardCheckedBaggage", "segmentIndex": 2, "paxType": "ADT", "piece": 1, "weight": 20 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
121
docs/08-05_ancillary-product.md
Normal file
121
docs/08-05_ancillary-product.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<!-- mipuyun-api-doc: ancillary-product -->
|
||||||
|
# AncillaryProduct(辅营产品)
|
||||||
|
|
||||||
|
## 数据结构总览
|
||||||
|
|
||||||
|
辅营产品采用三级嵌套结构:
|
||||||
|
|
||||||
|
```
|
||||||
|
AncillaryGroup(分组层)
|
||||||
|
└─ AncillaryCategory(类别层)
|
||||||
|
└─ BaggageOption(选项层)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AncillaryGroup(分组层)
|
||||||
|
|
||||||
|
按 **航程方向 + 运价家族** 分组的最外层容器。
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 示例值 | 说明 |
|
||||||
|
|--------|------|--------|------|
|
||||||
|
| currency | String | "CAD" | 售价币种(ISO 4217) |
|
||||||
|
| fareFamilyType | String | "BASIC" | 运价家族类型,如 `BASIC`、`SMART`、`PROMO` |
|
||||||
|
| journeyDirection | String | "outbound" | 航程方向:`outbound`(去程)/ `inbound`(回程) |
|
||||||
|
| categoryList | Array\<AncillaryCategory\> | - | 辅营类别列表 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AncillaryCategory(类别层)
|
||||||
|
|
||||||
|
按行李类别分组,携带定价模式和购买限制。
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 示例值 | 说明 |
|
||||||
|
|--------|------|--------|------|
|
||||||
|
| categoryCode | String | "StandardCheckedBaggage" | 类别代码,见下方 categoryCode 说明 |
|
||||||
|
| maxPieces | String | "5" | 该类别最多可购买件数 |
|
||||||
|
| pricingMode | String | "STEP" | 定价模式:`FLAT` / `STEP` / `TIERED`,见下方说明 |
|
||||||
|
| categoryDetail | Array\<BaggageOption\> | - | 该类别下的选项列表 |
|
||||||
|
|
||||||
|
### categoryCode 说明
|
||||||
|
|
||||||
|
| categoryCode | 说明 |
|
||||||
|
|--------------|------|
|
||||||
|
| CabinBaggageOverheadLocker | 手提行李(头顶行李架) |
|
||||||
|
| CabinBaggageUnderSeat | 手提行李(座椅下) |
|
||||||
|
| StandardCheckedBaggage | 托运行李 |
|
||||||
|
|
||||||
|
### pricingMode 说明
|
||||||
|
|
||||||
|
| pricingMode | 说明 |
|
||||||
|
|-------------|------|
|
||||||
|
| FLAT | 固定单价,每件为独立产品,pieceNo 固定为 1 |
|
||||||
|
| STEP | 逐件定价,pieceNo 表示第 N 件,同 pieceNo 可有多个重量选项 |
|
||||||
|
| TIERED | 按总重量档位选择,不计件,pieceNo 固定为 1 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## BaggageOption(选项层)
|
||||||
|
|
||||||
|
具体的行李规格和价格。
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 示例值 | 说明 |
|
||||||
|
|--------|------|--------|------|
|
||||||
|
| pieceNo | Integer | 1 | 第 N 件。STEP 模式下为序号(1, 2, 3...),FLAT/TIERED 模式下为 1 |
|
||||||
|
| weight | BigDecimal | 23 | 行李额重量(KG) |
|
||||||
|
| size | String | "55x40x23cm" | 尺寸限制,空字符串表示无特殊限制 |
|
||||||
|
| price | BigDecimal | 64.00 | 该选项/该件价格 |
|
||||||
|
| maxPieces | Integer | 1 | 该选项可购买数量 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 响应示例
|
||||||
|
|
||||||
|
### STEP 模式示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"currency": "CAD",
|
||||||
|
"fareFamilyType": "BASIC",
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"categoryList": [
|
||||||
|
{
|
||||||
|
"categoryCode": "StandardCheckedBaggage",
|
||||||
|
"maxPieces": "5",
|
||||||
|
"pricingMode": "STEP",
|
||||||
|
"categoryDetail": [
|
||||||
|
{ "pieceNo": 1, "weight": 10, "size": "", "price": 39.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 1, "weight": 23, "size": "", "price": 64.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 2, "weight": 23, "size": "", "price": 64.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 3, "weight": 23, "size": "", "price": 99.00, "maxPieces": 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **STEP 模式解读**:第 1 件可选 10kg($39)或 23kg($64),第 2 件 23kg($64),第 3 件 23kg($99)。
|
||||||
|
|
||||||
|
### TIERED 模式示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"currency": "CNY",
|
||||||
|
"fareFamilyType": "ECONOMY",
|
||||||
|
"journeyDirection": "outbound",
|
||||||
|
"categoryList": [
|
||||||
|
{
|
||||||
|
"categoryCode": "StandardCheckedBaggage",
|
||||||
|
"maxPieces": "1",
|
||||||
|
"pricingMode": "TIERED",
|
||||||
|
"categoryDetail": [
|
||||||
|
{ "pieceNo": 1, "weight": 20, "size": "", "price": 300.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 1, "weight": 25, "size": "", "price": 500.00, "maxPieces": 1 },
|
||||||
|
{ "pieceNo": 1, "weight": 30, "size": "", "price": 800.00, "maxPieces": 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **TIERED 模式解读**:按重量档位互斥选择,20kg(¥300)、25kg(¥500)或 30kg(¥800),只能选一个。
|
||||||
230
docs/08-06_fee-items.md
Normal file
230
docs/08-06_fee-items.md
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
<!-- mipuyun-api-doc: fee-items -->
|
||||||
|
# feeItems 实体定义
|
||||||
|
|
||||||
|
该实体用于拆分航班预订费用,字段与最新响应数据完全对齐,同时补充业务含义说明:
|
||||||
|
|
||||||
|
### **字段结构**
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
feeItems
|
||||||
|
├── amount (总金额)
|
||||||
|
├── currency (货币代码)
|
||||||
|
├── fare (票价)
|
||||||
|
│ ├── amount (票价总金额)
|
||||||
|
│ ├── name (费用名称)
|
||||||
|
│ ├── remark (费用备注)
|
||||||
|
│ └── passengers (按乘机人拆分)
|
||||||
|
│ └── 每个乘客的票价明细
|
||||||
|
├── tax (税费)
|
||||||
|
│ ├── amount (税费总金额)
|
||||||
|
│ ├── name (费用名称)
|
||||||
|
│ ├── remark (费用备注)
|
||||||
|
│ ├── passengers (按乘机人拆分)
|
||||||
|
│ │ └── 每个乘客的税费明细
|
||||||
|
│ │ └── fees (税费细项)
|
||||||
|
│ │ └── 每个税费的明细
|
||||||
|
│ └── fees (税费总细项)
|
||||||
|
│ └── 每个税费的明细
|
||||||
|
├── cabinBaggage (手提行李)
|
||||||
|
│ ├── amount (手提行李总金额)
|
||||||
|
│ ├── name (费用名称)
|
||||||
|
│ ├── remark (费用备注)
|
||||||
|
│ └── passengers (按乘机人拆分)
|
||||||
|
│ └── 每个乘客的手提行李费用明细
|
||||||
|
├── checkedBaggage (托运行李)
|
||||||
|
│ ├── amount (托运行李总金额)
|
||||||
|
│ ├── name (费用名称)
|
||||||
|
│ ├── remark (费用备注)
|
||||||
|
│ └── passengers (按乘机人拆分)
|
||||||
|
│ └── 每个乘客的托运行李费用明细
|
||||||
|
├── seat (座位)
|
||||||
|
│ ├── amount (座位总金额)
|
||||||
|
│ ├── name (费用名称)
|
||||||
|
│ ├── remark (费用备注)
|
||||||
|
│ └── passengers (按乘机人拆分)
|
||||||
|
│ └── 每个乘客的座位费用明细
|
||||||
|
├── payment (支付手续费)
|
||||||
|
│ ├── amount (支付手续费总金额)
|
||||||
|
│ ├── name (费用名称)
|
||||||
|
│ └── remark (费用备注)
|
||||||
|
└── other (其他额外费用)
|
||||||
|
├── amount (其他额外费用总金额)
|
||||||
|
├── name (费用名称)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段名 | 数据类型 | 示例值 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| totalPrice | Decimal | "850.00" | 总金额:航班预订的全部费用合计,单位与 currency 一致 |
|
||||||
|
| currency | String | "CNY" | 货币代码:标识费用的货币类型(如 CNY 为人民币、USD 为美元) |
|
||||||
|
| ticketPrice | Object | {"amount":"200.00","name":"票价",...} | 票价对象:包含票价总金额、费用名称、备注及可选的乘机人拆分明细(PassengerFee 数组) |
|
||||||
|
| tax | Object | {"amount":"250.00","name":"税",...} | 税费对象:包含税费总金额、费用名称、备注,可选乘机人拆分明细(PassengerFee 数组)和税费细项(FeeDetail 数组) |
|
||||||
|
| cabinBaggage | Object | {"amount":"50.00","name":"手提行李",...} | 手提行李费用对象:包含总金额、费用名称、备注及可选的乘机人拆分明细(PassengerFee 数组),可选字段 |
|
||||||
|
| checkedBaggage | Object | {"amount":"150.00","name":"托运行李",...} | 托运行李费用对象:包含总金额、费用名称、备注及可选的乘机人拆分明细(PassengerFee 数组),可选字段 |
|
||||||
|
| seat | Object | {"amount":"100.00","name":"座位",...} | 座位费用对象:包含总金额、费用名称、备注及可选的乘机人拆分明细(PassengerFee 数组),可选字段 |
|
||||||
|
| payment | Object | {"amount":"50.00","name":"支付手续费",...} | 支付手续费对象:包含总金额、费用名称、备注,无乘机人拆分,可选字段 |
|
||||||
|
| other | Object | {"amount":"0.00","name":"其他费用",...} | 其他额外费用对象:包含总金额、费用名称、备注,无乘机人拆分,可选字段 |
|
||||||
|
|
||||||
|
## 嵌套实体定义
|
||||||
|
|
||||||
|
### PassengerFee(乘机人费用明细)
|
||||||
|
|
||||||
|
| 字段名 | 数据类型 | 示例值 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| amount | Decimal | "100.00" | 乘机人对应费用金额:单个乘客在该费用类型下的应付金额 |
|
||||||
|
| name | String | "willow/yang" | 乘机人姓名:对应乘客的姓名标识 |
|
||||||
|
| remark | String | "成人票价" | 备注:说明该乘客费用的相关信息(如乘客类型、费用用途) |
|
||||||
|
| fees | Array[FeeDetail] | [{"amount":"100.00","name":"机场税",...}] | 税费细项数组:仅税费对象的乘机人明细中可选,包含该乘客的具体税费拆分,可选字段 |
|
||||||
|
|
||||||
|
### FeeDetail(费用细项明细)
|
||||||
|
|
||||||
|
| 字段名 | 数据类型 | 示例值 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| amount | Decimal | "170.00" | 细项金额:单个费用细项的总金额或乘机人对应金额 |
|
||||||
|
| name | String | "机场税" | 细项名称:描述费用细项的类型(如机场税、燃油附加费) |
|
||||||
|
| remark | String | "机场税" | 备注:补充说明费用细项的相关信息,与名称语义一致 |
|
||||||
|
| code | String | - | 费用细项编码:唯一标识该费用细项类型,可选字段 |
|
||||||
|
|
||||||
|
### **响应示例**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"feeItems": {
|
||||||
|
"totalPrice": "850.00",
|
||||||
|
"currency": "CNY",
|
||||||
|
"ticketPrice": {
|
||||||
|
"amount": "200.00",
|
||||||
|
"name": "票价",
|
||||||
|
"remark": "票价",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"amount": "100.00",
|
||||||
|
"name": "willow/yang",
|
||||||
|
"remark": "成人票价"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "100.00",
|
||||||
|
"name": "jasen/yang",
|
||||||
|
"remark": "成人票价"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tax": {
|
||||||
|
"amount": "250.00",
|
||||||
|
"name": "税",
|
||||||
|
"remark": "税费",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"amount": "150.00",
|
||||||
|
"name": "willow/yang",
|
||||||
|
"remark": "成人税价",
|
||||||
|
"fees": [
|
||||||
|
{
|
||||||
|
"amount": "100.00",
|
||||||
|
"name": "机场税",
|
||||||
|
"remark": "机场税"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "50.00",
|
||||||
|
"name": "燃油附加费",
|
||||||
|
"remark": "燃油附加费"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "100.00",
|
||||||
|
"name": "jasen/yang",
|
||||||
|
"remark": "成人税价",
|
||||||
|
"fees": [
|
||||||
|
{
|
||||||
|
"amount": "70.00",
|
||||||
|
"name": "机场税",
|
||||||
|
"remark": "机场税"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "30.00",
|
||||||
|
"name": "燃油附加费",
|
||||||
|
"remark": "燃油附加费"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fees": [
|
||||||
|
{
|
||||||
|
"amount": "170.00",
|
||||||
|
"name": "机场税",
|
||||||
|
"remark": "机场税"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "80.00",
|
||||||
|
"name": "燃油附加费",
|
||||||
|
"remark": "燃油附加费"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"cabinBaggage": {
|
||||||
|
"amount": "50.00",
|
||||||
|
"name": "手提行李",
|
||||||
|
"remark": "手提行李费",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"amount": "25.00",
|
||||||
|
"name": "willow/yang",
|
||||||
|
"remark": "手提行李费"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "25.00",
|
||||||
|
"name": "jasen/yang",
|
||||||
|
"remark": "手提行李费"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"checkedBaggage": {
|
||||||
|
"amount": "150.00",
|
||||||
|
"name": "托运行李",
|
||||||
|
"remark": "托运行李费",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"amount": "75.00",
|
||||||
|
"name": "willow/yang",
|
||||||
|
"remark": "托运行李费"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "75.00",
|
||||||
|
"name": "jasen/yang",
|
||||||
|
"remark": "托运行李费"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"seat": {
|
||||||
|
"amount": "100.00",
|
||||||
|
"name": "座位",
|
||||||
|
"remark": "选座费",
|
||||||
|
"passengers": [
|
||||||
|
{
|
||||||
|
"amount": "50.00",
|
||||||
|
"name": "willow/yang",
|
||||||
|
"remark": "选座费"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amount": "50.00",
|
||||||
|
"name": "jasen/yang",
|
||||||
|
"remark": "选座费"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"amount": "50.00",
|
||||||
|
"name": "支付手续费",
|
||||||
|
"remark": "支付手续费"
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"amount": "0.00",
|
||||||
|
"name": "其他费用",
|
||||||
|
"remark": "其他费用"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
141
docs/09-01_device-list.md
Normal file
141
docs/09-01_device-list.md
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<!-- mipuyun-api-doc: device-list -->
|
||||||
|
# device/list - 设备列表
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
设备列表API用于查询当前客户的所有设备信息,包括设备状态、绑定的VCC卡、任务状态等。
|
||||||
|
|
||||||
|
### 用户使用场景
|
||||||
|
|
||||||
|
本接口用于:
|
||||||
|
- 查看所有可用设备及其在线状态
|
||||||
|
- 检查设备的VCC卡绑定情况
|
||||||
|
- 查看设备的任务处理状态
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| **请求地址** | `https://${endpoint}/device/list` |
|
||||||
|
| **请求方法** | GET |
|
||||||
|
| **注意事项** | 无需请求体,从Header中获取clientCode |
|
||||||
|
|
||||||
|
### Header 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
成功时返回设备信息列表:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"status": "ONLINE",
|
||||||
|
"vccCardNumber": "424242******4242",
|
||||||
|
"bindingVccCardNumber": "555555******5555",
|
||||||
|
"lastHeartbeatTime": 1704140800000,
|
||||||
|
"taskStatus": "PROCESSING",
|
||||||
|
"processingTask": {
|
||||||
|
"taskId": "task-123",
|
||||||
|
"taskType": "BIND_VCC",
|
||||||
|
"status": "PROCESSING",
|
||||||
|
"createTime": "2025-01-15T10:30:00Z",
|
||||||
|
"updateTime": "2025-01-15T10:35:00Z",
|
||||||
|
"deviceId": "device-001"
|
||||||
|
},
|
||||||
|
"pendingTasks": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"deviceId": "device-002",
|
||||||
|
"status": "OFFLINE",
|
||||||
|
"vccCardNumber": "378222******2222",
|
||||||
|
"bindingVccCardNumber": null,
|
||||||
|
"lastHeartbeatTime": 1704130000000,
|
||||||
|
"taskStatus": "IDLE",
|
||||||
|
"processingTask": null,
|
||||||
|
"pendingTasks": [
|
||||||
|
{
|
||||||
|
"taskId": "task-124",
|
||||||
|
"taskType": "UNBIND_VCC",
|
||||||
|
"status": "PENDING",
|
||||||
|
"createTime": "2025-01-15T11:00:00Z",
|
||||||
|
"updateTime": "2025-01-15T11:00:00Z",
|
||||||
|
"deviceId": "device-002"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| deviceId | String | 设备编号 |
|
||||||
|
| status | String | 设备状态:ONLINE=在线,OFFLINE=离线 |
|
||||||
|
| vccCardNumber | String | 当前绑定的VCC卡号(脱敏显示) |
|
||||||
|
| bindingVccCardNumber | String | 正在绑定的VCC卡号(脱敏显示,绑定任务进行中时存在) |
|
||||||
|
| lastHeartbeatTime | Long | 最后心跳时间(时间戳毫秒) |
|
||||||
|
| taskStatus | String | 任务状态:IDLE=空闲,PROCESSING=处理中,PENDING=有等待任务 |
|
||||||
|
| processingTask | Object | 正在执行的任务信息 |
|
||||||
|
| pendingTasks | Array | 等待队列中的任务列表 |
|
||||||
|
|
||||||
|
### TaskInfo 任务信息
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| taskId | String | 任务ID |
|
||||||
|
| taskType | String | 任务类型:BIND_VCC=绑定VCC卡,UNBIND_VCC=解绑VCC卡,PAYMENT=支付 |
|
||||||
|
| status | String | 任务状态:PENDING=等待中,PROCESSING=处理中,COMPLETED=已完成,FAILED=失败 |
|
||||||
|
| createTime | String | 创建时间(ISO 8601格式) |
|
||||||
|
| updateTime | String | 更新时间(ISO 8601格式) |
|
||||||
|
| deviceId | String | 设备ID |
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 查询所有设备状态
|
||||||
|
|
||||||
|
### 请求
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET "https://${endpoint}/device/list" \
|
||||||
|
-H "client-key: your_key" \
|
||||||
|
-H "client-secret: your_secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"status": "ONLINE",
|
||||||
|
"vccCardNumber": "424242******4242",
|
||||||
|
"bindingVccCardNumber": null,
|
||||||
|
"lastHeartbeatTime": 1704140800000,
|
||||||
|
"taskStatus": "IDLE",
|
||||||
|
"processingTask": null,
|
||||||
|
"pendingTasks": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 设备状态ONLINE和OFFLINE的区别是什么?
|
||||||
|
|
||||||
|
- **ONLINE**:设备在线,可以接收和处理任务
|
||||||
|
- **OFFLINE**:设备离线,无法处理任务
|
||||||
|
|
||||||
|
### taskStatus有几种状态?
|
||||||
|
|
||||||
|
- **IDLE**:设备空闲,没有正在处理的任务
|
||||||
|
- **PROCESSING**:设备正在执行任务
|
||||||
|
- **PENDING**:设备有待处理的任务队列
|
||||||
|
|
||||||
|
### VCC卡号为什么要脱敏显示?
|
||||||
|
|
||||||
|
为了保护支付安全,VCC卡号只显示前6位和后4位,中间用*替换。
|
||||||
143
docs/09-02_device-bind.md
Normal file
143
docs/09-02_device-bind.md
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<!-- mipuyun-api-doc: device-bind -->
|
||||||
|
# device/bind - VCC卡绑定
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
VCC卡绑定API用于向设备提交VCC卡绑定请求。绑定过程是异步的,提交后会返回任务ID,可以通过任务查询接口查询绑定进度。
|
||||||
|
|
||||||
|
### 用户使用场景
|
||||||
|
|
||||||
|
本接口用于:
|
||||||
|
- 为在线设备绑定新的VCC卡
|
||||||
|
- 替换设备当前绑定的VCC卡
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| **请求地址** | `https://${endpoint}/device/bind` |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | 绑定过程是异步的,需要轮询任务状态 |
|
||||||
|
|
||||||
|
### Header 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
### 请求体参数
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"creditCard": {
|
||||||
|
"cardNumber": "4242424242424242",
|
||||||
|
"cvv": "123",
|
||||||
|
"expiryDate": "12/25"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| deviceId | String | 是 | "device-001" | 设备编号 |
|
||||||
|
| creditCard | Object | 是 | - | 信用卡信息 |
|
||||||
|
| creditCard.cardNumber | String | 是 | "4242424242424242" | 卡号 |
|
||||||
|
| creditCard.cvv | String | 是 | "123" | CVV码 |
|
||||||
|
| creditCard.expiryDate | String | 是 | "12/25" | 有效期,格式:MM/YY |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
成功时返回任务信息:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "VCC卡绑定任务已提交",
|
||||||
|
"taskId": "task-bind-123456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| success | Boolean | 是否成功提交 |
|
||||||
|
| message | String | 结果消息 |
|
||||||
|
| taskId | String | 任务ID,用于查询任务状态 |
|
||||||
|
|
||||||
|
失败时返回:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "设备离线,无法执行绑定任务",
|
||||||
|
"taskId": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 绑定VCC卡
|
||||||
|
|
||||||
|
### 请求
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "https://${endpoint}/device/bind" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "client-key: your_key" \
|
||||||
|
-H "client-secret: your_secret" \
|
||||||
|
-d '{
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"creditCard": {
|
||||||
|
"cardNumber": "4242424242424242",
|
||||||
|
"cvv": "123",
|
||||||
|
"expiryDate": "12/25"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "VCC卡绑定任务已提交",
|
||||||
|
"taskId": "task-bind-123456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查询绑定任务进度
|
||||||
|
|
||||||
|
使用返回的taskId查询任务状态:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET "https://${endpoint}/device/task/task-bind-123456" \
|
||||||
|
-H "client-key: your_key" \
|
||||||
|
-H "client-secret: your_secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 绑定是同步还是异步的?
|
||||||
|
|
||||||
|
绑定是**异步操作**。提交绑定请求后会立即返回任务ID,需要通过任务查询接口轮询任务状态。
|
||||||
|
|
||||||
|
### 绑定失败的可能原因?
|
||||||
|
|
||||||
|
- 设备离线(status=OFFLINE)
|
||||||
|
- 设备正在执行其他任务(taskStatus=PROCESSING)
|
||||||
|
- 信用卡信息格式错误
|
||||||
|
- 信用卡已过期
|
||||||
|
|
||||||
|
### 如何判断绑定是否完成?
|
||||||
|
|
||||||
|
通过任务查询接口检查任务状态:
|
||||||
|
- **PENDING**:任务在队列中等待
|
||||||
|
- **PROCESSING**:正在绑定中
|
||||||
|
- **COMPLETED**:绑定完成
|
||||||
|
- **FAILED**:绑定失败
|
||||||
|
|
||||||
|
### 绑定完成后如何验证?
|
||||||
|
|
||||||
|
再次调用设备列表接口,查看设备的 `vccCardNumber` 字段是否已更新为新卡号。
|
||||||
128
docs/09-03_device-unbind.md
Normal file
128
docs/09-03_device-unbind.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<!-- mipuyun-api-doc: device-unbind -->
|
||||||
|
# device/unbind - VCC卡解绑
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
VCC卡解绑API用于向设备提交VCC卡解绑请求。解绑过程是异步的,提交后会返回任务ID,可以通过任务查询接口查询解绑进度。
|
||||||
|
|
||||||
|
### 用户使用场景
|
||||||
|
|
||||||
|
本接口用于:
|
||||||
|
- 移除设备当前绑定的VCC卡
|
||||||
|
- 更换VCC卡前先解绑旧卡
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| **请求地址** | `https://${endpoint}/device/unbind` |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | 解绑过程是异步的,需要轮询任务状态 |
|
||||||
|
|
||||||
|
### Header 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
### 请求体参数
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"deviceId": "device-001"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| deviceId | String | 是 | "device-001" | 设备编号 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
成功时返回任务信息:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "VCC卡解绑任务已提交",
|
||||||
|
"taskId": "task-unbind-123456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| success | Boolean | 是否成功提交 |
|
||||||
|
| message | String | 结果消息 |
|
||||||
|
| taskId | String | 任务ID,用于查询任务状态 |
|
||||||
|
|
||||||
|
失败时返回:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "设备没有绑定的VCC卡",
|
||||||
|
"taskId": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 解绑VCC卡
|
||||||
|
|
||||||
|
### 请求
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "https://${endpoint}/device/unbind" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "client-key: your_key" \
|
||||||
|
-H "client-secret: your_secret" \
|
||||||
|
-d '{
|
||||||
|
"deviceId": "device-001"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "VCC卡解绑任务已提交",
|
||||||
|
"taskId": "task-unbind-123456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查询解绑任务进度
|
||||||
|
|
||||||
|
使用返回的taskId查询任务状态:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET "https://${endpoint}/device/task/task-unbind-123456" \
|
||||||
|
-H "client-key: your_key" \
|
||||||
|
-H "client-secret: your_secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 解绑是同步还是异步的?
|
||||||
|
|
||||||
|
解绑是**异步操作**。提交解绑请求后会立即返回任务ID,需要通过任务查询接口轮询任务状态。
|
||||||
|
|
||||||
|
### 解绑失败的可能原因?
|
||||||
|
|
||||||
|
- 设备离线(status=OFFLINE)
|
||||||
|
- 设备正在执行其他任务(taskStatus=PROCESSING)
|
||||||
|
- 设备没有绑定的VCC卡(vccCardNumber为空)
|
||||||
|
|
||||||
|
### 如何判断解绑是否完成?
|
||||||
|
|
||||||
|
通过任务查询接口检查任务状态:
|
||||||
|
- **PENDING**:任务在队列中等待
|
||||||
|
- **PROCESSING**:正在解绑中
|
||||||
|
- **COMPLETED**:解绑完成
|
||||||
|
- **FAILED**:解绑失败
|
||||||
|
|
||||||
|
### 解绑完成后如何验证?
|
||||||
|
|
||||||
|
再次调用设备列表接口,查看设备的 `vccCardNumber` 字段是否已为空。
|
||||||
165
docs/09-04_device-task.md
Normal file
165
docs/09-04_device-task.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<!-- mipuyun-api-doc: device-task -->
|
||||||
|
# device/task/{taskId} - 查询任务
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
任务查询API用于查询设备任务的执行状态和详情。通过绑定/解绑接口获取的任务ID,可以使用本接口查询任务进度。
|
||||||
|
|
||||||
|
### 用户使用场景
|
||||||
|
|
||||||
|
本接口用于:
|
||||||
|
- 查询VCC卡绑定任务的状态
|
||||||
|
- 查询VCC卡解绑任务的状态
|
||||||
|
- 查询支付任务的状态
|
||||||
|
- 获取任务的详细信息和设备状态
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| **请求地址** | `https://${endpoint}/device/task/{taskId}` |
|
||||||
|
| **请求方法** | GET |
|
||||||
|
| **注意事项** | taskId从绑定/解绑接口返回中获取 |
|
||||||
|
|
||||||
|
### Header 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
### URL 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| taskId | String | 是 | "task-bind-123456" | 任务ID,从绑定/解绑接口返回 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
成功时返回任务详情:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"deviceStatus": "ONLINE",
|
||||||
|
"task": {
|
||||||
|
"taskId": "task-bind-123456",
|
||||||
|
"taskType": "BIND_VCC",
|
||||||
|
"status": "PROCESSING",
|
||||||
|
"createTime": "2025-01-15T10:30:00Z",
|
||||||
|
"updateTime": "2025-01-15T10:35:00Z",
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"orderId": null,
|
||||||
|
"creditCard": {
|
||||||
|
"cardNumber": "424242******4242",
|
||||||
|
"cvv": "***",
|
||||||
|
"expiryDate": "12/25"
|
||||||
|
},
|
||||||
|
"orderDetail": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| deviceId | String | 执行任务的设备ID |
|
||||||
|
| deviceStatus | String | 设备状态:ONLINE=在线,OFFLINE=离线 |
|
||||||
|
| task | Object | 任务详细信息 |
|
||||||
|
|
||||||
|
### Task 任务信息
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| taskId | String | 任务ID |
|
||||||
|
| taskType | String | 任务类型:BIND_VCC=绑定VCC卡,UNBIND_VCC=解绑VCC卡,PAYMENT=支付 |
|
||||||
|
| status | String | 任务状态:PENDING=等待中,PROCESSING=处理中,COMPLETED=已完成,FAILED=失败 |
|
||||||
|
| createTime | String | 创建时间(ISO 8601格式) |
|
||||||
|
| updateTime | String | 更新时间(ISO 8601格式) |
|
||||||
|
| deviceId | String | 设备ID |
|
||||||
|
| orderId | String | 订单ID(仅PAYMENT类型任务) |
|
||||||
|
| creditCard | Object | 信用卡信息(仅BIND_VCC类型任务,脱敏显示) |
|
||||||
|
| orderDetail | String | 订单详情(仅PAYMENT类型任务) |
|
||||||
|
|
||||||
|
## 业务案例
|
||||||
|
|
||||||
|
### 查询绑定任务状态
|
||||||
|
|
||||||
|
### 请求
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET "https://${endpoint}/device/task/task-bind-123456" \
|
||||||
|
-H "client-key: your_key" \
|
||||||
|
-H "client-secret: your_secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应 - 任务处理中
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"deviceStatus": "ONLINE",
|
||||||
|
"task": {
|
||||||
|
"taskId": "task-bind-123456",
|
||||||
|
"taskType": "BIND_VCC",
|
||||||
|
"status": "PROCESSING",
|
||||||
|
"createTime": "2025-01-15T10:30:00Z",
|
||||||
|
"updateTime": "2025-01-15T10:35:00Z",
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"creditCard": {
|
||||||
|
"cardNumber": "424242******4242",
|
||||||
|
"cvv": "***",
|
||||||
|
"expiryDate": "12/25"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应 - 任务完成
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"deviceId": "device-001",
|
||||||
|
"deviceStatus": "ONLINE",
|
||||||
|
"task": {
|
||||||
|
"taskId": "task-bind-123456",
|
||||||
|
"taskType": "BIND_VCC",
|
||||||
|
"status": "COMPLETED",
|
||||||
|
"createTime": "2025-01-15T10:30:00Z",
|
||||||
|
"updateTime": "2025-01-15T10:36:00Z",
|
||||||
|
"deviceId": "device-001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应 - 任务不存在
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"deviceId": null,
|
||||||
|
"deviceStatus": null,
|
||||||
|
"task": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 任务状态有哪几种?
|
||||||
|
|
||||||
|
- **PENDING**:任务在队列中等待执行
|
||||||
|
- **PROCESSING**:任务正在执行中
|
||||||
|
- **COMPLETED**:任务执行完成
|
||||||
|
- **FAILED**:任务执行失败
|
||||||
|
|
||||||
|
### 任务查询不到是什么原因?
|
||||||
|
|
||||||
|
- 任务ID错误
|
||||||
|
- 任务已完成且已被清理(根据系统配置,任务可能会在完成后一段时间被清理)
|
||||||
|
- 任务ID来自其他客户
|
||||||
|
|
||||||
|
### 为什么要轮询查询任务状态?
|
||||||
|
|
||||||
|
因为绑定/解绑操作是异步的,设备需要时间完成操作。建议间隔3-5秒轮询一次,直到任务状态变为 COMPLETED 或 FAILED。
|
||||||
|
|
||||||
|
### 信用卡信息为什么要脱敏?
|
||||||
|
|
||||||
|
为了保护支付安全,任务详情中的信用卡信息只显示脱敏后的卡号和掩码CVV。
|
||||||
62
docs/10_error-codes.md
Normal file
62
docs/10_error-codes.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!-- mipuyun-api-doc: 10_error-codes -->
|
||||||
|
# 错误码说明
|
||||||
|
|
||||||
|
## 完整错误码列表
|
||||||
|
|
||||||
|
| 错误码 | 枚举名称 | 消息 | 可重试 | 说明 |
|
||||||
|
|--------|----------|------|--------|------|
|
||||||
|
| 100 | - | 鉴权失败 | false | 请检查 client-key, client-secret 信息是否正确 |
|
||||||
|
| 102 | - | 超过限流 | true | 请求频率超过限制,请稍后重试 |
|
||||||
|
| 103 | - | Proxy error | true | 代理服务器失败,请检查代理服务器 URL 是否正确,或者代理 IP 用量是否足够。如果使用平台代理且刚刚修改过命名,请等待 5 分钟平台缓存同步再试 |
|
||||||
|
| 104 | - | Agent not exist or agent is disabled | false | 检查 agent code 是否正确,agent 是否被停用。如果刚刚创建运行器(agent),请等待 5 分钟平台缓存同步再试 |
|
||||||
|
| 40013 | AGENT_MISSED_CREDENTIAL | Agent credential not configured | false | Agent 凭证未配置,请检查 Agent 的认证信息是否正确配置 |
|
||||||
|
| 42010 | PRICE_CHANGED | Fare price has changed, please check latest price from feeitem | false | 价格变动,请检查响应中的 feeItems 获取最新价格 |
|
||||||
|
| 41007 | FLIGHT_NOT_AVAILABLE | Flight not available | true | 航班不存在/已售罄 |
|
||||||
|
| 42011 | INSUFFICIENT_SEATS | Insufficient seats | true | 剩余座位不足 |
|
||||||
|
| 42000 | ORDER_ID_REQUIRED | Order ID is required | false | 缺少订单 ID |
|
||||||
|
| 42001 | ORDER_ID_DUPLICATE | Order ID already exists | false | 订单 ID 重复 |
|
||||||
|
| 42002 | PASSENGER_MISMATCH | Passenger information mismatch | false | 乘客信息不匹配 |
|
||||||
|
| 42003 | BOOKING_FAILED | Failed to create booking | true | 预订失败 |
|
||||||
|
| 42004 | HOLD_EXECUTION_FAILED | Hold execution failed | true | Hold 执行失败 |
|
||||||
|
| 42005 | BOOKING_NOT_FOUND | Booking not found | false | 预订未找到 |
|
||||||
|
| 42006 | DUPLICATE_PASSENGER_NAME | Duplicate passenger name in booking | false | 乘客姓名重复 |
|
||||||
|
| 42007 | DUPLICATE_BOOKING | Duplicate booking detected | false | 重复预订 |
|
||||||
|
| 42008 | INVALID_PASSENGER_INFO | Invalid passenger information | false | 乘客信息错误 |
|
||||||
|
| 42009 | DOCUMENT_ISSUE | Document validation failed | false | 证件问题 |
|
||||||
|
| 42012 | SEAT_NOT_AVAILABLE | Selected seat is not available | false | 所选座位不可用 |
|
||||||
|
| 49000 | SYSTEM_ERROR | Internal system error | true | 系统内部错误 |
|
||||||
|
| 49003 | QUOTA_EXCEEDED | Daily quota exceeded. Please upgrade your plan or try again tomorrow. | false | 日配额已超限,请升级套餐或明天再试 |
|
||||||
|
|
||||||
|
## PRICE_CHANGED (42010) 详细说明
|
||||||
|
|
||||||
|
**触发场景:**
|
||||||
|
|
||||||
|
当航司侧票价高于预期时,接口会返回错误码 42010。
|
||||||
|
|
||||||
|
**响应结构:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 42010,
|
||||||
|
"msg": "Fare price has changed, please check latest price from feeitem",
|
||||||
|
"timestamp": "2024-11-15T10:30:00Z",
|
||||||
|
"data": {
|
||||||
|
"orderId": "abbc4b57fb75",
|
||||||
|
"feeItems": {
|
||||||
|
"baseFare": 110.00,
|
||||||
|
"taxes": 52.50,
|
||||||
|
"total": 162.50,
|
||||||
|
"currency": "EUR"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**处理流程:**
|
||||||
|
|
||||||
|
1. 接收到 42010 错误响应
|
||||||
|
2. 从响应的 `data.feeItems` 中获取最新价格
|
||||||
|
3. 向用户展示价格变动信息
|
||||||
|
4. 询问用户是否接受新价格
|
||||||
|
5. 如用户同意,重新调用接口
|
||||||
|
6. 如用户拒绝,取消订单流程
|
||||||
90
docs/11-01_mailbox-domain-list.md
Normal file
90
docs/11-01_mailbox-domain-list.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<!-- mipuyun-api-doc: mailbox-domain-list -->
|
||||||
|
# mailbox/domain/list - 域名列表
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
查询当前客户已绑定的所有邮箱域名列表。
|
||||||
|
|
||||||
|
### 使用场景
|
||||||
|
|
||||||
|
- 查看当前客户已绑定的所有邮箱域名列表
|
||||||
|
- 管理员需要了解企业邮箱的域名配置情况
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| **请求地址** | `https://${endpoint}/mailbox/domain/list` |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
| **注意事项** | 无需请求体,系统自动从请求上下文中提取 clientCode |
|
||||||
|
|
||||||
|
### Header 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
返回 `MailboxDomain` 对象数组:
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 示例值 | 说明 |
|
||||||
|
|----------|------|--------|------|
|
||||||
|
| domainId | Long | 123 | 域名配置主键 |
|
||||||
|
| domainName | String | example.com | 域名全称 |
|
||||||
|
| status | Integer | 1 | 状态:0-待审核,1-已启用,2-已禁用,3-已删除 |
|
||||||
|
| statusText | String | 已启用 | 状态文本描述 |
|
||||||
|
| verifyStatus | Integer | 2 | 验证状态:0-未验证,1-验证中,2-验证通过,3-验证失败 |
|
||||||
|
| verifyStatusText | String | 验证通过 | 验证状态文本 |
|
||||||
|
| verifyToken | String | a1b2c3d4 | DNS验证令牌 |
|
||||||
|
| verifyHost | String | _mailbox-verify-a1b2c3d4 | DNS验证主机名 |
|
||||||
|
| verifyTime | String | 2025-01-01T10:00:00Z | 验证通过时间(ISO 8601格式) |
|
||||||
|
| createTime | String | 2025-01-01T10:00:00Z | 创建时间(ISO 8601格式) |
|
||||||
|
| updateTime | String | 2025-01-02T10:00:00Z | 更新时间(ISO 8601格式) |
|
||||||
|
| remark | String | 备注信息 | 备注 |
|
||||||
|
|
||||||
|
## 返回示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"domainId": 123,
|
||||||
|
"domainName": "example.com",
|
||||||
|
"status": 1,
|
||||||
|
"statusText": "已启用",
|
||||||
|
"verifyStatus": 2,
|
||||||
|
"verifyStatusText": "验证通过",
|
||||||
|
"verifyToken": "a1b2c3d4",
|
||||||
|
"verifyHost": "_mailbox-verify-a1b2c3d4",
|
||||||
|
"verifyTime": "2025-01-01T10:00:00Z",
|
||||||
|
"createTime": "2025-01-01T10:00:00Z",
|
||||||
|
"updateTime": "2025-01-02T10:00:00Z",
|
||||||
|
"remark": "主域名"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domainId": 124,
|
||||||
|
"domainName": "company.com",
|
||||||
|
"status": 0,
|
||||||
|
"statusText": "待审核",
|
||||||
|
"verifyStatus": 0,
|
||||||
|
"verifyStatusText": "未验证",
|
||||||
|
"verifyToken": "e5f6g7h8",
|
||||||
|
"verifyHost": "_mailbox-verify-e5f6g7h8",
|
||||||
|
"verifyTime": null,
|
||||||
|
"createTime": "2025-01-03T10:00:00Z",
|
||||||
|
"updateTime": "2025-01-03T10:00:00Z",
|
||||||
|
"remark": "备用域名"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
| 错误码 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| 401 | 认证失败,client-key 或 client-secret 无效 |
|
||||||
|
| 403 | 权限不足,无权访问该客户的域名列表 |
|
||||||
|
| 500 | 服务器内部错误 |
|
||||||
90
docs/11-02_mailbox-domain-apply.md
Normal file
90
docs/11-02_mailbox-domain-apply.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<!-- mipuyun-api-doc: mailbox-domain-apply -->
|
||||||
|
# mailbox/domain/apply - 申请绑定域名
|
||||||
|
|
||||||
|
# 申请绑定域名(mailbox/domain/apply) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 企业客户需要为自己的邮箱系统绑定自定义域名
|
||||||
|
> 1. 配置企业邮箱后,员工可以使用 @company.com 格式的邮箱地址
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 域名已被其他客户绑定
|
||||||
|
> 1. 域名格式不正确(如包含非法字符)
|
||||||
|
> 1. 客户已达到域名绑定数量上限
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 1000ms
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/mailbox/domain/apply |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境secret |
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domainName": "example.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| domainName | String | 是 | example.com | 要绑定的域名名称,必须是有效的域名格式 |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| domainId | Long | 123 | 域名唯一标识 |
|
||||||
|
| domainName | String | example.com | 域名名称 |
|
||||||
|
| status | String | PENDING | 域名状态:PENDING=待DNS验证 |
|
||||||
|
| dnsVerified | Boolean | false | DNS验证状态,新申请的域名需要验证 |
|
||||||
|
| createTime | String | 2025-01-02T10:00:00Z | 域名创建时间(ISO 8601格式) |
|
||||||
|
|
||||||
|
## 返回示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domainId": 123,
|
||||||
|
"domainName": "example.com",
|
||||||
|
"status": "PENDING",
|
||||||
|
"dnsVerified": false,
|
||||||
|
"createTime": "2025-01-02T10:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 后续步骤
|
||||||
|
|
||||||
|
申请域名绑定后,需要完成DNS验证才能激活邮箱服务:
|
||||||
|
|
||||||
|
1. 在域名DNS管理中添加相应的MX记录
|
||||||
|
2. 调用 `mailbox/domain/verify` 接口验证DNS配置
|
||||||
|
3. 验证通过后,域名状态将变为 ACTIVE
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
| **错误码** | **说明** |
|
||||||
|
| --- | --- |
|
||||||
|
| 400 | 请求参数错误,域名格式不正确 |
|
||||||
|
| 401 | 认证失败,client-key 或 client-secret 无效 |
|
||||||
|
| 409 | 域名已被其他客户绑定 |
|
||||||
|
| 429 | 已达到域名绑定数量上限 |
|
||||||
|
| 500 | 服务器内部错误 |
|
||||||
87
docs/11-03_mailbox-domain-detail.md
Normal file
87
docs/11-03_mailbox-domain-detail.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<!-- mipuyun-api-doc: mailbox-domain-detail -->
|
||||||
|
# mailbox/domain/detail - 域名详情
|
||||||
|
|
||||||
|
# 查询域名详情(mailbox/domain/detail) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 查看指定域名的详细配置信息
|
||||||
|
> 1. 管理员需要了解域名的DNS配置和验证状态
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 查询的域名ID不存在
|
||||||
|
> 1. 查询的域名不属于当前客户(权限不足)
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 500ms
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/mailbox/domain/detail |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境secret |
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domainId": 123
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| domainId | Long | 是 | 123 | 域名ID |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| domainId | Long | 123 | 域名唯一标识 |
|
||||||
|
| domainName | String | example.com | 域名名称 |
|
||||||
|
| status | String | ACTIVE | 域名状态 |
|
||||||
|
| dnsVerified | Boolean | true | DNS验证状态 |
|
||||||
|
| createTime | String | 2025-01-01T10:00:00Z | 域名创建时间 |
|
||||||
|
| updateTime | String | 2025-01-02T10:00:00Z | 域名更新时间 |
|
||||||
|
| mxRecord | String | mail.example.com | MX记录(如已配置) |
|
||||||
|
| txtRecord | String | v=spf1 include:... | SPF记录(如已配置) |
|
||||||
|
|
||||||
|
## 返回示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domainId": 123,
|
||||||
|
"domainName": "example.com",
|
||||||
|
"status": "ACTIVE",
|
||||||
|
"dnsVerified": true,
|
||||||
|
"createTime": "2025-01-01T10:00:00Z",
|
||||||
|
"updateTime": "2025-01-02T10:00:00Z",
|
||||||
|
"mxRecord": "mail.example.com",
|
||||||
|
"txtRecord": "v=spf1 include:_spf.example.com ~all"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
| **错误码** | **说明** |
|
||||||
|
| --- | --- |
|
||||||
|
| 400 | 请求参数错误,domainId 格式不正确 |
|
||||||
|
| 401 | 认证失败,client-key 或 client-secret 无效 |
|
||||||
|
| 403 | 权限不足,无权访问该域名信息 |
|
||||||
|
| 404 | 域名不存在 |
|
||||||
|
| 500 | 服务器内部错误 |
|
||||||
95
docs/11-04_mailbox-domain-delete.md
Normal file
95
docs/11-04_mailbox-domain-delete.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<!-- mipuyun-api-doc: mailbox-domain-delete -->
|
||||||
|
# mailbox/domain/delete - 删除域名
|
||||||
|
|
||||||
|
# 删除域名(mailbox/domain/delete) API 说明文档
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
> 1. 企业不再需要使用某个域名作为邮箱域名
|
||||||
|
> 1. 域名配置错误,需要删除后重新申请
|
||||||
|
|
||||||
|
## 错误场景(不应该使用本接口的场景)
|
||||||
|
|
||||||
|
> 1. 域名下仍有活跃的邮箱账户(需要先删除邮箱账户)
|
||||||
|
> 1. 域名不属于当前客户(权限不足)
|
||||||
|
> 1. 域名ID不存在
|
||||||
|
|
||||||
|
## 性能指标
|
||||||
|
|
||||||
|
> - 响应速度:98% 的请求响应速度 < 1000ms
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| **请求地址** | https://${endpoint}/mailbox/domain/delete |
|
||||||
|
| --- | --- |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
## 请求参数
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境secret |
|
||||||
|
|
||||||
|
### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domainId": 123
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数详情
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **是否必选** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| domainId | Long | 是 | 123 | 要删除的域名ID |
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
| **参数名称** | **类型** | **示例值** | **说明** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| code | Integer | 0 | 状态码:0=成功,1=失败 |
|
||||||
|
| msg | String | Domain deleted successfully | 操作结果消息 |
|
||||||
|
| domainId | Long | 123 | 被删除的域名ID |
|
||||||
|
|
||||||
|
## 返回示例
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "Domain deleted successfully",
|
||||||
|
"domainId": 123
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
失败响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 1,
|
||||||
|
"msg": "Failed to delete domain",
|
||||||
|
"domainId": 123
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
> - 删除域名是不可逆操作,请谨慎操作
|
||||||
|
> - 删除前请确保该域名下没有关联的邮箱账户
|
||||||
|
> - 删除后,该域名的所有邮箱服务将停止
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
| **错误码** | **说明** |
|
||||||
|
| --- | --- |
|
||||||
|
| 400 | 请求参数错误,domainId 格式不正确 |
|
||||||
|
| 401 | 认证失败,client-key 或 client-secret 无效 |
|
||||||
|
| 403 | 权限不足,无权删除该域名 |
|
||||||
|
| 404 | 域名不存在 |
|
||||||
|
| 409 | 域名下仍有活跃的邮箱账户,无法删除 |
|
||||||
|
| 500 | 服务器内部错误 |
|
||||||
400
docs/11-06_mailbox-mail-search.md
Normal file
400
docs/11-06_mailbox-mail-search.md
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
<!-- mipuyun-api-doc: mailbox-mail-search -->
|
||||||
|
# mailbox/mail/search - 搜索邮件
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
根据关键词、邮件类型等条件搜索邮件,返回分页结果。
|
||||||
|
|
||||||
|
### 使用场景
|
||||||
|
|
||||||
|
- 用户需要在邮箱中查找特定邮件
|
||||||
|
- 根据关键词、邮件类型等条件筛选邮件
|
||||||
|
- 分页浏览邮件列表
|
||||||
|
|
||||||
|
## 请求说明
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| **请求地址** | `https://${endpoint}/mailbox/mail/search` |
|
||||||
|
| **请求方法** | POST |
|
||||||
|
|
||||||
|
### Header 参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| Content-Type | String | 是 | application/json | 固定值,指定请求体格式为 JSON |
|
||||||
|
| Accept-Encoding | String | 是 | gzip, deflate, br | 必须要填写,否则服务器会拒绝 |
|
||||||
|
| client-key | String | 是 | xxxxx | 联系我们获取生产环境 key |
|
||||||
|
| client-secret | String | 是 | xxxxx | 联系我们获取生产环境 secret |
|
||||||
|
|
||||||
|
### 请求体参数
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 是否必选 | 示例值 | 说明 |
|
||||||
|
|----------|------|----------|--------|------|
|
||||||
|
| keyword | String | 否 | 机票 | 搜索关键词,支持邮件主题、发件人等 |
|
||||||
|
| mailType | Integer | 否 | 1 | 邮件类型:1-收件,2-发件 |
|
||||||
|
| domainName | String | 否 | example.com | 域名过滤 |
|
||||||
|
| hasAttachment | Boolean | 否 | true | 是否有附件 |
|
||||||
|
| readStatus | Integer | 否 | 0 | 阅读状态:0-未读,1-已读 |
|
||||||
|
| startTime | String | 否 | 2025-01-01T00:00:00Z | 起始时间(ISO 8601格式,**必须使用UTC时区**,以`Z`结尾) |
|
||||||
|
| endTime | String | 否 | 2025-01-31T23:59:59Z | 结束时间(ISO 8601格式,**必须使用UTC时区**,以`Z`结尾) |
|
||||||
|
| airlineCode | String | 否 | CA | 航空代码(如:CA-国航、MU-东航、CZ-南航等) |
|
||||||
|
| pageIndex | Integer | 是 | 1 | 页码,从1开始 |
|
||||||
|
| pageSize | Integer | 是 | 20 | 每页数量,建议10-50,最大100 |
|
||||||
|
| orderBy | String | 否 | sendTime | 排序字段,支持:`sendTime`(发送时间)、`receiveTime`(接收时间)、`subject`(主题) |
|
||||||
|
| orderDirection | String | 否 | DESC | 排序方向:`ASC`=升序,`DESC`=降序 |
|
||||||
|
|
||||||
|
#### 请求体示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"keyword": "机票",
|
||||||
|
"mailType": 1,
|
||||||
|
"airlineCode": "CA",
|
||||||
|
"pageIndex": 1,
|
||||||
|
"pageSize": 20,
|
||||||
|
"orderBy": "sendTime",
|
||||||
|
"orderDirection": "DESC"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 返回参数
|
||||||
|
|
||||||
|
返回分页结果 `PageResult<MailInfo>`:
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 示例值 | 说明 |
|
||||||
|
|----------|------|--------|------|
|
||||||
|
| pageIndex | Integer | 1 | 当前页码 |
|
||||||
|
| pageSize | Integer | 20 | 每页数量 |
|
||||||
|
| total | Long | 150 | 总记录数 |
|
||||||
|
| records | Array\<MailInfo\> | - | 邮件列表 |
|
||||||
|
|
||||||
|
> **注意**:
|
||||||
|
> - 请求和响应统一使用 `pageIndex`
|
||||||
|
> - 总页数 `totalPages` 字段已移除,前端需自行计算:`totalPages = Math.ceil(total / pageSize)`
|
||||||
|
|
||||||
|
### MailInfo 对象字段
|
||||||
|
|
||||||
|
| 参数名称 | 类型 | 示例值 | 说明 |
|
||||||
|
|----------|------|--------|------|
|
||||||
|
| mailId | String | MSG_001 | 邮件ID |
|
||||||
|
| subject | String | 机票预订确认 | 邮件主题 |
|
||||||
|
| fromAddress | String | airline@example.com | 发件人地址 |
|
||||||
|
| toAddresses | String\[\] | ["user@example.com"] | 收件人列表 |
|
||||||
|
| ccAddresses | String\[\] | ["cc@example.com"] | 抄送列表 |
|
||||||
|
| mailType | Integer | 1 | 邮件类型:1-收件,2-发件 |
|
||||||
|
| mailTypeText | String | 收件 | 类型文本 |
|
||||||
|
| hasAttachment | Boolean | true | 是否有附件 |
|
||||||
|
| attachmentCount | Integer | 2 | 附件数量 |
|
||||||
|
| mailSize | Long | 1024000 | 邮件大小(字节) |
|
||||||
|
| mailSizeText | String | 1.0 MB | 人性化大小 |
|
||||||
|
| readStatus | Integer | 0 | 阅读状态:0-未读,1-已读 |
|
||||||
|
| receiveTime | String | 2025-01-02T10:00:00Z | 接收时间 |
|
||||||
|
| sendTime | String | 2025-01-02T10:00:00Z | 发送时间 |
|
||||||
|
| emlDownloadUrl | String | https://... | 原始EML文件下载地址(临时链接,1小时有效期) |
|
||||||
|
|
||||||
|
## 返回示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pageIndex": 1,
|
||||||
|
"pageSize": 20,
|
||||||
|
"total": 150,
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"mailId": "MSG_001",
|
||||||
|
"subject": "机票预订确认",
|
||||||
|
"fromAddress": "airline@example.com",
|
||||||
|
"toAddresses": ["user@example.com"],
|
||||||
|
"ccAddresses": ["cc@example.com"],
|
||||||
|
"mailType": 1,
|
||||||
|
"mailTypeText": "收件",
|
||||||
|
"hasAttachment": true,
|
||||||
|
"attachmentCount": 2,
|
||||||
|
"mailSize": 1024000,
|
||||||
|
"mailSizeText": "1.0 MB",
|
||||||
|
"readStatus": 0,
|
||||||
|
"receiveTime": "2025-01-02T10:00:00Z",
|
||||||
|
"sendTime": "2025-01-02T10:00:00Z",
|
||||||
|
"emlDownloadUrl": "https://cdn.example.com/download/eml/MSG_001?token=xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mailId": "MSG_002",
|
||||||
|
"subject": "航班变更通知",
|
||||||
|
"fromAddress": "airline@example.com",
|
||||||
|
"toAddresses": ["user@example.com"],
|
||||||
|
"ccAddresses": [],
|
||||||
|
"mailType": 1,
|
||||||
|
"mailTypeText": "收件",
|
||||||
|
"hasAttachment": false,
|
||||||
|
"attachmentCount": 0,
|
||||||
|
"mailSize": 51200,
|
||||||
|
"mailSizeText": "50.0 KB",
|
||||||
|
"readStatus": 1,
|
||||||
|
"receiveTime": "2025-01-02T09:00:00Z",
|
||||||
|
"sendTime": "2025-01-02T09:00:00Z",
|
||||||
|
"emlDownloadUrl": "https://cdn.example.com/download/eml/MSG_002?token=yyy"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 时区说明
|
||||||
|
|
||||||
|
### UTC 时区要求
|
||||||
|
|
||||||
|
本接口要求所有时间参数**必须使用 UTC 时区**(协调世界时)。
|
||||||
|
|
||||||
|
**什么是 UTC?**
|
||||||
|
- UTC(Coordinated Universal Time)是世界标准时间,不受夏令时影响
|
||||||
|
- UTC 是全球统一的时间基准,与地理位置无关
|
||||||
|
- 北京时间 = UTC + 8小时,纽约时间 = UTC - 5小时(东部标准时间)
|
||||||
|
|
||||||
|
**为什么使用 UTC?**
|
||||||
|
1. **避免时区混淆**:不同地区的服务器和客户端使用不同时区会导致时间解释错误
|
||||||
|
2. **跨时区一致**:确保全球用户查询结果一致
|
||||||
|
3. **简化逻辑**:无需处理复杂的时区转换和夏令时问题
|
||||||
|
|
||||||
|
**时间格式要求:**
|
||||||
|
```
|
||||||
|
ISO 8601 格式:2025-01-15T00:00:00Z
|
||||||
|
^^^^^^^^^^^ ^^^^^^^ ^ ^
|
||||||
|
日期 时间 时区标识(UTC)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 时间转换示例
|
||||||
|
|
||||||
|
| 本地时间 | UTC 时间(需要发送) | 说明 |
|
||||||
|
|----------|---------------------|------|
|
||||||
|
| 2025-01-15 00:00:00 (北京) | 2025-01-14T16:00:00Z | 北京时间 UTC+8,减8小时 |
|
||||||
|
| 2025-01-15 00:00:00 (纽约) | 2025-01-15T05:00:00Z | 纽约时间 UTC-5,加5小时 |
|
||||||
|
| 2025-01-15 00:00:00 (伦敦) | 2025-01-15T00:00:00Z | 伦敦时间 UTC+0(冬季) |
|
||||||
|
| 2025-01-15 00:00:00 (东京) | 2025-01-14T15:00:00Z | 东京时间 UTC+9,减9小时 |
|
||||||
|
|
||||||
|
> **重要**:发送时间前,请务必将本地时间转换为 UTC 时间!
|
||||||
|
|
||||||
|
### 代码示例
|
||||||
|
|
||||||
|
#### Java 示例
|
||||||
|
|
||||||
|
```java
|
||||||
|
import java.time.*;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import okhttp3.*;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class MailSearchExample {
|
||||||
|
|
||||||
|
private static final String API_ENDPOINT = "https://api.example.com/mailbox/mail/search";
|
||||||
|
private static final String CLIENT_KEY = "your-client-key";
|
||||||
|
private static final String CLIENT_SECRET = "your-client-secret";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 方式1: 使用当前时间(自动转换为UTC)
|
||||||
|
ZonedDateTime nowUtc = ZonedDateTime.now(ZoneOffset.UTC);
|
||||||
|
ZonedDateTime oneDayAgoUtc = nowUtc.minusDays(1);
|
||||||
|
|
||||||
|
// 方式2: 从本地时间转换到UTC
|
||||||
|
ZonedDateTime localTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
|
||||||
|
ZonedDateTime utcTime = localTime.withZoneSameInstant(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
// 方式3: 指定特定时间(例如:北京时间2025-01-15 00:00:00)
|
||||||
|
ZonedDateTime beijingTime = ZonedDateTime.of(
|
||||||
|
2025, 1, 15, 0, 0, 0, 0,
|
||||||
|
ZoneId.of("Asia/Shanghai")
|
||||||
|
);
|
||||||
|
ZonedDateTime startTimeUtc = beijingTime.withZoneSameInstant(ZoneOffset.UTC);
|
||||||
|
ZonedDateTime endTimeUtc = beijingTime.plusDays(1).minusSeconds(1)
|
||||||
|
.withZoneSameInstant(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
// 格式化为ISO 8601格式(带Z后缀)
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
|
||||||
|
String startTime = startTimeUtc.format(formatter); // 2025-01-14T16:00:00Z
|
||||||
|
String endTime = endTimeUtc.format(formatter); // 2025-01-15T15:59:59Z
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
MailSearchRequest request = new MailSearchRequest();
|
||||||
|
request.setKeyword("机票");
|
||||||
|
request.setMailType(1);
|
||||||
|
request.setStartTime(startTime);
|
||||||
|
request.setEndTime(endTime);
|
||||||
|
request.setPageIndex(1);
|
||||||
|
request.setPageSize(20);
|
||||||
|
|
||||||
|
// 设置排序(按发送时间降序)
|
||||||
|
request.setOrderBy("sendTime");
|
||||||
|
request.setOrderDirection("DESC");
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
sendRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MailSearchRequest {
|
||||||
|
private String keyword;
|
||||||
|
private Integer mailType;
|
||||||
|
private String startTime;
|
||||||
|
private String endTime;
|
||||||
|
private Integer pageIndex;
|
||||||
|
private Integer pageSize;
|
||||||
|
private String orderBy;
|
||||||
|
private String orderDirection;
|
||||||
|
|
||||||
|
// getters and setters...
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendRequest(MailSearchRequest request) throws Exception {
|
||||||
|
Gson gson = new Gson();
|
||||||
|
String json = gson.toJson(request);
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient();
|
||||||
|
RequestBody body = RequestBody.create(
|
||||||
|
json,
|
||||||
|
MediaType.parse("application/json; charset=utf-8")
|
||||||
|
);
|
||||||
|
|
||||||
|
Request httpRequest = new Request.Builder()
|
||||||
|
.url(API_ENDPOINT)
|
||||||
|
.post(body)
|
||||||
|
.addHeader("Content-Type", "application/json")
|
||||||
|
.addHeader("Accept-Encoding", "gzip, deflate, br")
|
||||||
|
.addHeader("client-key", CLIENT_KEY)
|
||||||
|
.addHeader("client-secret", CLIENT_SECRET)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(httpRequest).execute()) {
|
||||||
|
System.out.println(response.body().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Python 示例
|
||||||
|
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
from zoneinfo import ZoneInfo # Python 3.9+
|
||||||
|
import json
|
||||||
|
|
||||||
|
API_ENDPOINT = "https://api.example.com/mailbox/mail/search"
|
||||||
|
CLIENT_KEY = "your-client-key"
|
||||||
|
CLIENT_SECRET = "your-client-secret"
|
||||||
|
|
||||||
|
def search_mails():
|
||||||
|
# 方式1: 使用当前UTC时间
|
||||||
|
now_utc = datetime.now(timezone.utc)
|
||||||
|
one_day_ago_utc = now_utc - timedelta(days=1)
|
||||||
|
|
||||||
|
# 方式2: 从本地时间转换到UTC(例如:北京时间)
|
||||||
|
beijing_tz = ZoneInfo("Asia/Shanghai")
|
||||||
|
local_time = datetime(2025, 1, 15, 0, 0, 0, tzinfo=beijing_tz)
|
||||||
|
start_time_utc = local_time.astimezone(timezone.utc)
|
||||||
|
end_time_utc = (local_time + timedelta(days=1) - timedelta(seconds=1)).astimezone(timezone.utc)
|
||||||
|
|
||||||
|
# 方式3: 直接创建UTC时间
|
||||||
|
start_time_utc = datetime(2025, 1, 14, 16, 0, 0, tzinfo=timezone.utc)
|
||||||
|
end_time_utc = datetime(2025, 1, 15, 15, 59, 59, tzinfo=timezone.utc)
|
||||||
|
|
||||||
|
# 格式化为ISO 8601格式(带Z后缀)
|
||||||
|
start_time = start_time_utc.isoformat()
|
||||||
|
end_time = end_time_utc.isoformat()
|
||||||
|
# 结果: "2025-01-14T16:00:00+00:00" 或 "2025-01-14T16:00:00Z"
|
||||||
|
|
||||||
|
# 确保以Z结尾(某些库可能使用+00:00)
|
||||||
|
if not start_time.endswith('Z'):
|
||||||
|
start_time = start_time.replace('+00:00', 'Z').replace('+00:00:00', 'Z')
|
||||||
|
if not end_time.endswith('Z'):
|
||||||
|
end_time = end_time.replace('+00:00', 'Z').replace('+00:00:00', 'Z')
|
||||||
|
|
||||||
|
# 构建请求体
|
||||||
|
payload = {
|
||||||
|
"keyword": "机票",
|
||||||
|
"mailType": 1,
|
||||||
|
"startTime": start_time, # "2025-01-14T16:00:00Z"
|
||||||
|
"endTime": end_time, # "2025-01-15T15:59:59Z"
|
||||||
|
"pageIndex": 1,
|
||||||
|
"pageSize": 20,
|
||||||
|
"orderBy": "sendTime",
|
||||||
|
"orderDirection": "DESC"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 发送请求
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
|
"client-key": CLIENT_KEY,
|
||||||
|
"client-secret": CLIENT_SECRET
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
API_ENDPOINT,
|
||||||
|
data=json.dumps(payload),
|
||||||
|
headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Status Code: {response.status_code}")
|
||||||
|
print(f"Response: {response.json()}")
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
# 常用时区转换工具函数
|
||||||
|
def convert_to_utc(local_time_str, local_timezone="Asia/Shanghai"):
|
||||||
|
"""
|
||||||
|
将本地时间字符串转换为UTC时间字符串
|
||||||
|
|
||||||
|
Args:
|
||||||
|
local_time_str: 本地时间,如 "2025-01-15 00:00:00"
|
||||||
|
local_timezone: 本地时区,默认 "Asia/Shanghai"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
UTC时间字符串,如 "2025-01-14T16:00:00Z"
|
||||||
|
"""
|
||||||
|
local_tz = ZoneInfo(local_timezone)
|
||||||
|
local_dt = datetime.strptime(local_time_str, "%Y-%m-%d %H:%M:%S")
|
||||||
|
local_dt = local_dt.replace(tzinfo=local_tz)
|
||||||
|
utc_dt = local_dt.astimezone(timezone.utc)
|
||||||
|
return utc_dt.isoformat().replace('+00:00', 'Z')
|
||||||
|
|
||||||
|
# 使用示例
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 北京时间 2025-01-15 00:00:00 转换为 UTC
|
||||||
|
utc_time = convert_to_utc("2025-01-15 00:00:00", "Asia/Shanghai")
|
||||||
|
print(f"UTC Time: {utc_time}") # 输出: 2025-01-14T16:00:00Z
|
||||||
|
|
||||||
|
search_mails()
|
||||||
|
```
|
||||||
|
|
||||||
|
#### cURL 示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "https://api.example.com/mailbox/mail/search" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Accept-Encoding: gzip, deflate, br" \
|
||||||
|
-H "client-key: your-client-key" \
|
||||||
|
-H "client-secret: your-client-secret" \
|
||||||
|
-d '{
|
||||||
|
"keyword": "机票",
|
||||||
|
"mailType": 1,
|
||||||
|
"startTime": "2025-01-14T16:00:00Z",
|
||||||
|
"endTime": "2025-01-15T15:59:59Z",
|
||||||
|
"pageIndex": 1,
|
||||||
|
"pageSize": 20,
|
||||||
|
"orderBy": "sendTime",
|
||||||
|
"orderDirection": "DESC"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 搜索技巧
|
||||||
|
|
||||||
|
- 支持模糊匹配,关键词可以匹配邮件主题和发件人
|
||||||
|
- mailType 为可选参数,不传则搜索所有类型邮件
|
||||||
|
- 建议 pageSize 设置为 20-50 以获得最佳性能
|
||||||
|
- **时间参数必须使用 UTC 时区**,发送前请确保时间已正确转换
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
| 错误码 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| 400 | 请求参数错误,pageIndex、pageSize、orderBy 或 orderDirection 不合法 |
|
||||||
|
| 401 | 认证失败,client-key 或 client-secret 无效 |
|
||||||
|
| 500 | 服务器内部错误 |
|
||||||
55
docs/11_proxy-conventions.md
Normal file
55
docs/11_proxy-conventions.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<!-- mipuyun-api-doc: 11_proxy-conventions -->
|
||||||
|
# Proxy约定说明
|
||||||
|
|
||||||
|
用户可在luban系统(my.mipuyun.com)管理我们提供的高质量住宅代理。
|
||||||
|
|
||||||
|
为了更有效的使用代理,对于Proxy字段的发送提供以下约定
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 指定代理地区/国家
|
||||||
|
|
||||||
|
在proxy名后拼接 `-国家码(地区码)`,myproxy是代理命名,举例如下:
|
||||||
|
|
||||||
|
| 地区(国家) | 码 | Proxy命名举例 |
|
||||||
|
|-----------|---|--------------|
|
||||||
|
| 美国 | us | myproxy-us |
|
||||||
|
| 法国 | fr | myproxy-fr |
|
||||||
|
| 英国 | uk | myproxy-uk |
|
||||||
|
| **欧洲** | **eu** | **myproxy-eu** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 利用多个代理提升agent质量
|
||||||
|
|
||||||
|
为提升agent对接的质量,支持在proxy字段输入多个代理,并提供串行和并发来满足各种场景
|
||||||
|
|
||||||
|
### 拼接符号介绍
|
||||||
|
|
||||||
|
| 符号 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **竖线 \|** | 多个代理随机选择 |
|
||||||
|
| **逗号 ,** | 多个代理串行选择,希望提升成功率,但可以接受响应速度略慢的场景 |
|
||||||
|
| **加号 +** | 多个代理并发执行,应用于有较高成功率&较低响应速度的场景 |
|
||||||
|
|
||||||
|
### 代理使用示例
|
||||||
|
|
||||||
|
| 代理举例 | 适合场景 | 效果 |
|
||||||
|
|----------|---------|------|
|
||||||
|
| myproxy-us | 所有场景 | 指定US地区进行agent执行 |
|
||||||
|
| myproxy-us\|myproxy-uk | 所有场景 | 从US, UK两个地区随机选择一个进行agent执行 |
|
||||||
|
| myproxy-us\|myproxy-uk,myproxy-us\|myproxy-eu | **shopping/search** | 仅对shpping/search生效,可接受较大的响应时长等待,第一轮采用myproxy-us\|myproxy-uk进行对接。如果成功,立即返回结束业务。如果失败,采用myproxy-us\|myproxy-eu启动第二轮对接。 |
|
||||||
|
| myproxy-us + myproxy-uk | **shopping/select**<br>**shopping/baggage**<br>**shopping/seat** | 采用多线程并发模式,线程a采用myproxy-us,线程b采用myproxy-uk, 同时向航司发起业务请求。 |
|
||||||
|
| myproxy-us\|myproxy-eu + myproxy-uk\|myproxy-uk | **shopping/select**<br>**shopping/baggage**<br>**shopping/seat** | 采用多线程并发模式,线程a采用myproxy-us\|myproxy-eu,线程b采用myproxy-uk\|myproxy-uk, 同时向航司发起业务请求。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 异常处理
|
||||||
|
|
||||||
|
### 如果将符号用在了不支持的场景怎么办?
|
||||||
|
|
||||||
|
系统会最大限度接受异常的代理串输入,但会选择最保守的执行方式,我们会采集最小的代理信息进行执行。
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
- 并发场景(select/baggage/seat)收到逗号:`myproxy-us,myproxy-uk`
|
||||||
|
- 那么执行层会变成:`myproxy-us`
|
||||||
157
docs/12_brightdata-proxy-advanced.md
Normal file
157
docs/12_brightdata-proxy-advanced.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<!-- mipuyun-api-doc: 12_brightdata-proxy-advanced -->
|
||||||
|
# BrightData 代理串高级用法
|
||||||
|
|
||||||
|
# 📄 BrightData 代理 URL 使用指南
|
||||||
|
|
||||||
|
**适用于:BrightData Residential / Datacenter / Mobile Proxies**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 1. 代理 URL 格式解析
|
||||||
|
|
||||||
|
示例 URL:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
http://brd-customer-hl_333c2-zone-myproxy-country-us-session-11111vy0c
|
||||||
|
```
|
||||||
|
|
||||||
|
### ✅ 结构拆解:
|
||||||
|
|
||||||
|
| **部分** | **说明** |
|
||||||
|
| --- | --- |
|
||||||
|
| brd-customer-hl_665225c2 | 客户 ID(固定,由 BrightData 分配) |
|
||||||
|
| zone=myproxy | 代理子账号名称 |
|
||||||
|
| country=us | 目标国家代码(ISO 3166-1 alpha-2,如 us, gb, jp) |
|
||||||
|
| session=11111vy0c | 会话 ID(用于控制 IP 是否复用) |
|
||||||
|
| proxypassword | 代理子账号密码 |
|
||||||
|
| brd.superproxy.io:22225 | BrightData 全球统一代理网关 |
|
||||||
|
|
||||||
|
> 💡 **关键参数均通过用户名(username)中的字段传递**,这是 BrightData 的特殊设计。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌍 2. 如何指定国家(Country)
|
||||||
|
|
||||||
|
只需修改 `country=xx` 部分即可。
|
||||||
|
|
||||||
|
### 示例:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
# 美国 IP
|
||||||
|
...-country-us-...
|
||||||
|
|
||||||
|
# 英国 IP
|
||||||
|
...-country-gb-...
|
||||||
|
|
||||||
|
# 日本 IP
|
||||||
|
...-country-jp-...
|
||||||
|
|
||||||
|
# 德国 IP
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ 支持所有 BrightData 覆盖的国家([完整国家列表](https%3A%2F%2Fbrightdata.com%2Fcountries))
|
||||||
|
> ⚠️ 如果指定的国家无可用 IP,请求可能失败或返回默认地区 IP(取决于 Zone 设置)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔁 3. 如何更换 IP(获取新 IP)
|
||||||
|
|
||||||
|
BrightData 使用 `**session**`** 参数控制 IP 复用**:
|
||||||
|
|
||||||
|
- **相同 **`**session**`** 值 → 复用同一个出口 IP**(通常维持 5 分钟以上)
|
||||||
|
- **不同 **`**session**`** 值 → 获取全新 IP**
|
||||||
|
### ✅ 方法:修改 `session` 字段
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
# Session A: 固定 IP #1
|
||||||
|
...-session-abc123@...
|
||||||
|
|
||||||
|
# Session B: 固定 IP #2(与 abc123 不同)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
> 🔑 **只要 **`**session**`** 值不同,就会分配新 IP**(即使其他参数相同)
|
||||||
|
|
||||||
|
### 💡 编程建议:
|
||||||
|
|
||||||
|
在代码中动态生成随机 session ID 来每次获取新 IP:
|
||||||
|
|
||||||
|
```
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
def generate_session_id(length=10):
|
||||||
|
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
||||||
|
|
||||||
|
session = generate_session_id()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 4. 如何保持 IP 不变(固定 IP)
|
||||||
|
|
||||||
|
只需 **在多次请求中使用相同的 **`**session**`** 值**。
|
||||||
|
|
||||||
|
### ✅ 规则:
|
||||||
|
|
||||||
|
- 同一个 `session` 在 **5 分钟内有效**
|
||||||
|
- 在此期间,所有使用该 session 的请求将通过 **同一个出口 IP**
|
||||||
|
- 超过 5 分钟无活动,IP 可能被回收
|
||||||
|
### 示例(固定美国 IP):
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
http://brd-customer-hl_665225c2-zone-myproxy-country-us-session-my_fixed_ip_001:xxxxy0c@brd.superproxy.io:22225/
|
||||||
|
```
|
||||||
|
|
||||||
|
> 🕒 建议:如果需要长时间固定 IP,每 5~8 分钟发一次心跳请求以保持会话活跃。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ 5. 完整使用示例(Python requests)
|
||||||
|
|
||||||
|
```
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# 固定美国 IP(session = "my_session_1")
|
||||||
|
proxy_url = "http://brd-customer-hl_665225c2-zone-myproxy-country-us-session-my_session_1:xxxxy0c@brd.superproxy.io:22225/"
|
||||||
|
|
||||||
|
proxies = {
|
||||||
|
"http": proxy_url,
|
||||||
|
"https": proxy_url
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
|
||||||
|
print(resp.json()) # 显示出口 IP
|
||||||
|
except Exception as e:
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ 6. 其他高级参数(可选)
|
||||||
|
|
||||||
|
你还可以在 username 中添加更多参数(用 `-` 连接):
|
||||||
|
|
||||||
|
[电子表格]
|
||||||
|
|
||||||
|
> 📌 完整参数文档:[BrightData Proxy Parameters](https%3A%2F%2Fdocs.brightdata.com%2Fapi-reference%2Fproxy%2Fgeolocation-targeting%23city-targeting)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❗ 注意事项
|
||||||
|
|
||||||
|
1. **密码(**`**proxypassword**`**)是敏感信息**,切勿泄露或提交到 Git。
|
||||||
|
1. **不要硬编码 session** 用于大规模爬虫,避免 IP 被目标网站封禁。
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 总结:核心操作速查
|
||||||
|
|
||||||
|
[电子表格]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
29
docs/README.md
Normal file
29
docs/README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!-- mipuyun-api-doc: overview -->
|
||||||
|
# 米普云 - 航司接口转换器API文档
|
||||||
|
|
||||||
|
## 什么是航司接口转换器
|
||||||
|
|
||||||
|
航司接口转换器是一种中间服务工具,用于将不同航空公司的预订、出票、查询等系统接口进行标准化和适配。由于各航司的系统架构、数据格式、认证方式各不相同,直接对接成本高、开发周期长。航司接口转换器通过统一的接入层,帮助第三方平台(如OTA、旅行社、企业差旅系统等)快速、高效地与多个航司系统对接。
|
||||||
|
|
||||||
|
该转换器的核心功能包括:
|
||||||
|
|
||||||
|
- **协议转换**:将不同航司的私有API或B2B协议转换为通用标准
|
||||||
|
- **数据映射**:将航司返回的原始数据结构转换为易于理解和处理的统一格式
|
||||||
|
- **身份代理**:通过Agent机制,自动完成登录、鉴权、会话维持等操作
|
||||||
|
- **稳定性保障**:提供重试机制、错误处理、日志记录等功能,提升对接稳定性
|
||||||
|
|
||||||
|
## 如何使用航司接口转换器
|
||||||
|
|
||||||
|
### 1. 选择需要转换的航司&渠道
|
||||||
|
|
||||||
|
访问 https://my.mipuyun.com,登录后选择:航司列表菜单,在你需要转换的航司上面选择对应的渠道,一般渠道有 Web(官网)/B2B/API。
|
||||||
|
|
||||||
|
### 2. 创建Agent
|
||||||
|
|
||||||
|
### 3. 在线测试
|
||||||
|
|
||||||
|
创建好 Agent 后,可在控制台中选择该 Agent 并点击"运行"按钮,立即发起一次测试请求。
|
||||||
|
|
||||||
|
### 4. 通过API与我们对接
|
||||||
|
|
||||||
|
当测试成功后,你可以调用我们的开放 API 接口,实现全流程自动化。
|
||||||
1
mipu-api
Submodule
1
mipu-api
Submodule
Submodule mipu-api added at 628155990a
Reference in New Issue
Block a user