<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>API on 逍遥笔记</title><link>https://blog.7qiang.com/tags/api/</link><description>Recent content in API on 逍遥笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>逍遥笔记</copyright><lastBuildDate>Sun, 16 Aug 2026 22:00:00 +0800</lastBuildDate><atom:link href="https://blog.7qiang.com/tags/api/index.xml" rel="self" type="application/rss+xml"/><item><title>Stripe 协议支付自动化深度拆解：从 HAR 抓包到纯 API 全链路实现</title><link>https://blog.7qiang.com/posts/stripe-protocol-payment-automation-deep-dive-2026/</link><pubDate>Sun, 16 Aug 2026 22:00:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/stripe-protocol-payment-automation-deep-dive-2026/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post Stripe 协议支付自动化深度拆解：从 HAR 抓包到纯 API 全链路实现" /&gt;&lt;section class="xiaoyao-contact-card" aria-label="联系逍遥"&gt;
 &lt;img class="xiaoyao-contact-card__qr" src="https://blog.7qiang.com/contact-qr.png" width="690" height="690" loading="lazy" decoding="async" alt="逍遥微信二维码"&gt;
 &lt;div class="xiaoyao-contact-card__content"&gt;
 &lt;h3 class="xiaoyao-contact-card__title"&gt;联系逍遥&lt;/h3&gt;
 &lt;p class="xiaoyao-contact-card__description"&gt;扫码添加微信，或点击下方按钮复制联系方式。&lt;/p&gt;
 &lt;div class="xiaoyao-contact-buttons" data-contact-buttons&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--wechat" type="button" data-copy-contact="plus6566" data-copy-label="微信号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;微信&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;plus6566&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--qq" type="button" data-copy-contact="826215906" data-copy-label="QQ 号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;QQ&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;826215906&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;span class="xiaoyao-contact-feedback" role="status" aria-live="polite"&gt;&lt;/span&gt;
&lt;/div&gt;

 &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;进微信群请联系博主，各位觉得文章对你有帮助的话可否打赏一些呀~&lt;/p&gt;
