铁路出行服务
火车票查询 · HTTP / JSON

家驿 · 接口契约文档

从第一条请求开始,清晰了解家驿的查询接口、报文约定与业务边界。

接入概览

本文档描述当前后端实现中的火车票查询能力。客户 OpenAPI 提供车次余票、经停站、儿童票价格与区间里程查询;车站起售时间见扩展接口章节。文档可公开阅读,接口调用仍需完成客户开通。

接入前向接口负责人获取:环境 Base URL、supplierId、secretKey、服务器时区与查询权限。本文不提供生产凭据或环境地址。
接口方式路径
余票/车次查询POST/supplier/vendor/openApi/queryTrains
经停站查询POST/supplier/vendor/openApi/queryTrainStop
儿童票价格计算POST/supplier/vendor/openApi/childTicketPrice
车次区间里程POST/supplier/vendor/openApi/queryTrainMileage

路径相对于环境 Base URL;本站网关前缀为 /api,拼接时不要重复添加。Content-Type: application/json;报文采用 UTF-8。请使用 HTTPS,并在服务端完成签名和加解密。

签名与报文约定

  1. 生成当前时间 timeStamp,格式 yyyy-MM-dd HH:mm:ss。按北京时间联调并确认服务端时区,时钟误差控制在 1 分钟内,每次请求刷新时间。
  2. 依次直接拼接 timeStamp + supplierId + secretKey,不加分隔符,计算 MD5 十六进制摘要作为 messageIdentity。服务端比较不区分大小写。
  3. 将业务 JSON 的 UTF-8 字节用分配的密钥进行 AES/ECB/PKCS7Padding 加密,再进行标准 Base64 编码,写入 bodyInfo。Java 对应 AES/ECB/PKCS5Padding,无 IV。
  4. 请求路径决定调用接口,serviceName 填对应的接口名。密钥按接入方分配值使用,不做 MD5 或 Base64 派生。

以下仅展示报文结构,尖括号内容均须替换,不能直接发送。

{
  "authentication": {
    "timeStamp": "<当前时间>",
    "serviceName": "queryTrains",
    "supplierId": "<分配的客户标识>",
    "messageIdentity": "<计算得到的 MD5 摘要>"
  },
  "bodyInfo": "<业务 JSON 加密后的 Base64 密文>"
}

统一响应

{
  "errNo": 0,
  "errMsg": "SUCCESS",
  "bodyInfo": "<响应业务 JSON 的 Base64 密文>"
}

先判断 errNo == 0,再使用同一密钥解密 bodyInfo 并解析 JSON。失败时读取 errNo 和 errMsg,bodyInfo 可能为空或不返回。HTTP 成功不等于业务成功。

01 / 余票与车次查询

POST /supplier/vendor/openApi/queryTrains

serviceName:queryTrains。返回车次时刻、席别票价及余票;经停信息通过独立接口查询。此接口需开通客户生产查询权限。

业务请求字段(加密前)

字段类型要求说明
ticketDatestring必传乘车日期,yyyy-MM-dd
fromStationstring必传出发站名称,按环境支持的车站名称传入
toStationstring必传到达站名称
trainNostring车次列表可选;经停必传对外车次号,例如 G1

不传 seatName;即使传入,当前接口也会忽略该字段。

{
  "ticketDate": "2026-10-20",
  "fromStation": "北京南",
  "toStation": "上海虹桥",
  "trainNo": "G1"
}

响应业务体(解密后)

trainList 为车次数组,无匹配结果可返回空数组。以下是空结果示例,不是实时查询。

{
  "trainList": []
}

trainList[] 字段

字段类型说明
trainNostring车次号
trainTypestring列车类型(高速/动车/普速/直达 等)
trainDatestring发车日期 yyyy-MM-dd
trainDateTimestring出发时间 HH:mm
arriveDatestring到达日期 yyyy-MM-dd
arriveDateTimestring到达时间 HH:mm
fromStationNamestring发站
toStationNamestring到站
durationMinutesinteger历时分钟
seatOptionsarray<object>座位详情列表(多种座位类型的价格/库存)
quickPassEnabledinteger是否支持快速进站,1=支持 0=不支持
bookablestring>=0 正常售票 -1 不可购票
canChooseBedstring是否可选铺位:1 可选铺,0 不可选铺
isDghstring是否是动高:1 是,0 否
isStartStationboolean是否是始发站:true 是,false 否
isEndStationboolean是否是终点站:true 是,false 否
preSaleStartTimestring预售时间(已开始售票则取时间最小值)
intelligentTrainstring是否智能动车组(1=是 其他否)
hasQuietCoachstring是否有静音车厢(1=是 其他否)
rejuvenationTrainstring是否复兴号(1=是 其他否)

