【问题标题】:With Stripe API, How To Get session_id of Checkout Session That Created a payment_intent Object, From payment_intent.succeeded Webhook使用 Stripe API,如何从 payment_intent.succeeded Webhook 获取创建 payment_intent 对象的结帐会话的 session_id
【发布时间】:2021-12-22 14:10:44
【问题描述】:

我正在开发和测试一个用 PHP 编写的 Stripe 集成,它运行良好。我可以创建会话,重定向到结帐表单,当付款完成时,它会向我的 webhook 脚本发送一个事件,该脚本成功处理有关付款的信息。

当我创建会话时,我将在我的网站上填写的表单的数据存储在数据库中,当付款通过时,我将信息存储在不同的表中,这很棒。

我遇到的问题是我不知道如何将有关成功付款的信息与生成它的会话联系起来。

关联这些数据对我来说很重要,因为我想跟踪哪些会话实际上导致了成功的支付,这样我就可以分析用户界面的流程并跟踪转化率并分析导致放弃结帐的因素会话。

在某些情况下,很容易将这些东西联系起来。例如,如果在给定的时间范围内只生成一个会话和一个成功的付款,与给定的电子邮件相关联,我可以将它们链接起来。问题是我希望能够处理一个人创建多个会话并放弃它们的(可能常见的)场景。在这种情况下,我无法将付款链接到与电子邮件关联的最新会话,因为单个客户可能会创建两个会话,但在第一个早期创建的会话中完成付款。

我不知道如何从返回到我的 webhook 的 payment_intent 对象中访问 session_id。我对如何解决这个问题的一些想法包括:

  • 侦听我的 webhook 脚本中发生的其他事件,这可能允许我链接两条记录。
  • 将元数据传递给会话,例如唯一生成的 ID,然后从 payment_intent 对象访问相同的元数据。但是,我无法通过阅读 Stripe 文档来弄清楚元数据是如何工作的,即使元数据从会话传递到 payment_intent 对象(文档没有明确说明或解释它,而且 session_id 没有传递的事实让我想知道元数据是否会被传递)。我不想做这个解决方案,因为它需要在生成会话之前生成唯一 ID 的额外步骤,这将需要我做更多的工作,也会使我的代码更复杂并涉及更多数据库调用和更多可能出错的潜在步骤(目前我正在生成会话,然后存储信息以响应会话的成功创建),但如果真的没有更好的选择,我可以容忍它。

我想在这里遵循“最佳实践”,但我不清楚 Stripe 打算如何让人们链接或访问数据,或者这可能是他们的疏忽。

如果你给我示例代码,如果可能的话,我更愿意在 PHP 中看到它,但你根本不需要给我看任何代码;只需给我一个关于如何完成此任务的抽象或一般概念就足够了,我可以自己想出编码细节。

【问题讨论】:

  • 您的元数据属性是正确的。当您获得 webhook 时,使用 用户 ID/订单 ID 链接备份。我对订阅做了类似的事情。这是关于元数据的文档,基本上只是一个数组..stripe.com/docs/payments/…
  • @Bossman 当我在创建会话对象时将元数据传递给它,即在调用 \Stripe\Checkout\Session::create() 时将其作为数组中的条目输入时,相应的 payment_intent 对象返回空元数据。所以看起来这种方法行不通。我想知道我是否需要在这里收听另一个事件,也许是checkout.session.completed。我想接下来我会尝试这条途径。
  • 你可以试试client_reference_id。这是您可以使用的另一个可选属性。进一步研究它,我认为元数据不会与会话对象一起保存,即使它在文档中作为属性。
  • 因此,尽管我想出了另一个解决方案,使用 webhook 监听 checkout.session.completed 事件,并且因为我更喜欢它而使用它,但对它进行更多研究,它也可以使用元数据完成,但关键是使用参数payment_intent_data.metadata,因为只有这个被传递给payment_intent 对象。我在第一次尝试时错过了这一点,因为我在会话对象中看到了 metadata 字段,它具有误导性。 Stripe 可以改进他们的文档;会话的 API 文档中未提及传递给会话的参数。
  • 取而代之的是这个单独的页面(我只是通过网络搜索找到的,不确定它是否或如何在文档内部链接到),它解释了:support.stripe.com/questions/…

标签: php stripe-payments checkout


【解决方案1】:

