--- url: >- https://acquirer-api-docs-v4-en.pingpongx.com/notes/zh/integrate/non-hosted-apm/index.md description: 说明 Non-hosted 本地支付 API 接入流程,帮助商户在自建收银台中接入电子钱包、网银等本地支付方式。 --- PingPong Non-hosted 本地支付是一款专为跨境交易打造的轻量级、高安全后端解决方案。通过标准化的 API 集成,商户可一站式接入全球丰富的本地支付方式(涵盖电子钱包、网银、银行卡等)。我们致力于为您扫除多通道对接的技术壁垒,在保障交易安全合规的前提下,为全球买家提供极致顺滑的支付体验,助力您的出海业务快速落地与规模化扩张。 ## 支付流程 ```mermaid %%{init: { 'theme': 'base', 'themeVariables': { 'primaryColor': '#E3F2FD', 'primaryTextColor': '#0D47A1', 'primaryBorderColor': '#1976D2', 'lineColor': '#1565C0', 'secondaryColor': '#BBDEFB', 'tertiaryColor': '#90CAF9', 'background': '#F8FBFF', 'mainBkg': '#E3F2FD', 'secondBkg': '#BBDEFB', 'tertiaryBkg': '#90CAF9', 'actorBkg': '#2196F3', 'actorBorder': '#1976D2', 'actorTextColor': '#FFFFFF', 'actorLineColor': '#1565C0', 'signalColor': '#0D47A1', 'signalTextColor': '#0D47A1', 'noteBkgColor': '#E1F5FE', 'noteTextColor': '#01579B', 'noteBorderColor': '#0288D1', 'loopTextColor': '#0D47A1', 'activationBkgColor': '#B3E5FC', 'activationBorderColor': '#0277BD' } }}%% sequenceDiagram participant Buyer as 👤 买家 participant Client as 💻 商户前端 participant Server as 🏪 商户服务端 participant PP as 🔄 PingPongCheckout participant APM as 🧾 本地支付通道 Buyer->>Client: 1. 进入下单页并选择本地支付方式 Client->>Server: 2. 提交订单信息、支付方式、设备信息 Server->>PP: 3. 调用下单并支付 PP-->>Server: 4. 返回 code、bizContent.status、action Server-->>Client: 5. 返回支付推进参数 Client->>APM: 6. 根据 action 推进支付 Buyer->>APM: 7. 在支付方式页面完成登录、授权或确认付款 APM-->>Client: 8. 按需跳回 payResultUrl APM-->>PP: 9. 返回支付处理结果 PP-->>Server: 10. 推送支付异步通知 Server-->>PP: 11. 返回 HTTP 2xx 确认接收 Server->>PP: 12. 未收到通知时主动查询交易 Server-->>Client: 13. 返回商户订单状态 ``` 流程说明: 1. 买家在商户下单页面选择本地支付方式,例如钱包、网银或银行转账。 2. 商户前端将订单信息、支付方式、设备信息提交到商户服务端。 3. 商户服务端调用 [下单并支付](/notes/zh/checkout/api/uniformly/) 创建支付订单。 4. PingPongCheckout 返回同步响应;若交易需要买家继续操作,响应中会包含 `action`。 5. 商户前端根据 `action` 推进买家继续完成支付。本文以下以跳转类本地支付场景说明接入步骤。 6. 买家完成支付后,PingPongCheckout 通过 `notificationUrl` 推送支付结果。 7. 如果商户长时间未收到异步通知,应主动调用 [交易查询](/notes/zh/checkout/api/getOne/) 确认最终状态。 ::: warning 注意 买家从本地支付页面跳回 `payResultUrl`,只表示买家回到了商户页面,不代表支付成功。订单落账、发货或发放权益必须以服务端异步通知或交易查询结果为准。 ::: ## 接口列表 Non-hosted 本地支付通常涉及以下接口和通知: | 阶段 | 类型 | 文档 | 是否必接 | 用途 | |:---|:---|:---|:---:|:---| | 支付创建 | API | [下单并支付](/notes/zh/checkout/api/uniformly/) | 必接 | 创建本地支付订单并获取支付推进参数 | | 支付结果 | 通知 | [支付通知](/notes/zh/notify/payment/notify/) | 必接 | 接收最终支付结果并更新商户订单状态 | | 支付结果 | API | [交易查询](/notes/zh/checkout/api/getOne/) | 推荐 | 在通知延迟、未达或需要补偿确认时主动核验交易状态 | | 退款 | API | [申请退款](/notes/zh/checkout/api/modifications/refund/) | 按需 | 对成功支付的本地支付交易发起退款 | | 退款 | 通知 | [退款通知](/notes/zh/notify/refundNotify/) | 推荐 | 接收退款结果并更新退款状态 | | 退款 | API | [退款查询](/notes/zh/checkout/api/getRefund/) | 推荐 | 在通知延迟、未达或对账时主动确认退款状态 | ## 集成准备 开始开发前,请确认以下信息已经准备完成。 | 准备项 | 说明 | |:---|:---| | 账号信息 | 已获取 `clientId`、`accId`,并确认店铺状态可正常交易 | | 支付方式 | 已开通本次需要接入的本地支付方式,并确认支持的国家、币种、金额范围和退款能力 | | 签名能力 | 已根据 [签名规约](/notes/zh/onlinePayment/developer/sign/) 完成请求签名,所有请求参数都需要参与签名 | | 验签能力 | 已能对 PingPongCheckout 返回响应和异步通知中的 `sign` 执行验签 | | 通知地址 | 已准备公网可访问的 `notificationUrl`,用于接收支付结果异步通知 | | 结果页地址 | 已准备 `payResultUrl`,用于跳转类支付方式完成后回到商户页面 | | 订单状态处理 | 已在商户系统内保存 `merchantTransactionId`、`requestId`、`transactionId` 和订单状态,并支持幂等更新 | ::: tip 提示 不同本地支付方式可能要求额外字段,例如 `customer`、`goods`、`billingAddress`、`shippingAddress` 或特定 `device.orderTerminal`。请以目标支付方式页面和 [下单并支付](/notes/zh/checkout/api/uniformly/) 参数表为准。 ::: ::: warning 注意 `notificationUrl` 必须是公网可访问的完整地址,不能填写 `localhost`、`127.0.0.1`、内网 IP,也不要在 URL 后携带 query 参数。 ::: ## 集成步骤 请按以下步骤完成集成: 1. [步骤 1:展示可用支付方式](#步骤-1-展示可用支付方式) 2. [步骤 2:创建支付订单](#步骤-2-创建支付订单) 3. [步骤 3:根据 action 推进支付](#步骤-3-根据-action-推进支付) 4. [步骤 4:获取最终支付结果](#步骤-4-获取最终支付结果) ### 步骤 1:展示可用支付方式 在买家下单页面展示本次需要集成的支付方式标识和名称,供买家根据自身需求和偏好选择。支付方式列表页面需要由您的前端自行实现。 展示支付方式时,建议至少基于以下条件过滤: | 条件 | 处理建议 | |:---|:---| | 交易国家 | 使用订单国家或买家结账国家匹配 `tradeCountry` | | 交易币种 | 使用支付方式支持的 `currency`,金额精度参考 [交易币种](/notes/zh/appendix/transactionCurrency/) | | 支付终端 | 根据 Web、WAP、App 等场景准备 `device.orderTerminal` | | 支付方式类型 | 将买家选择的支付方式写入 `paymentMethod.type` | ### 步骤 2:创建支付订单 调用 [下单并支付](/notes/zh/checkout/api/uniformly/) 创建支付订单。您需要收集买家的支付方式、订单信息、设备信息、支付金额等,并由商户服务端提交支付请求。 支付请求关键参数: | 参数 | 必填 | 说明 | |:---|:---:|:---| | `captureDelayHours` | M | 本地支付固定使用 `0`,表示立即 capture | | `amount` | M | 交易金额 | | `currency` | M | ISO 4217 三位交易币种 | | `merchantTransactionId` | M | 商户网站订单流水号,订单唯一标识 | | `requestId` | M | 支付请求流水号,全局唯一 | | `tradeCountry` | M | 交易国家,使用 ISO 3166-1 alpha-2 国家码 | | `shopperIP` | M | 买家下单 IP | | `paymentMethod.type` | M | 买家选择的本地支付方式 | | `goods` | M | 商品信息,至少包含 `goods[].name`、`goods[].unitPrice`、`goods[].number`、`goods[].imgUrl` | | `device.orderTerminal` | M | 下单终端。`01` 移动端浏览器(WAP)、`02` PC 端浏览器(WEB)、`04` iOS App、`05` Android App | | `notificationUrl` | O | 支付结果通知地址,建议传入 | | `payResultUrl` | C | 跳转类支付完成后的商户结果页地址 | | `merchantUserId` | M | 商户侧用户唯一 ID | | `customer.email` | C | 用户邮箱。实物类商户必传;部分支付方式也可能要求传入,请以具体支付方式要求为准 | | `customer.phone` | C | 用户手机号。部分本地支付方式会要求传入,请以具体支付方式要求为准 | 有关完整参数的更多信息,请参阅 [下单并支付](/notes/zh/checkout/api/uniformly/)。 支付请求示例(仅展示 `bizContent` 内容): ```json { "captureDelayHours": 0, "amount": "1000", "currency": "THB", "merchantTransactionId": "ORDER_202606100001", "requestId": "REQ_202606100001", "tradeCountry": "TH", "shopperIP": "203.0.113.10", "merchantUserId": "USER_12345", "notificationUrl": "https://www.example.com/checkout/notify", "payResultUrl": "https://www.example.com/checkout/result", "paymentMethod": { "type": "TrueMoney Wallet" }, "customer": { "email": "buyer@example.com", "phone": "66123456789" }, "goods": [ { "name": "Digital product", "description": "Order item", "sku": "SKU_001", "imgUrl": "https://www.example.com/product/SKU_001.png", "unitPrice": "1000", "number": "1", "virtualProduct": "Y" } ], "device": { "orderTerminal": "02" } } ``` ::: tip 提示 为便于阅读,本文示例将 `bizContent` 展开为 JSON 对象。实际请求时,请按照 [下单并支付](/notes/zh/checkout/api/uniformly/) 和 [签名规约](/notes/zh/onlinePayment/developer/sign/) 的要求处理 `bizContent` 和签名。 ::: 响应关键字段: | 参数 | 说明 | |:---|:---| | `transactionId` | PingPong 交易流水号 | | `merchantTransactionId` | 商户网站订单流水号 | | `requestId` | 支付请求流水号 | | `status` | 交易状态 | | `action` | 支付推进参数,买家需要继续操作时返回 | 响应示例(仅展示 `bizContent` 内容): ```json { "transactionId": "2026061050010001", "merchantTransactionId": "ORDER_202606100001", "requestId": "REQ_202606100001", "amount": "1000.000000", "currency": "THB", "status": "PROCESSING", "paymentMethod": { "type": "TrueMoney Wallet" }, "action": { "type": "PAYMENT_REDIRECT_URL", "paymentRedirectUrl": "https://sandbox-acquirer-static.pingpongx.com/payment/apm.html?token=example" }, "payResultUrl": "https://www.example.com/checkout/result", "transactionTime": "1781080205000", "captureDelayHours": 0 } ``` 下单响应中的 `status` 可能返回以下值,请根据指引进行处理: | `status` | 说明 | 处理指引 | |:---|:---|:---| | `SUCCESS` | 同步响应已成功 | 商户服务端可以更新订单状态,但仍建议接收异步通知或查询结果做最终一致性校验 | | `FAILED` | 支付失败 | 提示买家更换支付方式或重新发起支付 | | `PROCESSING` | 支付处理中 | 若响应包含 `action`,继续执行步骤 3;同时等待异步通知或主动查询 | ### 步骤 3:根据 action 推进支付 当下单响应的 `status` 为 `PROCESSING` 且返回 `action` 时,前端需要根据 `action` 推进支付流程。本文以下以 `action.type=PAYMENT_REDIRECT_URL` 的跳转类支付方式为例说明。 | `action.type` | 关键字段 | 前端处理 | |:---|:---|:---| | `PAYMENT_REDIRECT_URL` | `action.paymentRedirectUrl` | 将用户重定向到该地址,让用户在对应支付方式页面完成支付 | ::: warning 支付推进注意事项 - `action.paymentRedirectUrl` 是 PingPongCheckout 返回的完整支付推进链接。商户前端应直接使用服务端返回的原始值,不要自行拼接额外参数,也不要替换域名或路径。 - 建议在顶层页面、系统浏览器或系统级网页容器中打开支付推进链接;如果必须在 `WKWebView` 或 `WebView` 中承载,请提前完成真机验证。 ::: 商户服务端拿到 PingPong 返回的支付推进链接后,将该地址传递给前端,由商户前端跳转至支付方式页面。 以下为商户前端加载支付推进链接的示例代码:
::: tabs @tab Web ```js function redirectOnWeb(action) { if (action?.type !== 'PAYMENT_REDIRECT_URL') return; const paymentWindow = window.open(action.paymentRedirectUrl, '_blank'); if (!paymentWindow) { window.location.assign(action.paymentRedirectUrl); } } ``` @tab WAP ```js function redirectOnWap(action) { if (action?.type !== 'PAYMENT_REDIRECT_URL') return; window.location.href = action.paymentRedirectUrl; } ``` @tab App (iOS) ```objc // Objective-C 示例: NSURL *url = [NSURL URLWithString:paymentRedirectUrl]; if (url) { [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) { if (!success) { // 引导买家重试或更换支付方式 } }]; } // Swift 示例: guard let url = URL(string: paymentRedirectUrl) else { return } UIApplication.shared.open(url, options: [:]) { success in if !success { // 引导买家重试或更换支付方式 } } ``` @tab App (Android) ```java // Java 示例: try { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(paymentRedirectUrl)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } // Kotlin 示例: try { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(paymentRedirectUrl)) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) } catch (e: Exception) { e.printStackTrace() } ``` :::
### 步骤 4:获取最终支付结果 本地支付的最终结果,建议优先通过服务端异步通知确认。若异步通知延迟、未达、通知处理失败,或商户在买家回跳后需要立即核验结果,可再主动调用交易查询。交易查询的完整集成方案请参考 [支付后 > 查询交易](#查询交易)。 如果通过异步通知获取结果,商户服务端应优先返回 HTTP `2xx` 确认已接收,再根据通知中的 `status` 更新订单状态。 支付通知示例: ```json { "accId": "2023042011040310224447", "clientId": "2023042011040310224", "code": "000000", "description": "Transaction succeeded", "sign": "{{Sign}}", "signType": "SHA256", "bizContent": { "amount": "1000.000000", "currency": "THB", "transactionId": "2026061050010001", "merchantTransactionId": "ORDER_202606100001", "requestId": "REQ_202606100001", "notifyType": "RECHARGE", "paymentMethod": { "type": "TrueMoney Wallet" }, "status": "SUCCESS", "transactionTime": "1781080205000", "transactionEndingTime": "1781080265000", "captureDelayHours": 0 } } ``` 通知关键字段: | 参数 | 说明 | 处理建议 | |:---|:---|:---| | `sign` / `signType` | 通知签名和签名类型 | 必须验签,验签通过后再处理业务 | | `notifyType` | 通知类型,支付通知固定为 `RECHARGE` | 用于区分通知事件类型 | | `transactionId` | PingPong 交易流水号 | 保存并用于后续查询、对账 | | `merchantTransactionId` | 商户网站订单流水号 | 用于定位商户订单 | | `requestId` | 支付请求流水号 | 用于定位本次支付请求 | | `amount` / `currency` | 交易金额和币种 | 必须与商户订单金额、币种核对 | | `status` | 支付结果状态 | 按状态更新商户订单 | 通知中的 `status` 建议按以下方式处理: | `status` | 处理指引 | |:---|:---| | `SUCCESS` | 支付成功,可以进行发货、权益发放或订单完成处理 | | `FAILED` | 支付失败,订单保持未支付或失败状态,可允许买家重新支付 | | `CANCEL` | 支付取消或风控审核拒绝,订单不可按成功处理 | | `CLOSED` | 订单已关闭,买家不能继续使用该订单支付 | 收到通知后,您无需对响应内容进行加签处理。但无论订单支付是否成功,均必须严格按照以下固定格式返回响应。 通知响应示例: ```http HTTP/1.1 200 OK Content-Type: text/plain; charset=UTF-8 Content-Length: 2 OK ``` ## 支付后操作 以下内容介绍在支付流程推进后,如何通过服务端主动查询交易状态、处理退款及对账,帮助您实现稳定可靠的支付管理。 ### 查询交易 当买家从支付页面跳回商户结果页、异步通知延迟、通知处理失败,或商户需要执行补偿任务时,可以调用 [交易查询](/notes/zh/checkout/api/getOne/) 获取交易最新状态。 交易查询请求示例(仅展示 `bizContent` 内容): ```json { "merchantTransactionId": "ORDER_202606100001", "requestId": "REQ_202606100001" } ``` 交易查询响应示例(仅展示 `bizContent` 内容): ```json { "transactionId": "2026061050010001", "merchantTransactionId": "ORDER_202606100001", "requestId": "REQ_202606100001", "amount": "1000.000000", "currency": "THB", "status": "SUCCESS", "paymentMethod": { "type": "TrueMoney Wallet" }, "transactionTime": "1781080205000", "transactionEndingTime": "1781080265000" } ``` 查询响应关键字段: | 参数 | 处理方式 | |:---|:---| | `status` | 商户订单状态应以该字段为准 | | `transactionId` | 保存为 PingPong 交易流水号,用于后续退款、对账或查询 | | `amount` / `currency` | 与商户订单金额和币种核对 | | `transactionEndingTime` | 交易到达终态时间,可用于订单完成时间记录 | 交易查询状态处理建议: | `status` | 处理指引 | |:---|:---| | `SUCCESS` | 支付成功,可以完成订单 | | `FAILED` | 支付失败,可允许买家重新支付 | | `PROCESSING` | 支付处理中,继续等待异步通知或稍后查询 | | `CANCEL` | 支付取消或风控审核拒绝,不可按成功处理 | | `CLOSED` | 订单已关闭,买家不能继续使用该订单支付 | ### 退款 不同支付方式的退款能力不同,主要包括是否支持退款、退款有效期、是否支持部分退款以及是否支持多次部分退款。请参考 [支付方式](/notes/zh/paymentMethods/overview/) 页面或目标支付方式文档,确认具体退款能力。 支付成功后,如买家申请退款、商户取消已支付订单或需要退回部分或全部款项,您可以调用 [申请退款](/notes/zh/checkout/api/modifications/refund/) 对原交易发起退款。 PingPongCheckout 支持的退款能力如下: - 支持全额退款,即一次性退回原交易可退金额。 - 支持部分退款,即单次退款金额可小于原交易金额。 - 支持多次部分退款,即同一笔交易可发起多笔退款;累计退款金额需小于等于原交易可退金额。 请参考 [Refund](/notes/zh/integrate/modify/Refund/) 了解退款集成方案。具体发起退款的请求参数、响应字段和处理规则,请参考 [申请退款](/notes/zh/checkout/api/modifications/refund/);若需要确认退款处理结果,请参考 [退款查询](/notes/zh/checkout/api/getRefund/)。 ### 对账 如需了解账单生成规则与结算周期,可参考 [结算周期和对账单](/notes/zh/reconciliation/settlementCycle/);如需开通账单下载能力,可参阅 [SFTP服务申请](/notes/zh/reconciliation/transactionStatementDownload/)。