seatOptions[] 字段

字段类型说明
seatNamestring座位类型(硬座/软座/硬卧/软卧 等)
pricenumber该座位类型票价(元)
availableSeatsinteger剩余座位数量
lowerBerthPricenumber下铺价格(仅卧铺票存在)
middleBerthPricenumber中铺价格(仅卧铺票存在)
upperBerthPricenumber上铺价格(仅卧铺票存在)
discountstring票价折扣标识,例:"9.7"
lowerBerthDiscountstring下铺折扣
middleBerthDiscountstring中铺折扣
upperBerthDiscountstring上铺折扣
金额单位为元。字段可能随数据源缺失而为空;不要将 null 视为 0。余票、可售状态和票价均为查询结果,不代表库存锁定或出票承诺。

02 / 经停站查询

POST /supplier/vendor/openApi/queryTrainStop

serviceName:queryTrainStop。ticketDate、fromStation、toStation、trainNo 均应提供,字段格式见上表。

{
  "ticketDate": "2026-10-20",
  "fromStation": "北京南",
  "toStation": "上海虹桥",
  "trainNo": "G1"
}

响应业务体

字段类型说明
trainNostring查询车次号
originStationstring列车始发站
terminalStationstring列车终点站
stopListarray经停站列表,需兼容为空或缺失

stopList[] 字段

字段类型说明
serialNointeger经停站排列序号
stationCodestring出发站三字码(如 AOH = 上海虹桥)
stationNamestring出发站名称
trainTimestring出发时间 HH:mm
arrivalTimestring到达时间 HH:mm
stayMinutesstring停留时间(单位:分钟)
mileageKmstring自始发站累计运价里程(公里)

累计里程字段可能缺失,不能直接替代区间票价。始发站的到达时刻和终到站的发车时刻请兼容空值。

儿童票价格计算 · childTicketPrice

POST /supplier/vendor/openApi/childTicketPrice。authentication.serviceName 必须为 childTicketPrice,沿用本文的签名与 AES 加密协议。以下 JSON 是加密前的业务体,不能直接作为完整请求发送。

{
  "trainNo": "D1",
  "ticketDate": "2026-10-20",
  "fromStation": "北京南",
  "toStation": "上海虹桥",
  "seatName": "二等卧",
  "berth": "DOWN",
  "adultPrice": 100,
  "discount": 8.5
}

示例不代表实际车次及票价。trainNo、seatName、adultPrice 必填。adultPrice 为所选席别、铺位的成人实际执行价(元),必须大于 0。discount 大于 0 且不超过 10,8.5 表示八五折;不传或 10 表示无折扣。有折扣时还必须提供 ticketDate、fromStation、toStation,系统查询原价后计算;无折扣直接计算,不重复乘成人折扣。

卧铺必须传 berth:UP(上)、MIDDLE(中)、DOWN(下)。中铺仅支持硬卧、二等卧;座席不传 berth。adultPricesBySeat 可补充普速卧铺基础座席执行价,例如 {"硬座":160};缺失时可能采用估算规则。

解密后的响应字段

字段含义
statusSUCCESS / MISSING_BASE_PRICE / UNSUPPORTED_SEAT / INVALID_PRICE
calculatedPrice儿童票计算价(元);失败时可能为空或缺失
discountRate命中的儿童优惠比例,不是请求的成人折扣
ruleCode、dataCompleteness计算规则及数据完整性标记,应保留用于识别估算
message不能计算时的说明

外层 errNo=0 只表示接口执行成功;解密后必须检查 status。参考计算结果不构成实际售票价格承诺。

车次区间里程 · queryTrainMileage

POST /supplier/vendor/openApi/queryTrainMileage。authentication.serviceName 必须为 queryTrainMileage。请求使用同一签名、加密协议,业务体示例:

{
  "ticketDate": "2026-10-20",
  "trainNo": "G1",
  "fromStation": "北京南",
  "toStation": "上海虹桥"
}

四个字段均必填。日期为有效 yyyy-MM-dd,车站使用完整站名,到达站必须位于出发站之后。

解密后的响应字段

字段含义
statusSUCCESS 或 UNAVAILABLE
ticketDate、trainNo、fromStation、toStation请求日期、车次和区间
mileageKm区间公里数;未知为 null 或缺失,不以 0 代替
sourceLIANTIE / LOCAL_GRAPH
methodCUMULATIVE_DIFFERENCE(累计公里相减)或 STOP_ROUTE_SHORTEST_PATH(沿经停序列逐段计算)
mileageTypeSUPPLIER_REPORTED 或 FARE_GRAPH_ESTIMATE
estimatedtrue 表示本地图或代理日期估算;false 不代表与 12306 核验一致
dataDate实际使用的经停数据查询日期
reason不可用原因:STOP_ROUTE_UNAVAILABLE / MILEAGE_DATA_INCOMPLETE / LOCAL_GRAPH_UNAVAILABLE