&lt;hr&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;⚠️ 免责声明&lt;/strong&gt;：本文仅供安全研究与技术学习。文中描述的技术手段仅用于分析 Stripe 支付协议的工作原理，帮助支付系统开发者理解安全边界。请勿将相关技术用于任何未授权的操作。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;做过 SaaS 订阅的人都知道，Stripe 是全球最主流的支付处理商。几乎所有主流 AI 平台——从对话类到图像类——都用 Stripe 处理信用卡支付。&lt;/p&gt;
&lt;p&gt;但很少有人去研究 Stripe Checkout 背后的协议细节。大多数人的认知停留在&amp;quot;调一下 API、跳个 Checkout 页面、信用卡扣完款就行了&amp;quot;。&lt;/p&gt;
&lt;p&gt;实际上，Stripe 的 Checkout Session 协议远比你想象的复杂。从 &lt;code&gt;checkout_ui_mode&lt;/code&gt; 的 &lt;code&gt;custom&lt;/code&gt; 与 &lt;code&gt;hosted&lt;/code&gt; 两种模式，到 &lt;code&gt;ConfirmationToken&lt;/code&gt; 的创建机制，再到 &lt;code&gt;PaymentIntent&lt;/code&gt; 的 &lt;code&gt;requires_action&lt;/code&gt; 状态下 3DS 验证挑战的处理——每一步都有大量的协议细节、反欺诈检测和时序要求。&lt;/p&gt;
&lt;p&gt;今天我把这些全拆开。从 HAR 抓包出发，逐层剖析 Stripe 协议支付的完整链路，并提供 5 套不同技术栈的实现源码。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="零方法论如何逆向-stripe-支付协议"&gt;零、方法论：如何逆向 Stripe 支付协议
&lt;/h2&gt;&lt;p&gt;在开始之前，先讲方法论。所有协议支付的起点都是 &lt;strong&gt;HAR 抓包&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="01-什么是-har-文件"&gt;0.1 什么是 HAR 文件
&lt;/h3&gt;&lt;p&gt;HAR（HTTP Archive）是浏览器开发者工具导出的完整 HTTP 交互记录。包含每个请求的 URL、Headers、Body、Response，以及精确的时序信息。&lt;/p&gt;
&lt;p&gt;打开 Chrome DevTools → Network → 完成一次真实支付 → 右键 → Save all as HAR with content。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个 HAR 文件就是你的 ground truth&lt;/strong&gt;。所有协议支付的字段、值、顺序、编码方式，都以 HAR 为准。代码实现、第三方文档、安全审计报告——全部都可能过时或有误，只有 HAR 是当时浏览器真实发出的请求。&lt;/p&gt;
&lt;h3 id="02-har-分析流程"&gt;0.2 HAR 分析流程
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;筛选关键域名&lt;/strong&gt;：&lt;code&gt;api.stripe.com&lt;/code&gt;、&lt;code&gt;m.stripe.com&lt;/code&gt;、&lt;code&gt;checkout.stripe.com&lt;/code&gt;、平台 API 域名&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按时间排序&lt;/strong&gt;：找出完整的请求链路&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对比成功和失败&lt;/strong&gt;：同一流程的成功 HAR 和失败 HAR，diff 出关键差异&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提取稳定字段&lt;/strong&gt;：跨多个 HAR 都一致的值可以硬编码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标记动态字段&lt;/strong&gt;：每次不同的值（Session ID、Token、时间戳）需要运行时获取&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="03-经过验证的-har-请求链路"&gt;0.3 经过验证的 HAR 请求链路
&lt;/h3&gt;&lt;p&gt;通过分析多个成功支付的 HAR 文件，提取出标准的浏览器 Checkout 请求序列：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. POST /api/v1/payments/checkout → 创建 session (oaics_xxx)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. GET stripe/v1/elements/sessions → 获取 Elements 配置 (deferred_intent)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. POST /api/v1/payments/checkout/taxes → 税务重算 (US免税地址可消除VAT)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. GET stripe/v1/elements/sessions → 更新后的 amount
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5. POST stripe/v1/confirmation_tokens → 卡号 → ctoken_xxx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6. POST /api/v1/payments/checkout/confirm → 平台确认 → pi_xxx client_secret
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;7. POST stripe/v1/payment_intents/{pi}/confirm → Stripe 侧扣款
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;8. GET /checkout/verify → redirect_status=succeeded
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每一步都有大量细节。下面逐一拆解。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一为什么要做协议支付"&gt;一、为什么要做&amp;quot;协议支付&amp;quot;
&lt;/h2&gt;&lt;p&gt;先搞清楚一个概念：什么是协议支付（Protocol Payment）？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;浏览器支付&lt;/strong&gt;：用户打开 Stripe Checkout 页面 → 手动填写信用卡号 → 点击支付 → 完成。这是正常流程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;协议支付&lt;/strong&gt;：用纯 HTTP API 请求模拟浏览器的完整操作链路，包括 Stripe 的内部 API（不是官方 SDK 暴露的那些），直接在协议层完成支付，不需要浏览器。&lt;/p&gt;
&lt;p&gt;为什么要这么做？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;自动化需求&lt;/strong&gt;：批量管理订阅时，手动操作不现实&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能需求&lt;/strong&gt;：浏览器（Puppeteer/Playwright）启动慢、占内存大、不稳定；协议支付 &amp;lt;5s 完成&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境隔离&lt;/strong&gt;：服务端运行，不需要 GUI 环境&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学习价值&lt;/strong&gt;：深入理解支付系统的工作原理&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="二stripe-checkout-session-的两种模式"&gt;二、Stripe Checkout Session 的两种模式
&lt;/h2&gt;&lt;p&gt;Stripe Checkout 有两种 &lt;code&gt;checkout_ui_mode&lt;/code&gt;，这是整个协议支付的第一个分叉点：&lt;/p&gt;
&lt;h3 id="21-custom-模式-oaics_-前缀"&gt;2.1 Custom 模式 (&lt;code&gt;oaics_&lt;/code&gt; 前缀)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST /payments/checkout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;checkout_ui_mode&amp;#34;: &amp;#34;custom&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;currency&amp;#34;: &amp;#34;PHP&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;plan_type&amp;#34;: &amp;#34;plus&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;checkout_session_id&amp;#34;: &amp;#34;oaics_xxx&amp;#34;, &amp;#34;stripe_publishable_key&amp;#34;: &amp;#34;pk_live_...&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Custom 模式返回的 Session ID 以 &lt;code&gt;oaics_&lt;/code&gt; 开头。这种模式下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前端需要自己挂载 Stripe Elements&lt;/li&gt;
&lt;li&gt;通过 Stripe.js 创建 &lt;code&gt;ConfirmationToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;调用平台的 &lt;code&gt;confirm&lt;/code&gt; 接口完成支付&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;直接&lt;/strong&gt;在 Stripe API 上确认 PaymentIntent&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-hosted-模式-cs_live_-前缀"&gt;2.2 Hosted 模式 (&lt;code&gt;cs_live_&lt;/code&gt; 前缀)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST /payments/checkout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;checkout_ui_mode&amp;#34;: &amp;#34;hosted&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;currency&amp;#34;: &amp;#34;PHP&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;plan_type&amp;#34;: &amp;#34;plus&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;checkout_session_id&amp;#34;: &amp;#34;cs_live_xxx&amp;#34;, &amp;#34;url&amp;#34;: &amp;#34;https://checkout.stripe.com/...&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hosted 模式返回 &lt;code&gt;cs_live_&lt;/code&gt; 前缀的 Session。这种模式下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stripe 托管整个 Checkout 页面&lt;/li&gt;
&lt;li&gt;走 Stripe Payment Page 的内部协议&lt;/li&gt;
&lt;li&gt;流程更复杂，涉及 &lt;code&gt;ppage_&lt;/code&gt; 初始化、&lt;code&gt;elements&lt;/code&gt; Session、&lt;code&gt;inline_confirm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要额外处理平台侧的 &lt;code&gt;approve&lt;/code&gt; 操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两种模式的选择取决于平台的 billing 配置和你的需求。一般来说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果平台的计费货币与你的信用卡货币一致 → Custom 模式更简单&lt;/li&gt;
&lt;li&gt;如果存在货币不匹配（比如用美元卡付菲律宾比索订阅）→ 可能只有 Hosted 模式可用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="23-决定性参数checkout_ui_mode"&gt;2.3 决定性参数：&lt;code&gt;checkout_ui_mode&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;通过大量测试验证，&lt;strong&gt;决定返回 &lt;code&gt;oaics_&lt;/code&gt; 还是 &lt;code&gt;cs_live_&lt;/code&gt; 的唯一参数就是 &lt;code&gt;checkout_ui_mode&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 返回 oaics_ 的请求
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;entry_point&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;all_plans_pricing_modal&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;plan_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;basic_plan&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;billing_details&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;country&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PH&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PHP&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;checkout_ui_mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;custom&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 返回 cs_live_ 的请求
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;plan_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;basic_plan&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;billing_details&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;country&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PH&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PHP&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;checkout_ui_mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;hosted&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;cancel_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://platform.example.com/#pricing&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;locale&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;zh-CN&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;entry_point&lt;/code&gt;&lt;/strong&gt;：Custom 模式有，Hosted 模式没有&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;cancel_url&lt;/code&gt;&lt;/strong&gt;：Hosted 模式需要（Stripe 托管页面的返回按钮用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;locale&lt;/code&gt;&lt;/strong&gt;：Hosted 模式建议传（影响 Stripe 页面语言）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hosted 模式的响应多一个 &lt;code&gt;url&lt;/code&gt; 字段——这是 Stripe 托管页面的完整 URL，可以直接在浏览器中打开。&lt;/p&gt;
&lt;h3 id="24-_stripe_version-的版本差异"&gt;2.4 &lt;code&gt;_stripe_version&lt;/code&gt; 的版本差异
&lt;/h3&gt;&lt;p&gt;这是一个极其容易忽略的细节。两种模式使用&lt;strong&gt;不同的 &lt;code&gt;_stripe_version&lt;/code&gt;&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;模式&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;_stripe_version&lt;/code&gt; 值&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Custom (oaics_)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2025-03-31.basil&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Hosted (cs_live_)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2025-03-31.basil; checkout_server_update_beta=v1; checkout_manual_approval_preview=v1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Hosted 模式的版本串后面带了两个 beta flag。如果在 cs_live_ 请求中用了 Custom 的短版本串，Stripe 会返回字段缺失或行为不一致。&lt;/p&gt;
&lt;h3 id="25-两种模式的完整字段对比"&gt;2.5 两种模式的完整字段对比
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;Custom (oaics_)&lt;/th&gt;
 &lt;th&gt;Hosted (cs_live_)&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;确认端点&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;payment_intents/{pi}/confirm&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;payment_pages/{cs_live}/confirm&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;顶层 &lt;code&gt;source&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;elements&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;checkout&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;顶层 &lt;code&gt;version&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2021&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;custom&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;selection_flow&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;merchant_specified&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;automatic&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;elements_session_client&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有（8 个子字段）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;elements_options_client&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有（2 个子字段）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;link_brand&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;link&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;checkout_config_id&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有（两层不同值）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;hCaptcha 位置&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pmd[radar_options][hcaptcha_token]&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;passive_captcha_token&lt;/code&gt;（顶层）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;init_checksum&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;js_checksum&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;rv_timestamp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;expected_amount&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;这两套字段集完全不能混用&lt;/strong&gt;。这也是很多人协议支付做不通的原因——用了 oaics_ 的字段去调 cs_live_ 的接口，反过来也一样。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三custom-模式协议流程详解"&gt;三、Custom 模式协议流程详解
