定点医药机构如何在自建商城通过支付宝扣减医保个账?
明确结论
定点医药机构不能只凭支付宝商户号,在自建商城中直接扣减用户的医保个人账户。普通支付宝支付接口处理的是现金、余额、银行卡等资金。医保个账支付受医保基金监管,机构必须接入所在地医保部门认可的线上医保支付渠道,并完成定点资质、互联网诊疗或线上售药资质核验,以及系统改造、接口联调和验收。
在这套流程中,支付宝通常提供实名授权、医保电子凭证展码或授权、支付收银台等能力。用户能否使用医保个账、可支付多少、最终如何结算,仍由当地医保信息平台决定。淘宝或支付宝中的医保购药功能也不是通用接口,不能直接搬到自建商城使用。
接入方案会受到省市政策、机构类型和药品目录的影响。第一步应联系所在地医保局或医保经办机构,确认当地是否开放”互联网定点医药机构医保支付”,然后再向支付宝医疗健康或相关服务商申请对应能力。
为什么普通支付宝接口无法实现
医保个账不同于普通电子钱包,一笔交易通常要同时完成以下工作:
- 核验用户身份和医保参保状态。
- 校验药店、医院及互联网服务渠道的定点资格。
- 判断药品是否属于当地允许线上医保支付的范围。
- 区分医保支付、自费支付和配送费。
- 按医保规则完成预结算、正式结算、撤销及退费。
- 留存处方、药品、购药人、订单和配送等信息,接受监管。
- 分别核对医保结算结果和支付宝现金支付结果。
因此,alipay.trade.app.pay、alipay.trade.page.pay、alipay.trade.wap.pay 等普通支付产品不能代替医保结算接口。即使把支付方式名称改成”医保支付”,也不会真正扣减医保个账。
接入前需要确认的条件
进入技术开发前,应向当地医保经办机构逐项确认:
- 所在地区是否支持定点零售药店或医疗机构开展线上医保结算。
- 自建商城能否备案为线上服务渠道。
- 现有定点资格是否覆盖互联网复诊、处方流转或线上售药。
- 哪些药品、医疗服务和参保人类型可以使用医保个账。
- 是否需要接入全国统一医保信息平台相关接口、省级医保平台或指定服务商。
- 是否支持家庭共济、门诊统筹和异地参保人。
- 处方药是否必须经过互联网医院开方、审方和处方流转。
- 配送费、包装费等非医疗费用应如何收取。
- 结算、退费、对账和监管数据报送采用哪些规范。
如果当地尚未开放互联网医保支付,仅接入支付宝也无法突破这一限制。商城只能提供普通自费支付,或者引导用户到店完成医保结算。
推荐的接入流程
1. 完成机构和线上渠道备案
需要准备定点医药机构协议、营业执照、药品经营许可证或医疗机构执业许可证、互联网服务相关资质、支付宝企业账号和系统安全材料。
医保部门还可能要求提供药师审方、电子处方、配送管理、日志审计、隐私保护及应急处置方案。具体材料以当地要求为准。
2. 申请医保线上支付能力
向所在地医保经办机构申请线上医保结算,取得允许使用的接入渠道、接口规范和测试环境。
还要通过支付宝开放平台、支付宝医疗健康业务渠道或医保部门指定的服务商申请相应产品。申请时应说明以下信息:
- 机构类型是医院还是零售药店。
- 自建商城采用 H5、小程序、App 还是生活号。
- 只需要医保个账支付,还是也需要门诊统筹。
- 支付场景是线上购药、复诊缴费还是处方购药。
- 机构所在省市及定点编码。
普通支付宝当面付、手机网站支付或 App 支付只能收取自费部分,不能单独完成医保个账结算,因此不能只申请这些产品。
3. 完成基础数据映射
商城商品数据需要与医保侧的基础数据建立映射,常见内容包括:
- 定点医药机构编码。
- 药品或诊疗项目医保编码。
- 商品规格、剂型、生产企业和批准文号。
- 药店内部商品编码。
- 处方编号和处方明细。
- 医保支付金额、自费金额及非医疗费用。
- 订单号、医保结算单号和支付宝交易号。
商品名称相同,并不代表医保编码相同。规格、厂家或剂型不一致,都可能导致预结算失败。
4. 建立实名授权和参保身份核验流程
用户选择”医保支付”后,前端通常会跳转到支付宝,完成实名授权、医保电子凭证授权或身份核验。商城服务端取得业务所需的授权结果后,再通过医保结算渠道校验参保资格和待遇。
各地区、各接入模式使用的授权产品名称、请求参数和回调格式可能不同,必须以审批通过后提供的接口文档为准。身份证号、医保凭证以及可以直接调用医保接口的密钥,不应保存在前端。
5. 先做医保预结算
正式扣款前,应把订单和处方明细提交给医保结算渠道进行预结算。预结算结果通常包括:
- 当前订单能否使用医保支付。
- 医保个账可支付金额。
- 统筹基金支付金额。
- 用户现金自费金额。
- 不可报销商品及失败原因。
商城收银台应展示医保试算结果,不能自行按照药品价格计算医保金额。
6. 确认支付并完成正式结算
用户确认后,系统按照当地接入方案唤起支付宝医保支付流程。前端返回支付成功并不能作为最终依据,服务端还要结合异步通知和主动查询确认交易状态。
如果订单同时包含医保支付和现金支付,通常需要分别记录各项金额:
订单应付金额 = 医保个账支付 + 统筹基金支付 + 现金自费支付
是否允许混合支付,以及各类资金按什么顺序支付,由当地医保平台和支付宝接入方案决定。商城不能因为医保结算成功,就默认现金部分也已支付成功。
7. 处理发药、退单和退费
只有医保正式结算和现金支付状态都符合业务规则后,订单才能进入发药或配送环节。
退货时不能只调用支付宝普通退款接口。订单涉及医保金额时,通常还要发起医保结算撤销或医保退费,现金部分则通过支付宝原交易退款。部分地区可能限制处方药退货,处理时还要遵守药品监管和医保规定。
8. 做三方对账
系统至少要保存并核对三类账单:
- 商城业务订单。
- 医保结算账单。
- 支付宝现金交易账单。
支付宝交易号不能替代医保结算单号。这两个编号对应不同的资金渠道,结算周期和异常处理方式也可能不同。
系统实现建议
医保支付可以设计成独立的支付编排流程:
创建订单
→ 校验机构和商品医保资格
→ 获取用户医保授权
→ 医保预结算
→ 展示医保与自费金额
→ 用户确认
→ 发起医保正式结算
→ 支付现金自费部分
→ 接收异步通知并主动查询
→ 更新订单并发药
→ 日终三方对账
服务端可以维护以下状态,避免把不同阶段都压缩成一个”已支付”状态:
public enum MedicalOrderStatus {
CREATED,
AUTHORIZED,
PRESETTLED,
MEDICAL_SETTLING,
CASH_PAYING,
PAID,
DISPENSING,
COMPLETED,
REFUNDING,
REFUNDED,
FAILED
}
每张订单还应分别记录各类资金明细:
public record PaymentBreakdown(
BigDecimal totalAmount,
BigDecimal medicalAccountAmount,
BigDecimal fundAmount,
BigDecimal cashAmount,
BigDecimal deliveryFee
) {}
服务端代码示例
以下代码只用于说明系统结构,并非支付宝或医保平台的官方接口。真实项目必须采用审批通过后的属地接入文档,其中规定的接口地址、字段名、签名算法和证书要求都不能直接套用本示例。
public PaymentPreview previewMedicalPayment(
String orderId,
String userAuthorizationCode) {
Order order = orderService.getPayableOrder(orderId);
MedicalPreSettlementRequest request =
new MedicalPreSettlementRequest(
order.getInstitutionCode(),
order.getOrderNo(),
userAuthorizationCode,
order.getPrescriptionNo(),
order.getMedicalItems()
);
MedicalPreSettlementResult result =
medicalInsuranceGateway.preSettle(request);
if (!result.isEligible()) {
throw new BusinessException(result.getReason());
}
orderService.savePreSettlement(
orderId,
result.getPreSettlementNo(),
result.getMedicalAccountAmount(),
result.getFundAmount(),
result.getCashAmount()
);
return PaymentPreview.from(result);
}
正式结算时,必须使用服务端生成的订单金额,并通过幂等键防止重复扣款:
@Transactional
public PaymentResult confirmPayment(
String orderId,
String preSettlementNo,
String idempotencyKey) {
if (paymentService.hasProcessed(idempotencyKey)) {
return paymentService.getPreviousResult(idempotencyKey);
}
Order order = orderService.lockOrder(orderId);
orderService.verifyPreSettlement(order, preSettlementNo);
MedicalSettlementResult medicalResult =
medicalInsuranceGateway.settle(
new MedicalSettlementRequest(
order.getOrderNo(),
preSettlementNo,
idempotencyKey
)
);
CashPaymentResult cashResult = null;
if (medicalResult.getCashAmount().signum() > 0) {
cashResult = alipayGateway.createCashPayment(
order.getOrderNo(),
medicalResult.getCashAmount()
);
}
paymentService.saveResults(
orderId,
idempotencyKey,
medicalResult,
cashResult
);
return PaymentResult.of(medicalResult, cashResult);
}
支付回调必须验签,并以平台查询结果为准更新订单:
@PostMapping("/payment/notify")
public String handleNotify(HttpServletRequest request) {
Map<String, String> parameters = extractParameters(request);
if (!alipaySignatureVerifier.verify(parameters)) {
return "failure";
}
String outTradeNo = parameters.get("out_trade_no");
// 不能仅凭回调中的状态更新订单,应再次查询并核对金额、商户号和订单号。
CashPaymentResult payment = alipayGateway.query(outTradeNo);
paymentService.confirmCashPayment(payment);
return "success";
}
真实项目还要处理医保已经结算但现金支付失败、现金支付成功但通知丢失、重复回调、预结算过期、订单关闭和部分退费等情况。可以使用状态机或补偿任务处理这些状态,不能依赖一次同步请求完成整笔交易。
容易踩坑的地方
把普通支付宝支付当成医保支付
普通支付宝支付只能收取现金自费部分。医保个账必须通过医保结算链路扣减。
在商城端自行计算医保金额
医保可支付金额受参保地政策、药品目录、待遇资格和账户余额等因素影响,必须以医保预结算结果为准。
只根据前端返回发药
用户关闭页面、网络中断或伪造前端参数,都可能造成状态错误。是否发药应以服务端验签、主动查询和医保结算结果为依据。
忽略混合支付的中间状态
如果医保结算成功而现金支付失败,系统需要明确是保留医保结算并等待用户补付,还是撤销医保结算。应在联调阶段与医保平台确认具体处理规则。
将配送费计入医保
配送费、包装费等通常属于自费项目,但各地规定可能不同。这些费用应单独列项,并按属地医保政策处理。
缺少完整审计记录
医保交易需要保存请求流水号、响应码、业务状态、结算单号和操作日志。日志中的身份证号、手机号、医保凭证等敏感信息必须脱敏,也不能记录完整令牌或密钥。
落地时应向对接方索取的资料
开发前应取得以下正式资料:
- 属地互联网医保支付准入办法。
- 医保接口规范及错误码文档。
- 支付宝对应医疗医保产品的接入文档。
- 沙箱或联调环境账号。
- 签名、验签、证书及密钥管理要求。
- 预结算、正式结算、撤销和退费流程。
- 异步通知及主动查询规则。
- 对账文件格式和清算周期。
- 上线验收、备案及安全测评要求。
如果对接方只能提供普通支付宝支付文档,却没有医保预结算、正式结算和医保退费能力,就不能实现真正的医保个账扣费。项目应先取得属地医保经办机构的准入确认,再开始开发支付宝收银台。
备注:内容仅供参考。