必须同时检查外层 errNo 和业务体 status。里程不能替代票价查询,不保证等同于计价所用运价里程。

这两个新增 OpenAPI 沿用现有查询客户的开通范围。未配置或未开通返回 998;计算参数或基础数据不满足要求返回 2011;解析失败返回 6。不要把失败或 UNAVAILABLE 显示成 0 元、0 公里。

错误处理

errNo含义处理建议
0成功解密并解析 bodyInfo
1参数错误检查请求及必需字段
2签名错误/时间戳过期核对时钟、标识、密钥及拼接顺序
6数据解析错误检查密钥、填充及 Base64 编码
2011计算参数或基础数据不满足要求核对席别、铺位、折扣及区间,或联系接口负责人
998接口配置缺失或客户未开通联系接口负责人确认配置和权限
999系统内部异常记录接口、调用时间与错误码,交由对接人员排查

兼容未知非零错误码,展示明确的查询失败提示。空列表属于无结果,不能与接口失败混淆。调用频率、超时与重试策略按双方联调约定配置;本文不承诺未经约定的 SLA。

扩展平台接口

本节接口使用登录鉴权,且要求 order:train:list 权限,不使用上述 OpenAPI authentication/bodyInfo 报文。仅供已获授权的接入方使用;账号、登录方式和网关前缀由接口负责人提供。
接口方法与路径关键参数
车站起售时间GET /order/train/stationSaleTimestation、queryDate 均可选
车次区间里程GET /order/train/mileageticketDate、trainNo、fromStation、toStation 均必传
儿童票价格计算POST /order/train/childTicketPriceJSON 请求;trainNo、seatName、adultPrice 必传

统一使用 AjaxResult 包装(code、msg、data),成功 code 为 200。还需判断 data.status,不能只检查外层成功码。

车站起售时间

station 支持完整站名(可带“站”后缀)或三字电报码;不传则返回全部有效车站。queryDate 为 yyyy-MM-dd,默认北京时间当天。

data 返回 status、queryDate、timezone、stations;每个车站包含 stationName、stationTelecode、saleTime、startDate、stopDate、sourceType、lastRefreshTime。status 为 SUCCESS 或 NOT_FOUND,无记录时 stations 为空数组。saleTime 为 HH:mm,每日起售时刻不等于具体乘车日开售时间,也不代表实时可售。

车次区间里程

日期格式 yyyy-MM-dd;使用完整站名,到达站必须位于出发站之后。data 包含 status、ticketDate、trainNo、fromStation、toStation、mileageKm、source、method、mileageType、estimated、dataDate、reason。

status 为 SUCCESS 或 UNAVAILABLE;未知里程为 null。estimated 标识估算,dataDate 表示实际使用的经停查询日期。里程不可直接替代票价查询。

儿童票价格计算

{
  "trainNo": "D1",
  "seatName": "二等卧",
  "adultPrice": 100,
  "berth": "DOWN",
  "discount": 10
}

仅为参数示例,金额不是真实票价。adultPrice 为所选席别铺位的成人实际执行价(元);discount 大于 0 且不超过 10,8.5 表示八五折。不传或 10 为无折扣,有折扣时另需 ticketDate、fromStation、toStation。

卧铺必须提供 berth:UP、MIDDLE、DOWN;中铺仅接受硬卧、二等卧。座席不传 berth。adultPricesBySeat 可提供基础座席执行价,如 {"硬座":160}。

data 包含 status、calculatedPrice、discountRate、ruleCode、dataCompleteness、message。status 为 SUCCESS、MISSING_BASE_PRICE、UNSUPPORTED_SEAT 或 INVALID_PRICE。缺失基础座席价格可能使用估算规则,应同时读取规则与完整性标记;参数错误和原价缺失走统一异常响应。

联调检查清单

  • 确认环境地址、客户标识、密钥和生产查询权限。
  • 验证签名、报文加解密、当前时间及服务端时区。
  • 验证正常结果、空列表、空字段、错误签名和未开通场景。
  • 兼容跨日到达日期,价格保留小数,业务失败不展示为“无票”。
  • 密钥仅存储于服务端,不放入网页、浏览器存储或公开代码。

文档更新日期:2026-10-14。接口基于当前项目实现整理,环境与授权范围以实际交付为准。