Sabre SOAP API 航班搜索、支付与预订流程咨询
结论
不建议采用“BargainFinderMaxRQ 报价 → 立即完成外部扣款 → CreatePassengerNameRecordRQ 建立 PNR”的处理顺序。
BargainFinderMaxRQ 返回的是购物阶段的可用报价,并不会锁定价格。从搜索到建单期间,航班库存、订座舱位、税费、汇率和票价规则都可能变化。CreatePassengerNameRecordRQ 重新订座和计价后出现价格差异,是系统必须处理的正常业务场景,不能假设两次结果一定相同。
建议采用以下流程:
- 使用
BargainFinderMaxRQ搜索并展示参考价格。 - 客户选定行程后,重新验证该行程的可用性和价格。
- 向客户展示重新验证后的最终金额,并要求确认。
- 对支付执行 authorization,暂不 capture。
- 使用
CreatePassengerNameRecordRQ订座、重新计价并创建 PNR。 - 检查 PNR 中保存的价格是否与授权金额一致。
- 金额一致且操作成功时执行 capture;操作失败或金额变化时 void authorization。
- 按出票机器人服务商的要求设置 ticketing arrangement,并将成功创建的 PNR 放入其 PCC 的指定 queue。
- 持续跟踪出票结果、票号、出票失败和支付退款。
出票机器人一般不影响搜索逻辑,但会改变 PNR 的完整性要求、ticketing field、付款方式约定、queue 操作和失败补偿流程。不能仅凭“由机器人出票”判断 7TAW 是否适用,具体格式和时限必须由机器人服务商确认。
为什么两次价格可能不同
BargainFinderMaxRQ 主要用于搜索可售组合。结果返回后,对应舱位和价格通常没有为客户锁定。真正建立 PNR 时,可能出现以下变化:
- 原 booking class 已无库存,只能订入其他舱位。
- 航空公司更新了 fare、税费或 surcharge。
- 搜索结果中的 fare basis 在重新计价时已不可用。
- married segment、品牌运价或私有运价的适用条件发生变化。
- 搜索请求和建 PNR 请求使用了不同的 PCC、货币、乘客类型或 account code。
CreatePassengerNameRecordRQ的AirPrice配置与BargainFinderMaxRQ的 pricing qualifiers 不一致。- 搜索和建立 PNR 之间间隔过长。
- 航段订入后再次计价时,Sabre 返回的是当前可售价格,而不是之前的购物价格。
因此,不能直接把 BargainFinderMaxRQ 返回的金额作为外部支付网关的最终扣款金额。
推荐流程
1. 搜索阶段
通过 BargainFinderMaxRQ 获取行程、booking class、fare basis、品牌信息、行李和价格。保存后续重建所选行程所需的字段,但不要把保存响应视为锁价。
搜索与后续计价应尽量使用相同的条件,包括:
- PCC 和认证上下文
- POS
- currency
- passenger type code
- passenger count
- account code 或 corporate ID
- public/private fare 设置
- validating carrier
- cabin 和 branded fare 条件
2. 支付前重新验证
客户提交乘客资料并准备付款时,应再次检查航班和价格。
具体使用哪项服务,取决于客户实际开通的 Sabre API、工作流和版本。可选方式可能包括 itinerary revalidation、availability/pricing 服务,或者先建立可取消的 held PNR,再进行重新计价。不能只看 API 名称,就假设账户已经具备相应服务。
支付页面显示的最终金额必须来自紧邻支付和订座操作的最新验证结果,不能继续使用较早的搜索响应。
如果验证后金额发生变化,应按以下方式处理:
- 不发起扣款。
- 向客户展示新金额。
- 要求客户重新确认。
- 客户确认后,再继续支付和建立 PNR。
3. 支付采用 authorization/capture 两阶段模式
如果 payment gateway 支持,优先使用以下流程:
Revalidate price
↓
Authorize payment
↓
Create and price PNR
↓
Compare authorized amount with PNR price
├─ Match: capture payment, then queue PNR
└─ Mismatch/failure: void authorization
authorization 也不能无限期保证资金可用,因此必须明确授权有效期、capture 超时以及失败后的处理规则。
如果网关只支持立即 capture,就需要在以下两种方案之间选择,并建立相应的补偿机制:
- 先扣款:订座失败后必须自动退款。
- 先建 held PNR:支付失败后必须取消 PNR,释放库存。
通常情况下,先建立短期 held PNR,确认价格后再收款,更容易保证支付金额与 PNR 价格一致。但能否这样处理,以及 PNR 可以保留多久,仍需遵守航空公司的 ticketing time limit 和 Sabre 返回的限制。
CreatePassengerNameRecordRQ 应承担什么职责
CreatePassengerNameRecordRQ 可以编排订座、乘客资料、联系方式、计价、ticketing field 和结束交易等步骤。不过,“一次调用”不代表它与外部支付系统之间具备事务原子性。
下面是一个概念性的请求结构。具体 namespace、版本和节点是否可用,应以当前 Sabre schema 和账户配置为准:
<CreatePassengerNameRecordRQ
xmlns="http://services.sabre.com/sp/reservation/v2_5"
version="2.5.0">
<AirBook>
<HaltOnStatus Code="HL"/>
<HaltOnStatus Code="HN"/>
<HaltOnStatus Code="LL"/>
<HaltOnStatus Code="NN"/>
<HaltOnStatus Code="NO"/>
<HaltOnStatus Code="UC"/>
<HaltOnStatus Code="UN"/>
<HaltOnStatus Code="US"/>
<OriginDestinationInformation>
<FlightSegment
DepartureDateTime="2026-10-10T10:00:00"
FlightNumber="123"
NumberInParty="1"
ResBookDesigCode="Y"
Status="NN">
<DestinationLocation LocationCode="SIN"/>
<MarketingAirline Code="XX" FlightNumber="123"/>
<OriginLocation LocationCode="SYD"/>
</FlightSegment>
</OriginDestinationInformation>
</AirBook>
<AirPrice>
<PriceRequestInformation Retain="true">
<OptionalQualifiers>
<PricingQualifiers>
<PassengerType Code="ADT" Quantity="1"/>
</PricingQualifiers>
</OptionalQualifiers>
</PriceRequestInformation>
</AirPrice>
<TravelItineraryAddInfo>
<!-- Passenger names, phone, email and agency information -->
</TravelItineraryAddInfo>
<SpecialReqDetails>
<!-- SSR, OSI and ticketing arrangement as required -->
</SpecialReqDetails>
<PostProcessing>
<EndTransaction>
<Source ReceivedFrom="WEB"/>
</EndTransaction>
<RedisplayReservation/>
</PostProcessing>
</CreatePassengerNameRecordRQ>
需要检查的重点不是示例中的版本号或节点顺序,而是以下结果:
- 所有航段均处于可接受的 confirmed status。
- 已生成 PNR locator。
AirPrice执行成功。- 价格已正确保存到 PNR,而不是只返回了一条临时报价。
- 乘客人数和 PTC 与购物阶段完全一致。
- 响应中没有需要人工处理的 warning。
- 已获取并保存 ticketing time limit。
- End Transaction 确实成功。
仅检查 SOAP 请求成功或 HTTP 200 并不够。Sabre 响应可能同时包含 PNR locator、warning,以及某个编排步骤的业务错误。
如何比较最终价格
建议在服务器端记录并比较以下字段:
shopping_total
revalidated_total
pnr_priced_total
payment_authorized_total
payment_captured_total
currency
比较金额时必须同时核对货币。不要假设所有货币都有两位小数。对于零位或三位小数的货币,应按对应货币规则转换为最小货币单位后再比较,以免产生浮点数误差。
示例逻辑:
if (pnr.currency !== payment.currency) {
await voidAuthorization(payment.authorizationId);
await cancelPnr(pnr.locator);
throw new Error("Currency mismatch");
}
if (pnr.totalMinorUnits !== payment.authorizedMinorUnits) {
await voidAuthorization(payment.authorizationId);
await cancelPnr(pnr.locator);
return {
status: "PRICE_CHANGED",
latestAmount: pnr.total,
currency: pnr.currency
};
}
await capturePayment(payment.authorizationId);
await placePnrOnTicketingQueue(pnr.locator);
生产环境还需要处理以下情况:
- capture 成功,但 queue placement 失败。
- queue placement 成功,但机器人出票失败。
- capture 结果超时,暂时无法确认是否已扣款。
- 重试造成重复扣款或重复 queue placement。
- PNR 已创建成功,但调用方因网络超时未收到 locator。
支付、建立 PNR 和 queue 操作都应使用幂等标识。发生超时后,应先通过查询确认实际状态,不能直接重复执行。
外部支付与 PNR 中的付款方式
“客户通过外部网关付款”和“PNR 中指定 cash”是两个不同的概念。
PNR 或出票记录中的 form of payment,表示出票方如何记录或结算机票款。即使网站已经通过第三方网关收取银行卡款,也不代表出票机器人可以自动按 cash 出票。能否使用 cash,取决于客户、出票代理和机器人服务商之间的清算安排。
实施前,应要求机器人服务商书面确认以下事项:
- PNR 中需要使用哪种 form of payment。
- 是否接受
cash。 - 是否需要信用卡 FOP、invoice、agency account 或其他标识。
- 是否要在 PNR 中加入特定 remark、OSI 或 accounting 信息。
- 外部支付成功后的 transaction ID 是否需要写入 remark。
- 退款、void 和 exchange 分别由哪一方负责。
- 是否允许把完整支付信息写入 PNR。
不要把网关银行卡号或敏感认证数据直接写入普通 PNR remark。支付数据的保存和传递必须符合 PCI DSS 及网关的 tokenization 要求。
出票机器人如何接入
典型做法是先完整创建 PNR 并结束交易,再通过 queue 服务将 PNR 放入出票方指定的 PCC 和 queue。
Create PNR
↓
End Transaction
↓
Redisplay and verify PNR
↓
Capture payment
↓
QueuePlaceRQ / agreed queue operation
↓
Robot retrieves PNR
↓
Issue ticket
↓
Return ticket number or failure status
queue 操作最好与建立 PNR 分开。这样,只有满足以下条件的 PNR 才会进入出票队列:
- PNR 已成功创建并结束交易。
- 价格已经保存,且与付款金额一致。
- 支付已达到双方约定的状态。
- 必需的 passenger、SSR、contact、ticketing 和 remark 信息已经齐全。
概念性的 queue placement 请求可能如下:
<QueuePlaceRQ
xmlns="http://webservices.sabre.com/sabreXML/2011/10"
Version="2.0.4">
<QueueInfo>
<QueueIdentifier
Number="50"
PseudoCityCode="ROBOT_PCC"/>
</QueueInfo>
</QueuePlaceRQ>
这个示例只说明操作意图。实际请求结构、是否需要 category、能否跨 PCC 放入队列,以及应该使用 queue place 还是 queue transfer,都必须结合已开通的 Sabre 服务和双方的 branch/access 配置确认。
还要确认“International/Domestic Agent Q50”的实际含义。它可能指:
- 两个不同的 queue 或 category。
- 同一个
Q50,通过 PNR remark 区分国内和国际。 - 机器人服务商内部对
Q50的业务名称。
不能仅凭这段描述自行推导 queue/category 参数。
7TAW 是否仍然需要
7TAW 通常用于建立 ticketing arrangement,表示 PNR 正在等待出票,而不是已经出票。它不是“启动出票机器人”的开关,也不会自动把 PNR 送入机器人队列。
是否使用 7TAW,需要由机器人服务商确认。至少应明确以下事项:
- 要求使用
7TAW、7T-A还是其他 ticketing field。 - 是否必须包含日期、时间或 PCC。
- 时限采用航空公司的 ticketing deadline,还是机器人约定的处理期限。
- queue placement 后,机器人是否会自行更新 ticketing field。
- 出票成功后是否写回 ticket number。
- 出票失败后,是保留 PNR、移出 queue,还是放入 error queue。
如果服务商要求使用 7TAW,日期不能随意填写。它必须早于航空公司返回的最后出票期限,同时给机器人预留足够的处理时间。设置一个过于宽松的未来日期,可能造成航空公司取消航段或运价失效。
必须向出票机器人服务商确认的接口契约
开发 queue 功能前,建议先取得一份明确的接入说明,至少包括:
- 目标 PCC、queue number 和 category。
- 使用
QueuePlaceRQ,还是严格意义上的 queue transfer。 - 跨 PCC queue 所需的 branch/access 权限。
- 国内和国际 PNR 的区分方式。
- 接受的 form of payment。
- ticketing field 的准确格式。
- 必填的 remark、OSI、SSR 和 contact 信息。
- 婴儿、儿童、多乘客及多票价 PNR 的处理方式。
- 机器人取单频率和最长出票时间。
- 出票成功后的回传方式。
- 出票失败、价格变化和航段取消时的处理方式。
- void、refund、exchange 和 schedule change 的责任边界。
实施时的注意事项
- 不要根据
BargainFinderMaxRQ返回的金额直接进行不可逆扣款。 - 搜索结果中应明确提示,价格和座位仍需再次确认。
- 尽量缩短验价、支付授权和建立 PNR 之间的间隔。
- 只有成功保存到 PNR 的价格,才能用于最终核对支付金额。
- PNR 创建成功但支付失败时,应及时取消 PNR。
- 支付成功但建立 PNR 或出票失败时,应自动执行 void 或 refund,并保留可审计记录。
- queue placement 不代表出票成功,系统必须继续跟踪 ticket number。
cash和7TAW都应由出票代理确认,不能仅为技术实现方便而自行决定。- token 可以简化认证,但不能消除跨系统事务、状态核对和失败补偿。
- 上线前应分别测试价格变化、库存消失、重复请求、SOAP 超时、queue 权限不足、机器人拒单和支付退款等场景。
备注:内容仅供参考。