payment_intent.succeeded 事件为您提供 PaymentIntent ID。您可以使用 CheckoutSessions“列表”端点 [0] 通过传递 payment_method 参数来获取使用该 PaymentIntent ID 的 CheckoutSession。

[0]https://stripe.com/docs/api/checkout/sessions/list#list_checkout_sessions-payment_intent

【讨论】:

  • 这是一个很好的解决方案并且有效,但我最终更喜欢我提出的另一个解决方案,使用 webhook 处理 checkout.session.completed 事件,然后从会话对象中获取 PaymentIntent ID,因为这种方法使用少了一次 API 调用,而 API 调用通常是我脚本中的限速因素。
【解决方案2】:

Stripe 数据的结构方式是 Session 对象有一个字段 payment_intent ,其中包含 payment_intent 对象的 id。最初,在创建会话时,此字段为空或 null,但在执行付款时,它会被填充。 payment_intent 对象不包含链接它们的任何相关字段,部分原因是payment_intent 可以通过许多不同的方法生成,而不仅仅是结帐会话。所以需要用到Session对象,但是需要在会话完成后才能访问。

因此,我能够通过设置一个 webhook 来监听 checkout.session.completed 事件来达到预期的结果,因为当该事件触发时,该字段已被填充并指代已成功完成的付款,并且该事件返回包含相关字段的会话对象。 payment_intent.succeeded 事件的 webhook 不太有用,因为它只返回 payment_intent 对象,如果没有额外的 API 调用,就无法从中访问相关信息。 @hmunoz 的解决方案提供了一种方法来做到这一点,但我更喜欢我的解决方案,因为它避免了这种额外的 API 调用。由于 API 调用依赖于网络访问,它们通常是我的脚本中最慢的一步,并且最容易出错,因此我更倾向于将它们最小化的解决方案。

一旦我检索到与会话对应的 payment_intent 对象的 Stripe ID,然后我会更新与会话对应的数据库中的条目,以包含 Stripe 的 payment_intent ID,这样就可以加入我数据库中的数据.

与使用元数据相比,我更喜欢这种解决方案,因为它不需要传递任何元数据。可能有一种方法可以使用元数据来获得类似的结果,使用我自己的内部生成的 ID,但我无法让它工作,因为似乎 Stripe 只是丢弃了我传递的元数据。也许我做的不对,但是在我能够让基于元数据的解决方案正常工作之前,我就让这个解决方案工作了。

关于 ID 的注意事项:切换到本地想法是有益的,但很棘手

有一点需要注意或注意,因为我有一个处理 payment_intent.succeeded 事件的 webhook(因为它可以通过结帐会话以外的东西生成)并使用它从 payment_intent 对象中输入一些详细信息,包括它的ID,到本地数据库中,您无法保证事件将按什么顺序触发。因此,如果您希望链接本地数据库中与结帐会话对象和 payment_intent 对象相对应的表,您最终可能会在会话表中保存一个 payment_intent 的 ID,之前该 payment_intent 的对应行已输入到 payment_intents 表中。

因此,我需要在每个事件的事件处理中写入一个条件,以检查该行是否存在(对应于首先处理的事件。)如果 checkout.session.completed 首先触发,我把Stripe 在 session 条目中的 payment_intent 的 ID,然后,当 payment_intent.succeeded 触发时,我不仅添加了 payment_intent 对象,而且我用我的本地 ID 为 payment_intent 更新了会话的行,它是一个整数,允许更多快速且计算强度较低的连接。

另一方面,如果 payment_intent.success 首先触发,那么当 checkout.session.completed 触发时,我会在数据库中检索适当的本地 ID,参考已完成的付款,并将其放入本地表中会话。

我强烈建议这样做,尽管它需要更多的工作,因为 Stripe 的 ID 是长度有些随意的长字符串(即,根据他们的文档,他们保留延长它们的权利),这意味着你需要一个相当长的在文本字段上建立索引以获得良好的连接性能,这是我想避免的。为每个表转换为您自己的本地整数 ID 可以让您以更好的性能和更少的服务器负载在本地加入它们。相对于您将加入此数据的时间而言,事件处理相对较少,这既是因为客户查看他们自己的数据,也是因为您像我一样想要查看和分析您的数据。

【讨论】:

    猜你喜欢
    • 2021-06-24
    • 2022-01-05
    • 2021-12-16
    • 2020-11-26
    • 2021-04-01
    • 2020-09-26
    • 2022-01-01
    • 2021-12-24
    • 2021-03-30
    相关资源
    最近更新 更多