&lt;/h2&gt;&lt;p&gt;Custom 模式是最干净的协议支付路径。完整流程 8 步：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 1. 刷新 Session（获取最新 Token） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 2. 查询账号信息（确认当前订阅状态） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 3. 获取定价信息（币种+金额） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 4. 创建 Checkout Session │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 5. 更新税务信息（Billing 地址） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 6. 创建 ConfirmationToken（卡号→Token）│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 7. 确认支付（Confirm Checkout） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 8. 确认 PaymentIntent（Stripe 侧） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="31-创建-confirmationtoken"&gt;3.1 创建 ConfirmationToken
&lt;/h3&gt;&lt;p&gt;这是协议支付最核心的一步。浏览器里，Stripe.js 会在 iframe 中收集卡号，然后调用 Stripe 的内部 API 创建一个 &lt;code&gt;ConfirmationToken&lt;/code&gt;（&lt;code&gt;ctoken_&lt;/code&gt; 前缀）。&lt;/p&gt;
&lt;p&gt;协议支付需要直接模拟这个请求：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://api.stripe.com/v1/confirmation_tokens
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Content-Type: application/x-www-form-urlencoded
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;type=card
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[type]=card
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[card][number]=4242424242424242
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[card][exp_month]=12
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[card][exp_year]=2029
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[card][cvc]=123
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[billing_details][name]=John Doe
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[billing_details][address][country]=US
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;payment_method_data[billing_details][address][postal_code]=97201
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;key=pk_live_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&amp;amp;_stripe_version=2025-03-31.basil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;几个关键细节：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;key&lt;/code&gt; 必须是平台的 Stripe Publishable Key&lt;/strong&gt;，不是你自己的&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;_stripe_version&lt;/code&gt; 必须匹配&lt;/strong&gt;当前 Stripe.js 的 API 版本&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要传 Stripe.js 的指纹参数&lt;/strong&gt;：&lt;code&gt;guid&lt;/code&gt;、&lt;code&gt;muid&lt;/code&gt;、&lt;code&gt;sid&lt;/code&gt;、&lt;code&gt;time_on_page&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Referer 必须是平台域名&lt;/strong&gt;，Stripe 会校验&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="卡号格式细节"&gt;卡号格式细节
&lt;/h4&gt;&lt;p&gt;HAR 验证发现，浏览器发送的卡号&lt;strong&gt;带空格&lt;/strong&gt;（&lt;code&gt;4004 1641 0185 9397&lt;/code&gt;），而不是纯数字。不过 Stripe 接受两种格式。&lt;/p&gt;
&lt;h4 id="guidmuidsid-格式"&gt;guid/muid/sid 格式
&lt;/h4&gt;&lt;p&gt;这三个指纹 ID 的格式比很多人以为的更复杂。HAR 验证的正确格式是 &lt;strong&gt;42 字符&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;guid = randomUUID() + randomHex(6)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx + 6位hex
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; = 36字符UUID + 6字符 = 42字符
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;code&gt;a1b2c3d4-e5f6-4789-abcd-ef0123456789abc123&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;有些实现用 32 位纯 hex 也能工作，但 HAR 中浏览器发送的是 42 字符格式。&lt;/p&gt;
&lt;h4 id="attribution-元数据两层结构"&gt;Attribution 元数据（两层结构）
&lt;/h4&gt;&lt;p&gt;&lt;code&gt;confirmation_tokens&lt;/code&gt; 请求中有一组 &lt;code&gt;client_attribution_metadata&lt;/code&gt; 字段，这些是 Stripe 用来追踪支付集成来源的元数据：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;payment_user_agent = stripe.js/...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;client_session_id = &amp;lt;UUID&amp;gt; # 每 session 唯一
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;merchant_integration_source = elements # ← oaics_ 固定 &amp;#34;elements&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;merchant_integration_version = 2021
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;merchant_integration_subtype = payment-element
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;payment_intent_creation_flow = deferred
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;payment_method_selection_flow = merchant_specified # ← oaics_ 固定
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;additional_elements = [expressCheckout, payment, address]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些字段在 &lt;code&gt;confirmation_tokens&lt;/code&gt; 请求中出现两次——一次在 &lt;code&gt;payment_method_data&lt;/code&gt; 内部，一次在顶层。&lt;strong&gt;两层的值大部分相同，但 &lt;code&gt;merchant_integration_source&lt;/code&gt; 在 confirm 请求中变成 &lt;code&gt;l1&lt;/code&gt;&lt;/strong&gt;。这个细节从 HAR 中才能发现。&lt;/p&gt;
&lt;h4 id="请求头"&gt;请求头
&lt;/h4&gt;&lt;p&gt;HAR 中 Stripe API 请求的完整请求头：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Accept: application/json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Content-Type: application/x-www-form-urlencoded
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Origin: https://js.stripe.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Referer: https://js.stripe.com/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-CH-UA: &amp;#34;Not=A?Brand&amp;#34;;v=&amp;#34;99&amp;#34;, &amp;#34;Chromium&amp;#34;;v=&amp;#34;151&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-CH-UA-Mobile: ?0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-CH-UA-Platform: &amp;#34;Windows&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-Fetch-Site: same-site
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-Fetch-Mode: cors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-Fetch-Dest: empty
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Accept-Language: en-US,en;q=0.9
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意 &lt;code&gt;Accept-Language&lt;/code&gt; 必须存在。这是纯协议支付跑通的关键 bug 之一——缺少这个 header 会导致 Stripe 返回非预期的响应格式。&lt;/p&gt;
&lt;p&gt;返回值：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ctoken_1xxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;card&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;payment_method_preview&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;card&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;brand&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;visa&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;last4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;4242&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="32-确认-checkout"&gt;3.2 确认 Checkout
&lt;/h3&gt;&lt;p&gt;拿到 &lt;code&gt;ConfirmationToken&lt;/code&gt; 后，调用平台的 confirm 接口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST /api/v1/payments/checkout/confirm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;checkout_session_id&amp;#34;: &amp;#34;oaics_xxx&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;confirmation_token&amp;#34;: &amp;#34;ctoken_1xxx&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一步平台会拿着你的 token 去 Stripe 创建 PaymentIntent 并尝试扣款。&lt;/p&gt;
&lt;p&gt;如果一切顺利（卡余额充足、无 3DS 要求），PaymentIntent 直接变成 &lt;code&gt;succeeded&lt;/code&gt;，订阅激活。&lt;/p&gt;
&lt;p&gt;如果遇到 3DS 验证，流程会更复杂——我们在第五节讲。&lt;/p&gt;
&lt;h3 id="33-elements-session--获取支付配置"&gt;3.3 Elements Session — 获取支付配置
&lt;/h3&gt;&lt;p&gt;在创建 ConfirmationToken 之前，需要先调用 Stripe 的 &lt;code&gt;elements/sessions&lt;/code&gt; API 获取支付配置信息。这一步在 HAR 中被调用&lt;strong&gt;两次&lt;/strong&gt;——一次在税务更新前，一次在税务更新后。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;GET https://api.stripe.com/v1/elements/sessions?deferred_intent[mode]=subscription
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;amp;deferred_intent[amount]=98214
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;amp;deferred_intent[currency]=php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;amp;deferred_intent[setup_future_usage]=off_session
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;amp;deferred_intent[payment_method_types][0]=card
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;amp;type=deferred_intent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;amp;key=pk_live_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;amp;_stripe_version=2025-03-31.basil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键返回值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;elements_session_id&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;elements_session_xxx&lt;/code&gt;，后续 confirm 请求需要&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;customer_session_client_secret&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;cuss_xxx&lt;/code&gt;，客户会话密钥&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;payment_method_configuration&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;pmc_xxx&lt;/code&gt;，支付方式配置 ID&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="34-税务地址优化--us-免税地址消除-vat"&gt;3.4 税务地址优化 — US 免税地址消除 VAT
&lt;/h3&gt;&lt;p&gt;这是一个实际操作中极其重要的技巧。&lt;/p&gt;
&lt;p&gt;很多 SaaS 平台默认按账号注册地收税。比如菲律宾区的订阅，标价 ₱982.14 但实际会加 12% VAT 变成 ₱1,100+。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：在 &lt;code&gt;taxes&lt;/code&gt; API 调用中使用美国免税州地址。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST /api/v1/payments/checkout/taxes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;checkout_session_id&amp;#34;: &amp;#34;oaics_xxx&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;billing_details&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;name&amp;#34;: &amp;#34;John Doe&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;address&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;country&amp;#34;: &amp;#34;US&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;state&amp;#34;: &amp;#34;OR&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;city&amp;#34;: &amp;#34;Portland&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;postal_code&amp;#34;: &amp;#34;97201&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;line1&amp;#34;: &amp;#34;123 Main St&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;美国有 5 个无销售税的州：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Oregon (OR)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Montana (MT)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delaware (DE)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New Hampshire (NH)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alaska (AK)&lt;/strong&gt; — 大部分地区无销售税&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HAR 验证：使用 US 地址后 tax=0，最终金额保持 ₱982.14。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重要&lt;/strong&gt;：&lt;code&gt;taxes&lt;/code&gt; 和后续 &lt;code&gt;confirmation_tokens&lt;/code&gt; 中的地址必须一致。同一个 session 内选择一个地址后全程复用。&lt;/p&gt;
&lt;h3 id="35-paymentintent-确认--stripe-侧扣款"&gt;3.5 PaymentIntent 确认 — Stripe 侧扣款
&lt;/h3&gt;&lt;p&gt;平台的 &lt;code&gt;/confirm&lt;/code&gt; 返回 &lt;code&gt;client_secret&lt;/code&gt;（格式：&lt;code&gt;pi_xxx_secret_xxx&lt;/code&gt;）后，需要调用 Stripe 的 &lt;code&gt;payment_intents/confirm&lt;/code&gt; 完成实际扣款：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://api.stripe.com/v1/payment_intents/{pi_id}/confirm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;return_url = https://platform.example.com/checkout/verify?stripe_session_id=oaics_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;confirmation_token = ctoken_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;key = pk_live_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;_stripe_version = 2025-03-31.basil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;client_secret = pi_xxx_secret_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;client_attribution_metadata[client_session_id] = &amp;lt;UUID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;client_attribution_metadata[merchant_integration_source] = l1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这里 &lt;code&gt;merchant_integration_source&lt;/code&gt; 变成了 &lt;code&gt;l1&lt;/code&gt;，不再是 &lt;code&gt;elements&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="pi-拒卡重试"&gt;PI 拒卡重试
&lt;/h4&gt;&lt;p&gt;HAR 验证了一个重要特性：&lt;strong&gt;同一个 PaymentIntent 被拒卡后可以用新的 ConfirmationToken 重试&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一张卡 → &lt;code&gt;generic_decline&lt;/code&gt; → PI 状态 &lt;code&gt;requires_payment_method&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;创建新的 &lt;code&gt;confirmation_token&lt;/code&gt;（用另一张卡）&lt;/li&gt;
&lt;li&gt;再次调用 &lt;code&gt;payment_intents/confirm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第二张卡 → &lt;code&gt;succeeded&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;这意味着拒卡不需要重建整个 Checkout Session&lt;/strong&gt;，只需要换卡重建 token。&lt;/p&gt;
&lt;h3 id="36-cookie-隔离架构"&gt;3.6 Cookie 隔离架构
&lt;/h3&gt;&lt;p&gt;协议支付需要严格的 Cookie 隔离。一个常见的 bug 是平台的 Cookie 被发送到 Stripe API，或反过来。&lt;/p&gt;
&lt;p&gt;最佳实践：使用两个独立的 HTTP 客户端：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 平台客户端 — 带 Cookie（session token）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;platform_http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookies_enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;platform_http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;__Secure-platform-auth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Stripe 客户端 — 不带 Cookie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;stripe_http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookies_enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;绝不&lt;/strong&gt;让 Stripe 客户端发送平台 Cookie，也不要让平台客户端发送 Stripe 的 Cookie。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四hosted-模式协议流程详解"&gt;四、Hosted 模式协议流程详解
&lt;/h2&gt;&lt;p&gt;Hosted 模式（&lt;code&gt;cs_live_&lt;/code&gt;）的流程更复杂，因为需要模拟 Stripe Payment Page 的完整内部协议。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 1. 创建 Checkout (hosted) → cs_live_ session │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 2. 更新税务 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 3. 分配信用卡 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 4. 初始化 Payment Page → ppage_ token │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 5. 获取 Elements Session │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 6. 创建 ConfirmationToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 7. 确认 Checkout (内部 confirm) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 8. 平台 Approve 操作 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 9. 轮询 PaymentIntent 状态 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 10. 处理 3DS Challenge（如果需要） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 11. 验证最终状态 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└────────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="41-payment-page-初始化"&gt;4.1 Payment Page 初始化
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;GET https://checkout.stripe.com/api/payment-page/{cs_live_xxx}/init
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;→ {&amp;#34;ppage_token&amp;#34;: &amp;#34;ppage_xxx&amp;#34;, &amp;#34;merchant_name&amp;#34;: &amp;#34;...&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是 Hosted 模式独有的。返回一个 &lt;code&gt;ppage_&lt;/code&gt; token，后续所有 Stripe Payment Page API 都需要这个 token。&lt;/p&gt;
&lt;h3 id="42-elements-sessionhosted-模式特殊字段"&gt;4.2 Elements Session（Hosted 模式特殊字段）
&lt;/h3&gt;&lt;p&gt;Hosted 模式的 &lt;code&gt;elements/sessions&lt;/code&gt; 请求比 Custom 模式多出很多字段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://api.stripe.com/v1/elements/sessions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[mode] = subscription
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[amount] = 98214
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[currency] = php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[setup_future_usage] = off_session
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[payment_method_types][0] = card
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[payment_method_configuration][id] = pmc_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;currency = php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;elements_init_source = custom_checkout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;referrer_host = platform.example.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;stripe_js_id = &amp;lt;UUID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;locale = zh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;type = deferred_intent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;checkout_session_id = cs_live_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;_stripe_version = 2025-03-31.basil; checkout_server_update_beta=v1; ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要传 &lt;code&gt;checkout_session_id&lt;/code&gt;（Custom 模式不需要）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elements_init_source&lt;/code&gt; 是 &lt;code&gt;custom_checkout&lt;/code&gt;（不是 &lt;code&gt;elements&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;需要传 &lt;code&gt;referrer_host&lt;/code&gt;、&lt;code&gt;stripe_js_id&lt;/code&gt;、&lt;code&gt;locale&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用&lt;strong&gt;长版本&lt;/strong&gt;的 &lt;code&gt;_stripe_version&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;返回值中有一个重要字段 &lt;code&gt;passive_captcha.rqdata&lt;/code&gt;——这是 hCaptcha Enterprise 的 &lt;code&gt;rqdata&lt;/code&gt;，后续 confirm 如果触发 challenge 需要用到。&lt;/p&gt;
&lt;h3 id="43-hosted-模式的-confirm-请求"&gt;4.3 Hosted 模式的 Confirm 请求
&lt;/h3&gt;&lt;p&gt;cs_live_ 的 confirm 走的是 &lt;code&gt;payment_pages/confirm&lt;/code&gt;，不是 &lt;code&gt;payment_intents/confirm&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://api.stripe.com/v1/payment_pages/{cs_live_xxx}/confirm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个请求的 body 字段比 Custom 模式多很多：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[client_betas][0] = custom_checkout_server_updates_1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[client_betas][1] = custom_checkout_manual_approval_1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[elements_init_source] = custom_checkout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[referrer_host] = platform.example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[session_id] = elements_session_xxx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[stripe_js_id] = &amp;lt;UUID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[locale] = zh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[is_aggregation_expected] = false
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_options_client[saved_payment_method][enable_save] = auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_options_client[saved_payment_method][enable_redisplay] = auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;init_checksum = &amp;lt;checksum&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;js_checksum = &amp;lt;checksum&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rv_timestamp = &amp;lt;timestamp&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;expected_amount = 98214
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;expected_payment_method_type = card
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;version = &amp;lt;build_hash&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;js_checksum&lt;/code&gt; 和 &lt;code&gt;rv_timestamp&lt;/code&gt; 是从 Stripe.js 部署状态动态提取的，&lt;code&gt;init_checksum&lt;/code&gt; 来自 init 响应。&lt;/p&gt;
&lt;h3 id="44-approve-机制与-sentinel-token"&gt;4.4 Approve 机制与 Sentinel Token
&lt;/h3&gt;&lt;p&gt;Hosted 模式下，&lt;code&gt;payment_pages/confirm&lt;/code&gt; 成功后，状态不会直接变成 &lt;code&gt;succeeded&lt;/code&gt;，而是进入 &lt;code&gt;requires_approval&lt;/code&gt;（HAR 中 confirm 返回 &lt;code&gt;status=open&lt;/code&gt;）。这时需要调用平台的 approve 接口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST /api/v1/payments/checkout/approve
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Authorization: Bearer {access_token}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;X-Vendor-Challenge-Token: {sentinel_token}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="sentinel-token-结构"&gt;Sentinel Token 结构
&lt;/h4&gt;&lt;p&gt;这里的 &lt;code&gt;challenge_token&lt;/code&gt; 是一个编码后的 JSON 对象，内部包含多个通过算力证明（PoW）和 Turnstile 验证生成的字段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;p&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gAAAAAB...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 主负载（加密后的 PoW + session 信息）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;c&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// enforcement_token（基于 FNV-1a 的算力证明结果）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;UUID&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 一次性标识
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;flow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;platform_checkout&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 标记来源流程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;turnstile_dx_token&amp;gt;&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;// 4000+ 字符的 Turnstile 验证 token
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;t&lt;/code&gt; 字段是核心&lt;/strong&gt;——如果为空字符串，approve 立即返回 &lt;code&gt;blocked&lt;/code&gt;。它来自 Cloudflare Turnstile 的隐式挑战验证（不是肉眼可见的验证码）。&lt;/p&gt;
&lt;h4 id="sentinel-token-生成流程"&gt;Sentinel Token 生成流程
&lt;/h4&gt;&lt;p&gt;完整的 Sentinel 生成需要两个组件协作：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. 生成 requirements_token（本地 seed + difficulty &amp;#34;0&amp;#34;）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. POST sentinel.platform.com/backend-api/sentinel/req
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 返回 {turnstile: {dx: &amp;#34;...&amp;#34;}, ...}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. 用 server seed 生成 enforcement_token（FNV-1a 算力证明）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. 在 Node.js VM 中执行 Turnstile SDK（需要 jsdom 模拟 DOM 环境）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 返回 turnstile token（~4388 字符）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5. 组装 JSON → Base64 → 设为请求头
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PoW 使用 &lt;strong&gt;FNV-1a&lt;/strong&gt; 哈希算法，difficulty 对 checkout 流程通常是 “0”（即几乎不需要算力）&lt;/li&gt;
&lt;li&gt;Turnstile SDK 必须在&lt;strong&gt;真实的 DOM 环境&lt;/strong&gt;中执行——简单的字符串拼接无法通过验证&lt;/li&gt;
&lt;li&gt;实际生产中需要 Node.js + jsdom 来执行官方 Turnstile VM&lt;/li&gt;
&lt;li&gt;SDK 代码需要定期更新（随平台版本迭代）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="approve-的正确时机"&gt;Approve 的正确时机
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;关键发现&lt;/strong&gt;：Approve 不应该主动调用。正确的流程是 &lt;strong&gt;fall-through&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;confirm → status=open, requires_approval
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 等待 Stripe 回调
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 平台自动完成 approve（不需要客户端调）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; poll payment_page → PI 出现
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 可能 requires_action → verify_challenge
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; poll 到 succeeded → 完成
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但某些边缘情况下（平台回调未触发），客户端需要手动 approve。此时 Sentinel token 是必须的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Approve 是&lt;strong&gt;一次性操作&lt;/strong&gt;，同一 session 不可重复&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;t&lt;/code&gt; 字段为空或格式错误 → 返回 &lt;code&gt;blocked&lt;/code&gt; → session 作废&lt;/li&gt;
&lt;li&gt;成功的 approve 返回 &lt;code&gt;{&amp;quot;result&amp;quot;:&amp;quot;approved&amp;quot;}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="五3ds-验证挑战"&gt;五、3DS 验证挑战
&lt;/h2&gt;&lt;p&gt;当 Stripe 判断交易需要额外验证时，PaymentIntent 会进入 &lt;code&gt;requires_action&lt;/code&gt; 状态，附带 3DS challenge 信息。&lt;/p&gt;
&lt;h3 id="51-challenge-类型"&gt;5.1 Challenge 类型
&lt;/h3&gt;&lt;p&gt;Stripe 使用 hCaptcha Enterprise 作为 3DS 验证手段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;requires_action&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;next_action&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;verify_with_challenge&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;verify_with_challenge&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://challenges.stripe.com/...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;challenge_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;hcaptcha&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="52-verify_challenge-完整请求格式"&gt;5.2 verify_challenge 完整请求格式
&lt;/h3&gt;&lt;p&gt;HAR 中验证的 &lt;code&gt;verify_challenge&lt;/code&gt; 完整请求：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://api.stripe.com/v1/payment_intents/{pi_id}/verify_challenge
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;captcha_response = {hcaptcha_token} # P0开头的长字符串
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;captcha_vendor_name = hcaptcha # 固定值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;captcha_sitekey = xxxxxxxx-xxxx-xxxx # Stripe 的 hCaptcha sitekey
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;expected_amount = 98214 # 交易金额
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;expected_currency = php # 币种
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;key = pk_live_xxx # Publishable Key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;_stripe_version = 2025-03-31.basil; checkout_server_update_beta=v1; ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;client_secret = pi_xxx_secret_xxx # PI 的 client_secret
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字段名是 &lt;code&gt;captcha_response&lt;/code&gt; 而不是 &lt;code&gt;challenge_response&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要同时传 &lt;code&gt;captcha_vendor_name&lt;/code&gt; 和 &lt;code&gt;captcha_sitekey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要传 &lt;code&gt;expected_amount&lt;/code&gt;/&lt;code&gt;expected_currency&lt;/code&gt; 做一致性校验&lt;/li&gt;
&lt;li&gt;使用&lt;strong&gt;长版本&lt;/strong&gt; &lt;code&gt;_stripe_version&lt;/code&gt;（与 Hosted 模式一致）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="53-hcaptcha-enterprise-的特殊性"&gt;5.3 hCaptcha Enterprise 的特殊性
&lt;/h3&gt;&lt;p&gt;Stripe 使用的不是普通 hCaptcha，而是 &lt;strong&gt;hCaptcha Enterprise&lt;/strong&gt;。区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;有 &lt;code&gt;rqdata&lt;/code&gt; 参数&lt;/strong&gt;：普通 hCaptcha 不需要 rqdata，Enterprise 必须传&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sitekey 是 Stripe 专有的&lt;/strong&gt;：从 &lt;code&gt;elements/sessions&lt;/code&gt; 响应的 &lt;code&gt;passive_captcha&lt;/code&gt; 字段中提取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;invisible 模式&lt;/strong&gt;：浏览器里看不到验证码图片，但后台在做风控评估&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 从 elements_session 响应中提取&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rqdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elements_session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;passive_captcha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rqdata&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sitekey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elements_session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;passive_captcha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;sitekey&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="54-时效性问题"&gt;5.4 时效性问题
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;hCaptcha token 有时效性&lt;/strong&gt;——浏览器里 ~4 秒解出即有效，但远程打码服务可能需要 30-120 秒。如果超时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;verify_challenge&lt;/code&gt; 返回 &lt;code&gt;payment_intent_authentication_failure&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;但 PI 状态仍然是 &lt;code&gt;requires_action&lt;/code&gt;——&lt;strong&gt;可以重新 verify_challenge&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解决方案分级：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;最优&lt;/strong&gt;：本地 headless 浏览器解 hCaptcha（&amp;lt;5s，成功率 95%+）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;次优&lt;/strong&gt;：支持 Enterprise rqdata 的快速打码 API（如 YesCaptcha，~15s）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兜底&lt;/strong&gt;：如果 PI 已经进入 &lt;code&gt;requires_action&lt;/code&gt;，可以循环重试 verify_challenge（每次用新 captcha token）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="55-3ds-vs-hcaptcha-的区别"&gt;5.5 3DS vs hCaptcha 的区别
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;重要澄清&lt;/strong&gt;：Stripe 的 &lt;code&gt;verify_with_challenge&lt;/code&gt; 并非传统银行 3DS 验证（3D Secure）。它是 Stripe 自有的风控挑战，使用 hCaptcha 作为人机验证手段。&lt;/p&gt;
&lt;p&gt;真正的银行 3DS（如 Visa Secure）会打开银行页面要求输入 OTP/密码，这个在纯协议支付中&lt;strong&gt;无法绕过&lt;/strong&gt;——但使用虚拟信用卡（VCC）通常不会触发银行 3DS，只会触发 Stripe 自身的 hCaptcha challenge。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六tls-指纹对抗"&gt;六、TLS 指纹对抗
&lt;/h2&gt;&lt;p&gt;纯 HTTP 请求最大的挑战不是协议逻辑，而是 &lt;strong&gt;TLS 指纹&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Stripe 和 Cloudflare 都会检查 TLS Client Hello 的指纹（JA3/JA4），如果发现你的 TLS 握手特征不像浏览器，直接返回 403/429。&lt;/p&gt;
&lt;h3 id="61-指纹伪装"&gt;6.1 指纹伪装
&lt;/h3&gt;&lt;p&gt;Python 项目使用 &lt;code&gt;curl_cffi&lt;/code&gt; 库，支持模拟多种浏览器的 TLS 指纹：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PROFILES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;chrome131&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Chrome/131.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;chrome124&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Chrome/124.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;safari18&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Safari/605.1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;firefox117&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Firefox/117.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Node.js 项目使用 &lt;code&gt;CycleTLS&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;initCycleTLS&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;cycletls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cycleTLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;initCycleTLS&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cycleTLS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ja3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;771,4865-4866-4867...&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Mozilla/5.0 ...&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="62-指纹轮换策略"&gt;6.2 指纹轮换策略
&lt;/h3&gt;&lt;p&gt;当遇到 403/429 时，自动切换到下一个 TLS 指纹配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TLSFingerprintManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rotate_on_failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exclude_current&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pick_next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最多重试 3 次，每次使用不同的浏览器指纹。&lt;/p&gt;
&lt;h3 id="63-tls-指纹与-user-agent-一致性"&gt;6.3 TLS 指纹与 User-Agent 一致性
&lt;/h3&gt;&lt;p&gt;一个常见错误是 TLS 指纹和 User-Agent 不匹配。比如用 Chrome 131 的 TLS 指纹配置但 User-Agent 写的是 Chrome 124，Cloudflare 的 bot detection 会立即发现这种不一致。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正确做法&lt;/strong&gt;：TLS profile 和 UA 必须成对配置：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PROFILES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;tls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;chrome131&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;ua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/131.0.0.0 Safari/537.36&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;sec_ch_ua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#34;Not=A?Brand&amp;#34;;v=&amp;#34;99&amp;#34;, &amp;#34;Chromium&amp;#34;;v=&amp;#34;131&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;tls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;safari18&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;ua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) ... Safari/605.1.15&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;sec_ch_ua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="c1"&gt;# Safari 不发 sec-ch-ua&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="64-http-协议版本"&gt;6.4 HTTP 协议版本
&lt;/h3&gt;&lt;p&gt;另一个细节：Stripe 的 API 请求在浏览器中走 &lt;strong&gt;HTTP/2&lt;/strong&gt;，但 &lt;code&gt;payment_intents/confirm&lt;/code&gt; 在某些实现中用 HTTP/1.1 反而更稳定。&lt;/p&gt;
&lt;p&gt;HAR 中观察到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;confirmation_tokens&lt;/code&gt;：HTTP/2&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment_intents/confirm&lt;/code&gt;：可以 HTTP/1.1&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment_pages/confirm&lt;/code&gt;：HTTP/2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 &lt;code&gt;curl_cffi&lt;/code&gt; 时默认走 HTTP/2（如果服务端支持），CycleTLS 需要在选项中显式指定。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七stripejs-指纹参数"&gt;七、Stripe.js 指纹参数
&lt;/h2&gt;&lt;p&gt;Stripe 的 &lt;code&gt;confirmation_tokens&lt;/code&gt; 和 &lt;code&gt;payment_intents/confirm&lt;/code&gt; 接口都需要一组指纹参数。这些参数由 Stripe.js 在前端收集，协议支付需要正确模拟：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数&lt;/th&gt;
 &lt;th&gt;含义&lt;/th&gt;
 &lt;th&gt;生成方式&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;guid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;全局唯一 ID&lt;/td&gt;
 &lt;td&gt;UUID + 6位 hex = 42 字符（见 3.1 节）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;muid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;设备 ID&lt;/td&gt;
 &lt;td&gt;同 guid 格式，42 字符&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;sid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;会话 ID&lt;/td&gt;
 &lt;td&gt;同 guid 格式，42 字符&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;time_on_page&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;页面停留时间&lt;/td&gt;
 &lt;td&gt;随机 8-30 秒（模拟真实用户）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;key&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Publishable Key&lt;/td&gt;
 &lt;td&gt;从 Checkout Session 获取&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;_stripe_version&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;API 版本&lt;/td&gt;
 &lt;td&gt;从 Stripe.js 的 basil 部署中提取&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="71-mstripecom6--指纹注册"&gt;7.1 m.stripe.com/6 — 指纹注册
&lt;/h3&gt;&lt;p&gt;在所有业务请求之前，Stripe.js 会向 &lt;code&gt;m.stripe.com/6&lt;/code&gt; 发送 4 次 POST 请求注册设备指纹。HAR 中的完整调用链：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST https://m.stripe.com/6 (×4)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每次请求的 body 是 &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;，包含：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v2 = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;id = &amp;lt;stripe_js_id&amp;gt; # 与 confirmation_tokens 中的 guid 不同
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tag = &amp;lt;event_tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;src = js
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a = &amp;lt;JSON编码的分析数据&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tag&lt;/code&gt; 的值依次为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;stripejs-init-started&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stripejs-init-complete&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;adyen-component-loaded&lt;/code&gt;（如果有 Adyen）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment-element-mounted&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;a&lt;/code&gt; 字段包含浏览器环境的详细指纹数据（屏幕尺寸、时区、语言、plugin 列表等）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实际影响&lt;/strong&gt;：不发这些请求也能支付成功，但长期使用同一个 &lt;code&gt;guid&lt;/code&gt;/&lt;code&gt;muid&lt;/code&gt; 而从未注册过指纹可能触发 Stripe Radar 的异常检测。建议至少发一次 &lt;code&gt;stripejs-init-complete&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="72-rstripecomb--遥测上报"&gt;7.2 r.stripe.com/b — 遥测上报
&lt;/h3&gt;&lt;p&gt;Stripe.js 还会持续向 &lt;code&gt;r.stripe.com/b&lt;/code&gt; 发送遥测数据：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;plain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个请求的 payload 是 JSON（不是 form-urlencoded），包含支付流程中的各种事件指标（加载时间、渲染时间、错误数）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;measurement&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;paymentElement.mount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;metrics&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;342&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;client_session_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;UUID&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;publish_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pk_live_xxx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;实际影响&lt;/strong&gt;：纯可选。不发不影响支付成功。但如果你的实现在生产中运行，偶尔发几次遥测可以让你的流量看起来更像真实浏览器。&lt;/p&gt;
&lt;h3 id="73-动态提取-stripejs-版本"&gt;7.3 动态提取 Stripe.js 版本
&lt;/h3&gt;&lt;p&gt;Stripe.js 的版本（&lt;code&gt;_stripe_version&lt;/code&gt;）和构建哈希（&lt;code&gt;rv&lt;/code&gt;/&lt;code&gt;sv&lt;/code&gt;）不是固定的，需要从 Stripe 的部署状态接口动态提取：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 获取当前 Stripe.js 部署信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://js.stripe.com/deploy_status_henson.json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;basil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// basil.rv = &amp;#34;2025-03-31&amp;#34; → _stripe_version = &amp;#34;2025-03-31.basil&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Custom 模式只需要基础版本：&lt;code&gt;2025-03-31.basil&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Hosted 模式需要追加 beta flags：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2025-03-31.basil; checkout_server_update_beta=v1; custom_checkout_beta=v1; ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些 beta flags 从 &lt;code&gt;deploy_status_henson.json&lt;/code&gt; 的 metadata 或 checkout 页面的初始化脚本中提取。Stripe 大约每 1-2 周更新一次部署版本。&lt;/p&gt;
&lt;h3 id="74-js_checksum-和-rv_timestamp"&gt;7.4 js_checksum 和 rv_timestamp
&lt;/h3&gt;&lt;p&gt;Hosted 模式的 &lt;code&gt;payment_pages/confirm&lt;/code&gt; 需要两个动态校验值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;js_checksum&lt;/code&gt;&lt;/strong&gt;：当前 Stripe.js bundle 的 SHA 校验和，从 deploy status 提取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rv_timestamp&lt;/code&gt;&lt;/strong&gt;：当前 Stripe.js 的部署时间戳（Unix 毫秒），也从 deploy status 提取&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两个值随 Stripe.js 版本更新而变化。如果使用过期的 checksum/timestamp，confirm 可能会被静默拒绝。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deploy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://js.stripe.com/deploy_status_henson.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;js_checksum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;basil&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;js_checksum&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rv_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;basil&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rv_timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="八代理池架构"&gt;八、代理池架构
&lt;/h2&gt;&lt;p&gt;协议支付的另一个核心组件是代理池。Stripe 和平台都会检查请求的源 IP，用数据中心 IP 直连容易被标记。&lt;/p&gt;
&lt;h3 id="81-双代理池"&gt;8.1 双代理池
&lt;/h3&gt;&lt;p&gt;最佳实践是使用两个独立的代理池：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;平台代理池&lt;/strong&gt;：用于访问 SaaS 平台的 API（需要与账号注册地匹配）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stripe 代理池&lt;/strong&gt;：用于访问 Stripe API（需要住宅 IP，避免被 Radar 标记）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="82-代理健康检查"&gt;8.2 代理健康检查
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProxyVerifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected_country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://ipapi.co/json/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;country_code&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected_country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;ProxyCountryMismatchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="83-出口-ip-一致性"&gt;8.3 出口 IP 一致性
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;关键规则&lt;/strong&gt;：创建 Checkout Session 和确认支付时，必须使用&lt;strong&gt;同一个出口 IP&lt;/strong&gt;。Stripe 会比对两次请求的 IP，如果不一致会拒绝交易。&lt;/p&gt;
&lt;p&gt;这意味着整个支付流程中的所有请求（从创建 session 到 confirm）必须绑定同一个代理出口。如果代理池做了负载均衡，需要在支付流程中&amp;quot;钉住&amp;quot;一个代理节点。&lt;/p&gt;
&lt;h3 id="84-代理类型选择"&gt;8.4 代理类型选择
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;代理类型&lt;/th&gt;
 &lt;th&gt;适用场景&lt;/th&gt;
 &lt;th&gt;风险&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;住宅代理（Residential）&lt;/td&gt;
 &lt;td&gt;Stripe API / 平台 API&lt;/td&gt;
 &lt;td&gt;最安全，IP 信誉高&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ISP 代理（Static Residential）&lt;/td&gt;
 &lt;td&gt;长期固定使用&lt;/td&gt;
 &lt;td&gt;中等，某些已被标记&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;数据中心代理（Datacenter）&lt;/td&gt;
 &lt;td&gt;测试/开发&lt;/td&gt;
 &lt;td&gt;高风险，Stripe Radar 会标记&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;移动代理（Mobile）&lt;/td&gt;
 &lt;td&gt;高价值交易&lt;/td&gt;
 &lt;td&gt;最安全但最贵&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;生产环境建议住宅代理。数据中心 IP 在 Stripe 的风控系统中通常有较高的 risk score。&lt;/p&gt;
&lt;h3 id="85-代理故障降级"&gt;8.5 代理故障降级
&lt;/h3&gt;&lt;p&gt;代理不可用时的处理策略：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_proxy_with_fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 降级：尝试其他国家的代理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;US&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 最终降级：直连（仅限测试环境）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow_direct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;NoProxyAvailableError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：不要在生产环境用直连降级——数据中心 IP 直连 Stripe 几乎必被拒。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="九状态机设计"&gt;九、状态机设计
&lt;/h2&gt;&lt;p&gt;完整的协议支付需要处理多种失败场景和重试逻辑。最佳实践是使用状态机：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;初始化 → 刷新Session → 检查权限 → 获取定价 → 创建Checkout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ ↓ ↓ ↓ ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 失败→退出 失败→退出 已有订阅→跳过 失败→退出 失败→退出
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 更新税务 → 创建Token → 确认支付
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ ↓ ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 失败→退出 卡被拒→换卡 3DS→验证
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 成功 / 失败
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个状态转移都需要处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;卡被拒（Card Declined）&lt;/strong&gt;：分类拒绝原因（余额不足/CVV错误/风控拒绝），决定是换卡重试还是放弃&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3DS 验证&lt;/strong&gt;：进入 Challenge 流程&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session 过期&lt;/strong&gt;：创建新 Session 重试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate Limiting&lt;/strong&gt;：TLS 指纹轮换 + 退避重试&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="91-decline-错误分类"&gt;9.1 Decline 错误分类
&lt;/h3&gt;&lt;p&gt;Stripe 的卡拒绝错误不是一个笼统的&amp;quot;失败&amp;quot;，而是分为可重试和不可重试两类：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可重试（换卡后重试）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;generic_decline&lt;/code&gt; — 最常见，通常是风控拒绝，换卡几乎总能过&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insufficient_funds&lt;/code&gt; — 余额不足，充值后或换卡可过&lt;/li&gt;
&lt;li&gt;&lt;code&gt;processing_error&lt;/code&gt; — Stripe 侧临时错误，直接重试&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;不可重试（放弃本次 session）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stolen_card&lt;/code&gt; / &lt;code&gt;lost_card&lt;/code&gt; — 卡已被标记，不能再用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;card_not_supported&lt;/code&gt; — 卡类型不支持（如某些预付卡）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currency_not_supported&lt;/code&gt; — 卡不支持目标币种&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;需要特殊处理&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;incorrect_cvc&lt;/code&gt; — CVC 错误，检查是否传错了&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expired_card&lt;/code&gt; — 卡过期，需要从卡池中移除&lt;/li&gt;
&lt;li&gt;&lt;code&gt;card_velocity_exceeded&lt;/code&gt; — 卡的交易频率超限，冷却后可重试&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="92-fast-path-优化"&gt;9.2 Fast-Path 优化
&lt;/h3&gt;&lt;p&gt;一个重要的状态机优化：&lt;strong&gt;如果 PI 已经 &lt;code&gt;succeeded&lt;/code&gt;，跳过 hCaptcha&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;HAR 中发现，有时 confirm 返回 &lt;code&gt;requires_action&lt;/code&gt;（hCaptcha challenge），但 PI 实际上已经扣款成功。这时如果盲目去解 captcha，反而可能出错。&lt;/p&gt;
&lt;p&gt;正确做法是在收到 &lt;code&gt;requires_action&lt;/code&gt; 后，&lt;strong&gt;先查询 PI 状态&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/v1/payment_intents/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pi_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pk_live&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;succeeded&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 已经扣款成功，跳过 captcha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PaymentResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;requires_action&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 确实需要解 captcha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;solve_hcaptcha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="93-hosted-模式轮询"&gt;9.3 Hosted 模式轮询
&lt;/h3&gt;&lt;p&gt;cs_live_ 模式在 confirm 之后需要轮询 &lt;code&gt;payment_page&lt;/code&gt; 状态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST https://api.stripe.com/v1/payment_pages/{cs_live_xxx}/poll
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;payment_intent&amp;#34;: &amp;#34;pi_xxx&amp;#34;, &amp;#34;status&amp;#34;: &amp;#34;open&amp;#34;} // 等待中
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;payment_intent&amp;#34;: &amp;#34;pi_xxx&amp;#34;, &amp;#34;payment_object_status&amp;#34;: &amp;#34;requires_action&amp;#34;} // 需要 captcha
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;payment_intent&amp;#34;: &amp;#34;pi_xxx&amp;#34;, &amp;#34;payment_object_status&amp;#34;: &amp;#34;succeeded&amp;#34;} // 完成
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;轮询间隔建议 2-3 秒，最多轮询 60 秒。如果超时未变化，检查是否需要手动 approve。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="十安全边界与最佳实践"&gt;十、安全边界与最佳实践
&lt;/h2&gt;&lt;h3 id="101-session-隔离"&gt;10.1 Session 隔离
&lt;/h3&gt;&lt;p&gt;每次支付使用独立的 Session，不复用已失败的 Session。特别是 Hosted 模式下，&lt;code&gt;approve&lt;/code&gt; 操作后的 Session 不可再次使用。&lt;/p&gt;
&lt;h3 id="102-dry-run-模式"&gt;10.2 Dry-Run 模式
&lt;/h3&gt;&lt;p&gt;所有实现都应支持 Dry-Run 模式——执行完整流程但不提交最终的 &lt;code&gt;confirm&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit_payments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confirm_payment_intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Dry-run: skipping confirm&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这对于调试非常重要：你可以验证整个流程（创建 session、生成 token、税务计算）都正确，而不实际扣钱。&lt;/p&gt;
&lt;h3 id="103-不要存储敏感数据"&gt;10.3 不要存储敏感数据
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;信用卡号仅在内存中使用，支付完成后立即清除&lt;/li&gt;
&lt;li&gt;Session token 不应写入日志（log 中用 &lt;code&gt;***&lt;/code&gt; 替代）&lt;/li&gt;
&lt;li&gt;代理凭据不要硬编码，用环境变量或加密存储&lt;/li&gt;
&lt;li&gt;Stripe Publishable Key 可以写入代码（它本来就是公开的），但 Secret Key 绝不能出现在客户端&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="104-请求节奏模拟"&gt;10.4 请求节奏模拟
&lt;/h3&gt;&lt;p&gt;纯协议支付的一个风险是请求速度&lt;strong&gt;太快&lt;/strong&gt;。浏览器用户从打开支付页面到点击确认，通常需要 15-60 秒。如果你的自动化在 2 秒内完成全部请求，Stripe Radar 可能标记为异常。&lt;/p&gt;
&lt;p&gt;建议在关键步骤间加入随机延迟：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 创建 session 后&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 更新税务后&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 创建 token 后&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# confirm 前&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;总时间控制在 8-30 秒之间比较自然。&lt;/p&gt;
&lt;h3 id="105-并发控制"&gt;10.5 并发控制
&lt;/h3&gt;&lt;p&gt;批量处理多个账号时，不要让所有请求同时发出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stripe API&lt;/strong&gt;：有 rate limit，同一 publishable key 下大量并发 confirm 会触发 429&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平台 API&lt;/strong&gt;：多个账号同时操作可能触发风控&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代理池&lt;/strong&gt;：每个代理 IP 上同时只运行 1-2 个支付流程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议使用信号量（semaphore）限制并发：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 最多同时处理 3 个支付&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;process_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="十一实现对比"&gt;十一、实现对比
&lt;/h2&gt;&lt;p&gt;文末提供的 5 套实现覆盖了不同的技术栈和使用场景：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;实现&lt;/th&gt;
 &lt;th&gt;语言/框架&lt;/th&gt;
 &lt;th&gt;模式&lt;/th&gt;
 &lt;th&gt;特点&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;saas-pay-sdk&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python / CLI&lt;/td&gt;
 &lt;td&gt;Custom&lt;/td&gt;
 &lt;td&gt;最精简的 CLI 工具，TLS 指纹轮换，daemon 上报&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;subscription-manager&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python Flask / Web UI&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;完整 Web 管理面板，支持绑卡、查账单、升级降级&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;payment-gateway&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python Flask / Web UI&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;批量支付面板，账号池管理，barrier 模式批量确认&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;checkout-server&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python / Local HTTP&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;本地支付编排服务器，Playwright 降级，SQLite 持久化&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;protocol-engine&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Node.js / Modules&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;模块化协议引擎，CycleTLS，动态 Stripe.js 版本抓取&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;每个实现都有自己的优缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;想要最快上手 → &lt;code&gt;saas-pay-sdk&lt;/code&gt;（纯 CLI，pip install 即可）&lt;/li&gt;
&lt;li&gt;想要可视化管理 → &lt;code&gt;subscription-manager&lt;/code&gt;（Web UI）&lt;/li&gt;
&lt;li&gt;想要批量处理 → &lt;code&gt;payment-gateway&lt;/code&gt;（账号池 + 批量模式）&lt;/li&gt;
&lt;li&gt;想要理解底层 → &lt;code&gt;protocol-engine&lt;/code&gt;（模块化，可以单独引用任何一层）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="下载"&gt;下载
&lt;/h2&gt;&lt;p&gt;以下是 5 套完整实现的源码下载链接：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;项目&lt;/th&gt;
 &lt;th&gt;下载链接&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;saas-pay-sdk&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/saas-pay-sdk.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Python CLI 工具&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;subscription-manager&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/subscription-manager.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Flask Web 管理面板&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;payment-gateway&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/payment-gateway.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;批量支付网关面板&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;checkout-server&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/checkout-server.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;本地支付编排服务器&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;protocol-engine&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/protocol-engine.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Node.js 协议引擎模块&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：所有源码中的 API Key、域名、账号信息均已替换为占位符。使用前需要根据你的实际环境配置 &lt;code&gt;.env&lt;/code&gt; 文件。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="推荐虚拟卡平台"&gt;推荐：虚拟卡平台
&lt;/h2&gt;&lt;p&gt;协议支付离不开信用卡。如果你需要一张支持 Stripe 的虚拟信用卡用于订阅海外 SaaS 服务（ChatGPT、Claude、Cursor 等），推荐 &lt;strong&gt;ZovoCard&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持 Visa / Mastercard，全球 Stripe 商户可用&lt;/li&gt;
&lt;li&gt;即开即用，无需实体卡，支持 USDT 充值&lt;/li&gt;
&lt;li&gt;多卡管理，适合批量订阅场景&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="link" href="https://zovocard.com/register?invite=DW6AYPAP" target="_blank" rel="noopener"
 &gt;注册 ZovoCard →&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;如果你对支付安全感兴趣，欢迎加微信群交流。&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>