在 Webhook 端点中接收 Stripe 事件
向您的 AWS 账户发送事件。
我们即将支持在 Amazon EventBridge 中接收 Stripe 事件,但先期为封闭测试阶段。要提前访问,请前往 eventbridge.stripe.dev 进行注册。
为什么要使用 Webhook
在构建 Stripe 集成时,您可能希望在您的 Stripe 账户中有事件发生时,您的应用程序可以接收它们,以便您的后端系统可以执行相应操作。
要启用 Webhook 事件,您需要注册 Webhook 端点。注册后,当您的 Stripe 账户中发生事件时,Stripe 可以将实时事件数据推送到您的应用程序的 Webhook 端点。Stripe 使用 HTTPS 将 Webhook 事件作为 JSON 有效负载发送到您的应用程序,该有效载荷包含事件对象。
接收 Webhook 事件对于侦听异步事件尤其有用,例如客户的银行确认付款、客户对收款提出争议、经常性付款成功,或收集订阅付款。
事件概览
Stripe 会生成事件数据,我们可以将这些数据发送给您,通知您账户中的活动。
当有事件发生时,Stripe 会生成一个新的事件对象。单个 API 请求可能会导致创建多个事件。例如,如果您为客户创建新的订阅,您会收到 customer.subscription.created
和 payment_intent.succeeded
事件。
在您的 Stripe 账户中注册 Webhook 端点后,您可以使 Stripe 自动将事件对象作为 POST 请求的一部分发送到您的应用程序托管的已注册 Webhook 端点。在您的 Webhook 端点收到事件后,您的应用程序可以运行后端操作(例如,在您收到 payment_intent.succeeded
事件后,调用您的配送商的 API 来安排配送)。
事件对象
我们发送到您的 Webhook 端点的事件对象提供了已修改对象的快照。在适用的情况下,它们可以包含指示变化的 previous_attributes
属性。
查看我们发送到您的 Webhook 的事件类型的完整列表。
示例事件有效负载
以下事件显示的是试用结束时的订阅更新。
{ "id": "evt_1MqqbKLt4dXK03v5qaIbiNCC", "object": "event", "api_version": "2024-04-10", "created": 1680064028,
事件对象的结构
查看事件对象的结构,以更好地理解事件及其提供的基本信息。
事件类型
您会收到 Webhook 端点在您的配置中侦听的所有事件类型的事件。使用接收到的事件 type
确定您的应用程序需要执行的处理操作。与每个事件的 type
对应的 data.object
是不同的。
真实和测试模式
您可能会收到向您的端点发送真实和测试模式事件的请求。如果您对真实和测试模式都使用单个端点,或者如果您是一个 Connect 平台,那么在对真实 Standard 账户发出测试模式的请求,就会发生这种情况。用 livemode
属性检查对象是处于真实模式还是测试模式,并确定事件的正确处理方式。
API 版本
api_version
表示事件的 API 版本,并且指示所包含的 data.object 的结构。您的端点使用配置的 API 版本接收事件,该版本可以不同于您账户的默认 API 版本或与事件相关的任何请求的 API 版本。该属性由目的地端点决定,这表明相同的事件可能被发送到使用不同 API 版本的多个端点。如果您使用的是我们的 Java、.NET 或 Go 客户端库,请务必将端点 API 版本配置为使用客户端中固定的相同 API 版本。否则,您可能无法反序列化事件对象。
从 API 中检索事件对象时,您不能控制 data.object
结构的 API 版本。而应从适当的 API 端点检索该对象,并使用 Stripe-Version
头来指定 API 版本。
API 请求事件
当 API 请求导致生成事件时,该请求显示为 request.id
。如果您在发出请求时使用了 idempotency_key
,它将作为 request.idempotency_key
包含在内。在调查导致事件的原因时,请检查此 request
散列。
数据对象和先前属性
对于 *.updated
事件,事件有效负载包括 data.previous_attributes
,它允许您检查 Stripe 对象所发生的变化。上例 customer.subscription.updated
事件中的 previous_attributes
说明,除了其他变化外,订阅具有 status: trialing
先前的值。data.object
表示状态为 active
,这表示订阅已结束试用期。
等待发送
用 pending_webhooks
来确定为此事件配置的端点中有多少没有成功响应发送请求。最初发送时,该值为 1 或更高,原因是您的端点没有成功响应。如果您稍后需要再检索此事件,那么随着每个端点成功响应,pending_webhooks
将降到最小值 0。这对于 invoice.created
事件非常重要,因为发送不成功可能会延迟账单的最终确定。
Connect 子账户事件
从 Connect 子账户发送到 Connect 端点的事件包含 account
。使用 account
来跟踪对象所属的 Connect 子账户,以确保您的平台可以适当地处理事件数据。
为什么会生成事件对象
下表描述了触发生成事件对象的不同场景。
Source | 触发器 |
---|---|
管理平台 | 当您通过在 Stripe 管理平台中修改 Stripe 资源来调用 API 时。 |
API | 当应用程序或网站中的用户操作导致 API 调用时。 |
API | 当您使用 Stripe CLI 手动触发事件时。 |
API | 当您用 Stripe CLI 直接调用 API 时。 |
开始
要开始在您的应用程序中接收 Webhook 事件,请按照以下步骤创建并注册 Webhook 端点:
- 创建一个 Webhook 端点处理器来接收事件数据的 POST 请求。
- 使用 Stripe CLI 在本地测试您的 Webhook 端点处理器。
- 通过管理平台或 API 在 Stripe 中注册您的端点。
- 保护您的 Webhook 端点。
您可以注册并创建一个端点,用它同时处理几个不同的事件类型,也可以为特定事件设置单独的端点。
创建处理器
设置一个 HTTP 或 HTTPS 端点函数,该函数可以用 POST 方法接受 Webhook 请求。如果您仍在您的本地机器上开发您的端点,则它可以使用 HTTP。可公开访问后,您的 Webhook 端点函数必须使用 HTTPS。
设置您的端点函数,以便它:
- 使用由事件对象组成的 JSON 有效负载处理 POST 请求。
- 在执行任何可能导致超时的复杂逻辑之前,快速返回一个成功状态码 (
2xx
)。例如,您必须返回一个200
响应,然后才能在您的会计系统中将客户的账单更新为已支付。
备注
或者,您可以利用我们的交互式 Webhook 端点构建器,以您的编程语言构建一个 Webhook 端点功能。
示例端点
这个代码片段是一个 Webhook 函数,配置它的目的有三:一是检查事件类型是否可被接收,二是处理事件,三是返回 200 响应。
测试您的处理器
在您使用 Webhook 端点功能之前,我们建议您测试您的应用程序集成。方法是配置本地侦听器,以此将事件发送到您的本地机器,并发送测试事件。测试时,您需要使用 CLI。
将事件转发到本地端点
要将事件转发到本地端点,请使用 CLI 运行以下命令来设置本地侦听器。在测试模式下,--forward-to
会将所有的 Stripe 事件发送到您本地的 Webhook 端点。
stripe listen --forward-to localhost:4242/stripe_webhooks
备注
您还可以在 Stripe Shell 上运行 Stripe 侦听命令,通过 Stripe Shell 终端查看事件——尽管您无法将事件从 Shell 转发到本地端点。
有些配置有助于用本地侦听器进行测试,这些配置包括:
- 要禁用 HTTPS 证书验证,使用
--skip-verify
可选标志。 - 仅转发特定事件时,使用
--events
可选标志,并传入事件列表,用逗号分隔。
stripe listen --events payment_intent.created,customer.created,payment_intent.succeeded,checkout.session.completed,payment_intent.payment_failed \ --forward-to localhost:4242/webhook
- 要将事件从已经在 Stripe 上注册的公共 Webhook 端点转发到本地 Webhook 端点,请使用
--load-from-webhooks-api
可选标志。它会加载您注册的端点,解析路径及其注册的事件,然后将路径附加到您本地的 Webhook 端点的--forward-to path
路径中。
stripe listen --load-from-webhooks-api --forward-to localhost:5000
- 要检查 Webhook 签名,请使用侦听 (listen) 命令初始输出中的
{{WEBHOOK_SIGNING_SECRET}}
。
Ready! Your webhook signing secret is '{{WEBHOOK_SIGNING_SECRET}}' (^C to quit)
触发测试事件
要发送测试事件,请通过 Stripe 管理平台手动创建对象来触发事件目的地订阅的事件类型。您也可以在 Stripe Shell 或 Stripe CLI 中使用以下命令。
此示例触发一个 payment_intent.succeeded
事件:
stripe trigger payment_intent.succeeded Running fixture for: payment_intent Trigger succeeded! Check dashboard for event details.
备注
了解如何用 Stripe for VS Code 触发事件。
在 Stripe 中注册您的端点
测试完 Webhook 端点功能后,通过开发人员管理平台或 API 中的 Webhook 部分注册 Webhook 端点可访问的 URL,以便 Stripe 知道在哪里发送事件。您最多可以在 Stripe 上注册 16 个 Webhook 端点。注册的 Webhook 端点必须是可公开访问的 HTTPS URL。
Webhook URL 格式
注册 Webhook 端点时使用的 URL 格式:
https://<your-website>/<your-webhook-endpoint>
例如,如果您的域名是 https://mycompanysite.com
,您的 Webhook 端点的路径为 @app.route('/stripe_webhooks', methods=['POST'])
,那便指定 https://mycompanysite.com/stripe_webhooks
作为端点 URL。
添加一个 Webhook 端点
备注
如果您在账户中启用了工作台,您需要使用工作台注册 Webhook 端点。
Stripe 支持两种端点类型:Account 和 Connect。为 Account 创建端点,除非您已经创建了 Connect 应用程序。通过以下步骤在开发人员管理平台内注册 Webhook 端点。您最多可以在每个 Stripe 账户上注册 16 个 Webhook 端点。
- 导航到 Webhook 页面。
- 点击添加端点。
- 在端点 URL 中添加您的 Webhook 端点的 HTTPS URL。
- 如果您有 Stripe Connect 账户,则输入描述,然后点击侦听 Connect 子账户上的事件。
- 在选择事件中选择您目前在您的本地 Webhook 中接收的事件类型。
- 点击添加端点。
用 Stripe API 注册 Webhook 端点
您也可以通过编程方式创建 Webhook 端点。
要接收来自 Connect 子账户的事件,请使用 Connect 参数。
下面的示例为创建一个端点,在收款成功或失败时给您发送通知。
保护您的端点
强烈建议您通过确保您的处理器验证所有 Webhook 请求都是由 Stripe 生成的来保护您的集成应用。您可以选择使用我们的官方库来验证 Webhook 签名或手动验证它们。
调试 Webhook 集成
向 Webhook 端点发送事件时,可能会出现多种问题:
- Stripe 可能无法将事件发送到您的 Webhook 端点。
- 您的 Webhook 端点可能存在 SSL 问题。
- 您的网络连接时断时续。
- 您的 Webhook 端点没有接收到您期望接收的事件。
查看事件的发送情况
备注
如果您在账户中启用了工作台,那么您需要用工作台管理活动的发送。
要查看特定端点的事件发送情况,请在 Webhook 选项卡中选择 Webhook 端点。
要查看您的账户中触发的所有事件,请查看事件选项卡。
修复 HTTP 状态代码
当一个事件显示状态代码 200
时,它表示已成功地发送到 Webhook 端点。您可能还会收到一个不同于 200
的状态代码。有关常见 HTTP 状态代码和推荐解决方案的列表,请查看下表。
待处理的 Webhook 状态 | 描述 | 修复 |
---|---|---|
(无法连接)错误 | 我们无法建立到目标服务器的连接。 | 确保您的主机域名可以公开访问互联网。 |
(302 ) 错误(或其他 3xx 状态) | 目标服务器尝试将请求重定向到另一个位置。这种情况,我们认为对 Webhook 请求的重定向响应是失败的。 | 将 Webhook 端点目的地设置为重定向解析的 URL。 |
(400 ) 错误(或其他 4xx 状态) | 目标服务器不能或不会处理请求。当服务器检测到错误 (400 )、目标 URL 有访问限制 (401 , 403 ) 或目标 URL 不存在 (404 ) 时,可能会发生这种情况。 |
|
(500 ) 错误(或其他 5xx 状态) | 目标服务器在处理请求时遇到了错误。 | 查看应用程序的日志,了解它为什么返回 500 错误。 |
(TLS 错误)ERR | 我们无法与目标服务器建立安全连接。这些错误通常是由目标服务器的证书链中的 SSL/TLS 证书或中间证书有问题而引起的。 | 执行 SSL 服务器测试,找出可能导致此错误的问题。 |
(超时) ERR | 目标服务器响应 Webhook 请求的时间过长。 | 务必要在您的 Webhook 处理代码中延迟复杂的逻辑并立即返回成功的响应。 |
事件的发送行为
本节旨在帮助您理解 Stripe 向 Webhook 端点发送事件时的不同行为。
重试行为
在真实模式下,Stripe 会连续 3 天一直尝试向您的 Webhook 发送特定事件,但尝试频率递减。您可以在管理平台的事件部分查看下次重试时间。
在测试模式下,Stripe 会在几个小时内重试三次。之后,您可以使用管理平台的事件部分手动重试将单个事件传输到 Webhook 端点。您还可以查询错过的事件来协调任何时间段的数据。
即使您重新手动尝试向给定端点提交单个 Webhook 事件并且尝试成功,自动重试仍会继续。
如果 Stripe 在尝试重试时,您的端点已被禁用或删除,那么就会阻止进一步尝试该事件。但是,如果您在 Stripe 重试之前禁用并又重新启用了某个 Webhook 端点,那仍可看到后续的重试尝试。
禁用行为
在真实和测试模式下,如果某个端点连续数天没有响应 2xx
HTTP 状态码,则 Stripe 会尝试给您发送邮件通知,告知该端点配置错误。邮件中还会告知何时将自动禁用这个端点。
API 版本
当事件发生时,您的账户设置中的 API 版本,因此会表明在 Webhook 中发送的 Event
对象的结构。例如,如果您的账户设置为旧的 API 版本,如 2015-02-16,并且您通过版本控制更改了特定请求的 API 版本,则生成并发送到您的端点的 Event
对象仍然是基于 2015-02-16 这个旧的 API 版本。
Event
对象创建后不能更改。例如,如果您更新某笔收款,则原始收款事件保持不变。这意味着对您账户的 API 版本的后续更新不会追溯性地更改当前的 Event
对象。通过旧版本的 API 调用 /v1/events
来获取旧的事件对收到的事件的结构也没有影响。
您可以将测试 Webhook 端点设置到默认的 API 版本或最新的 API 版本。发送到 Webhook URL的 Event
是为端点的特定版本构建的。您还可以通过编程方式创建具有特定 api_version 的端点。
事件排序
Stripe 不保证能够按事件生成的顺序来发送事件。例如,创建订阅时可能会生成以下事件:
customer.subscription.created
invoice.created
invoice.paid
charge.created
(如果有收款)
您的端点不应期望上述事件按照这个顺序发送,而是应该来一个处理一个。您也可以用 API 来获取任何丢失的对象(例如,您可以使用来自 invoice.paid
的信息获取账单、收款及订阅对象——如果您恰好是先收到的这个事件的话)。
Webhook 用法最佳实践
查看这些最佳做法,时刻确保您的 Webhook 安全,并与您的集成应用良好运行。
处理重复事件
Webhook 端点可能偶尔会多次收到同一个事件。您可以将事件处理方式作幂等处理,防止重复收到事件。一种方法是记录您已处理的事件,然后不再处理它们。
仅侦听集成所需的事件类型
将 Webhook 端点配置为仅接收集成应用所需的事件类型。侦听额外的事件(或所有事件)会给您的服务器带来过度的压力,因此不建议这样做。
您可以在管理平台或通过 API 更改事件(Webhook 端点收到的事件)。
异步处理事件
配置您的处理器来处理带有异步队列的传入事件。如果选择同步处理事件,可能会遇到扩展性问题。Webhook 发送量的任何大峰值(例如,在所有订阅都续订的月初)都可能会使您的端点主机不堪重负。
异步队列允许您以系统支持的速度处理并发事件。
去除 Webhook 路由的 CSRF 保护
如果您使用着 Rails、Django 或其他网络框架,那么您的站点可能会自动检查每个 POST 请求是否包含一个_CSRF 令牌_。这是一个重要的安全功能,有助于保护您及您的用户免受跨站请求伪造 (cross-site request forgery, CSRF) 攻击。但是,这一安全措施也可能会阻止您的站点处理合法事件。如果是这样,那么您可能需要从 CSRF 保护中去除 Webhook 路由。
通过 HTTPS 服务器接收事件
如果您为您的 Webhook 端点使用了 HTTPS 网址,那么 Stripe 会在发送您的 Webhook 数据之前先验证到您的服务器的连接是否安全。为此,您的服务器必须要正确配置,具有支持 HTTPS 的有效服务器证书。真实模式要求有 HTTPS URL。Stripe Webhook 目前不支持 TLS v1.3。
定期滚动端点签名私钥
用来验证事件来自 Stripe 的私钥可在管理平台的 Webhook 部分来修改。对于每个端点,点击滚动私钥。您可以选择立即使当前私钥过期,也可以延迟 24 小时后再让它过期,以便让自己有时间更新服务器上的验证码。这段时间内,端点会有多个私钥处于活动状态。Stripe 会为每个私钥生成一个签名,直到过期。为了保证它们的安全,建议您定期或在怀疑私钥泄露时滚动它们。
验证事件是否是从 Stripe 发送的
Stripe 会从一组固定的 IP 地址发送 Webhook 事件。仅信任来自这些 IP 地址的事件。
此外,验证 Webhook 签名以确认收到的事件是从 Stripe 发送的。Stripe 通过在每个事件的 Stripe-Signature
头中包含一个签名来对它发送到您的端点的 Webhook 事件进行签名。这样可表示事件是由 Stripe 发送的,而非第三方。可以用我们的官方库来验证签名,也可以用您自己的方案手动验证。
以下部分描述了 Webhook 签名的验证方式:
- 检索您的端点的私钥。
- 验证签名。
检索您的端点的私钥
使用管理平台的 Webhook 部分。选择要获取其私钥的端点,并在页面的右上角找到此私钥。
Stripe 为每个端点生成一个唯一私钥。如果您为测试和真实 API 密钥使用相同的端点,那么每个端点的密钥各不相同。此外,如果您使用多个端点,则必须要为您想用来验证签名的每个端点都获取一个私钥,然后 Stripe 会开始签署它发送到端点的每个 Webhook。
防止重放攻击
重放攻击 (Replay Attack)是攻击者截获有效的有效载荷及其签名,然后再重新传输。为了减轻这类攻击,Stripe 在 Stripe-Signature
头内包含了时间戳。因为这个时间戳是签名有效载荷的一部分,因此它也由签名验证,因此攻击者在不使签名无效的情况下不能更改时间戳。如果签名有效,但时间戳太老,那么您可以让您的应用程序拒绝有效载荷。
我们的库在时间戳和当前时间之间有 5 分钟的默认容差。您可以通过在验证签名时提供附加参数来更改这个容差。使用网络时间协议(Network Time Protocol,简称NTP),确保您的服务器时钟的准确性,并与 Stripe 的服务器时间同步。
每当向您的端点发送事件时,Stripe 都会生成时间戳和签名。如果 Stripe 重试一个事件(例如,您的端点之前回复了一个非 2xx
的状态码),则我们会为新的发送尝试生成新的签名和时间戳。
快速返回 2xx 响应
您的端点必须要快速返回一个成功的状态码 (2xx
),然后才能执行任何可能导致超时的复杂逻辑。例如,您必须返回一个 200
响应,然后才能在您的会计系统中将客户的账单更新为已支付。