跳转到内容

能力 · API

Payment Request API

发布于

有限可用不支持的浏览器: Firefox (Desktop)W3C

PaymentRequest 把结账面板交给浏览器:页面列出接受的支付方式、商品明细与总额、需要的联系人字段,浏览器从已存的卡片、Apple Pay、Google Pay 或已安装的支付处理程序收集凭据,以 PaymentResponse 返回。页面不渲染卡片表单,除非所选方式主动返回,页面也接触不到原始卡号。

桌面 Chrome 60 与 Android 上的 Chrome 53 发布了该构造函数,Edge 15 与 Safari 11.1 跟进,Android WebView 在 136 加入(BCD api.PaymentRequest)。Safari 只实现一种支付方式:https://apple.com/apple-pay。Firefox 55 的实现藏在 dom.payments.request.enabled 与 dom.payments.request.supportedRegions 之后,没有任何版本默认开启。

new PaymentRequest(methodData, details)
new PaymentRequest(methodData, details, options)
request.canMakePayment()
request.show()
request.show(detailsPromise)
request.abort()
response.complete()
response.complete(result)
response.retry(errorFields)

canMakePayment() 返回 Promise<boolean>,不显示任何 UI。show() 返回 Promise<PaymentResponse>,用户授权付款后兑现;abort() 与 complete() 返回 Promise<undefined>,retry() 返回的 Promise 在用户改正被标记的字段后兑现。构造函数带 [SecureContext],并要求 payment Permissions Policy,其默认允许列表为 'self';跨源 iframe 需要 allow="payment"。请求对象一次性使用:show() 调用过一次后 [[state]] 离开 "created",再次 show() 或之后的 canMakePayment() 都会被拒绝。

构造函数接受两个必填字典和一个可选字典。

参数 类型 必填 说明
methodData sequence<PaymentMethodData> 是 每种接受的支付方式一项。supportedMethods 是支付方式标识符,要么是 https://google.com/pay、https://apple.com/apple-pay 这样的 URL,要么是 secure-payment-confirmation 这样的标准化字符串;data 是该方式自己的规范定义的对象(商户 id、允许的卡组织)。列表不能为空,也不能重复同一标识符。
details PaymentDetailsInit 是 total(PaymentItem:label、amount)必填;amount 是 PaymentCurrencyAmount,含 ISO 4217 currency 代码和 "29.99" 这样的十进制字符串 value。可选成员:id(省略时生成 UUID)、displayItems、shippingOptions(id、label、amount、selected),以及按支付方式改动总额的 modifiers(supportedMethods、total、additionalDisplayItems、data)。
options PaymentOptions 否 requestPayerName、requestPayerEmail、requestPayerPhone、requestShipping(布尔,默认 false)与 shippingType("shipping"、"delivery" 或 "pickup",默认 "shipping",只影响面板上的文案)。

show(detailsPromise) 接受可选的 Promise<PaymentDetailsUpdate>,让面板在服务端算完购物车之前就能打开。complete(result) 接受 "success"、"fail" 或 "unknown"(默认值)。retry(errorFields) 接受 PaymentValidationErrors 字典,含 error、payer(name、email、phone)、shippingAddress(按地址字段键入的 AddressErrors)与 paymentMethod。

规范定义了下列失败情形。Chrome 附带固定消息的地方引自 components/payments/core/error_strings.cc。

异常 条件
SecurityError 构造函数:文档不被允许使用 payment Permissions Policy。show():浏览器要求瞬时激活却没有,或对调用限速。
TypeError 构造函数:methodData 为空;缺少 details.total;某个 amount.value 不是合法的十进制金额字符串,或总额为负;两个配送选项共用一个 id。Chrome 另加限制:最多 1024 个配送选项、1024 个 modifier,details.id 最长 1024 字符。
RangeError 构造函数:支付方式标识符既不是合法 URL 也不是标准化字符串、同一标识符出现两次,或 currency 不是格式正确的 ISO 4217 代码。
InvalidStateError show():文档不是 fully active,或 [[state]] 不是 "created"(Chrome:Already called show() once)。abort():没有进行中的 show() 或 retry()、已有 abort() 挂起,或浏览器无法中止当前交互。canMakePayment():[[state]] 不是 "created" 或文档不是 fully active。complete() 与 retry():响应已完成,或有 retry() 挂起。
AbortError show():文档不可见、已有另一张支付面板在显示(Chrome:Another PaymentRequest UI is already showing in a different tab or window.)、用户关闭面板(Chrome:User closed the Payment Request UI.),或页面调用了 abort()(Chrome:The website has aborted the payment)。complete():面板打开期间文档不再 fully active。
NotSupportedError show():列出的方式没有一个受支持。Chrome 还会在既非 localhost、file:// 也非加密协议的源上拒绝,消息为 Only localhost, file://, and cryptographic scheme origins allowed.。
NotAllowedError canMakePayment():浏览器对反复变换支付方式列表的查询施加反指纹配额。
OperationError show():所选支付处理程序报告内部错误,例如被操作系统终止。

canMakePayment() 兑现为 false 不是异常:它表示设备上没有任何列出的方式可用,这就是改显示托管结账页的信号。

示例以 Google Pay 作为支付方式标识符;换成你的支付服务商的标识符与 data 对象即可。每个示例都先检测构造函数,缺失或没有可用方式时回退到托管结账页。

仅在 canMakePayment() 兑现为 true 时显示钱包按钮

Section titled “仅在 canMakePayment() 兑现为 true 时显示钱包按钮”

页面加载时构造请求,询问是否有任何列出的方式可用,只在 true 时展示原生按钮。结果为 false 或构造函数缺失时,保留普通的「继续结账」链接,它跳转到支付服务商的托管页面。

const methodData = [{
supportedMethods: "https://google.com/pay",
data: { environment: "PRODUCTION", apiVersion: 2, apiVersionMinor: 0 /* 商户配置 */ },
}];
const details = {
total: { label: "合计", amount: { currency: "CNY", value: "199.00" } },
};
async function prepareCheckout() {
const hosted = document.querySelector("#hosted-checkout");
const wallet = document.querySelector("#wallet-button");
if (!("PaymentRequest" in window)) {
hosted.hidden = false;
return;
}
const request = new PaymentRequest(methodData, details);
let available = false;
try {
available = await request.canMakePayment();
} catch (err) {
console.warn(`${err.name}: ${err.message}`); // 超出浏览器查询配额时被拒绝
}
wallet.hidden = !available;
hosted.hidden = available;
}
prepareCheckout();

保留用来测试的 request 对象:canMakePayment() 不会消耗它,下一个示例的点击处理函数可以在同一实例上调用 show()。

服务端扣款后用 complete() 关闭面板

Section titled “服务端扣款后用 complete() 关闭面板”

show() 必须在点击处理函数内运行,瞬时激活才在。把 response.toJSON() 发给服务端,服务端一回应就调用 complete("success") 或 complete("fail");在此之前面板一直开着,Chrome 超时后会自行关闭,效果等同于无参调用 complete()。

const wallet = document.querySelector("#wallet-button");
wallet.addEventListener("click", async () => {
const request = new PaymentRequest(methodData, details);
let response;
try {
response = await request.show();
} catch (err) {
if (err.name === "AbortError") return; // 用户关闭了面板
location.assign("/checkout/hosted"); // 其他任何拒绝:回退到托管结账页
return;
}
const result = await fetch("/api/charge", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(response.toJSON()),
});
await response.complete(result.ok ? "success" : "fail");
if (result.ok) location.assign("/checkout/thanks");
});

complete("fail") 显示浏览器的失败状态并关闭面板;接下来该告诉用户怎么办,是页面的责任。

设置 requestShipping: true 后,面板让用户选地址,并在请求对象上触发 shippingaddresschange。在监听器内同步调用 event.updateWith(),传入新明细的 Promise;完结之前面板显示加载状态。规范允许浏览器在用户授权前对地址做脱敏,所以用 country、region 与 postalCode 计算运费,不要依赖街道行。

const request = new PaymentRequest(methodData, {
total: { label: "合计", amount: { currency: "CNY", value: "199.00" } },
shippingOptions: [
{ id: "ground", label: "普通快递(5 天)", amount: { currency: "CNY", value: "0.00" }, selected: true },
],
}, { requestShipping: true });
request.addEventListener("shippingaddresschange", (event) => {
const { country, postalCode } = event.target.shippingAddress;
event.updateWith(
fetch(`/api/shipping?country=${country}&postal=${postalCode}`)
.then((r) => r.json())
.then((quote) => ({
total: { label: "合计", amount: { currency: "CNY", value: quote.total } },
shippingOptions: quote.options,
}))
);
});

报价返回 shippingOptions: [] 表示该地址无法配送;在更新里加上 error: "该地区暂不支持配送",用户就能看到原因。

规范

规范状态
Payment Request API(支付请求)W3C
Payment Request API: constructorW3C
Payment Request API: show() methodW3C
Payment Request API: canMakePayment() methodW3C
  • 图例
  • 支持
  • 部分支持
  • 需开启标志
  • 不支持
  • 未知
浏览器 / 平台支持版本置信度来源备注
Chrome (Android)支持61中来源—
Chrome (Desktop)支持61中来源—
Edge (Desktop)支持79中来源—
Safari (iOS)支持11.1中来源1
Safari (macOS)支持11.1中来源2
Firefox (Desktop)不支持—中来源3
Samsung Internet支持7.0中来源—
  1. 以 Apple Pay 作为支付方式。
  2. 由 Apple Pay 支撑。
  3. 实现曾发布后又被禁用;默认不可用。

生态与商业政策

主体类型场景状态赞助备注
Apple Paypayment_sdkSafari / iOS支持否在 Safari 中通过 Payment Request 可用;需要完成商户域名验证。
Stripepayment_sdkCross-browser支持否Stripe 把 Payment Request 封装为 Payment Request Button / Payment Element。
Google Play billingstore_policyGoogle Play TWA不支持否依据 Play 政策,分发数字商品的 TWA 必须使用 Play Billing,而不是 Payment Request。

源数据: /compatibility/payment-request.json · 全球使用占比: 90 % (StatCounter 2026-05)

来源: 规范 · MDN · 最近核验 2026-06-24 · 置信度: 中 (由来源计算)