跳转到内容

输入关键词开始搜索文档。

Stripe

最后更新 查看 Markdown 源文件@flue/stripe

快速开始

使用 Stripe 蓝图为已有的 Flue 项目添加已验证的 webhook 入口和应用自有的 API 行为。在终端或你选择的编码智能体中运行以下命令:

flue add channel stripe

概述

该蓝图安装 @flue/stripe、Stripe 官方的 stripe SDK 以及所需的 TypeScript 对等依赖(如有需要)。它在 <source-root>/channels/stripe.ts 创建文件,其中命名的 channel 导出默认验证快照 webhook 事件,项目自有的 client 处理出站 API 调用。根据应用调整所选事件、智能体和工具。

src/channels/stripe.ts(简略版)
import Stripe from 'stripe';
import { createStripeChannel } from '@flue/stripe';
import { dispatch, useModel } from '@flue/runtime';
import { Billing } from '../agents/billing.ts';

export const client = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  httpClient: Stripe.createFetchHttpClient(),
});

export const channel = createStripeChannel({
  client,
  webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
  async webhook({ event }) {
    if (event.type !== 'checkout.session.completed') return;
    const session = event.data.object;
    const customerId =
      typeof session.customer === 'string' ? session.customer : session.customer?.id;
    if (!customerId) return;

    await dispatch(Billing, {
      id: customerId,
      message: {
        kind: 'signal',
        type: `stripe.${event.type}`,
        body: `Checkout session ${session.id} reported payment status ${session.payment_status}.`,
        attributes: {
          eventId: event.id,
          customerId,
          sessionId: session.id,
          paymentStatus: session.payment_status,
          ...(session.amount_total === null ? {} : { amountTotal: String(session.amount_total) }),
          ...(session.currency === null ? {} : { currency: session.currency }),
        },
      },
    });
  },
});

匹配的事件被接受到由其 Stripe 客户标识的计费智能体。其他事件收到空的成功响应。生成的模块还定义了一个客户绑定的检索工具;蓝图将该工具连接到计费智能体。对于 Cloudflare 目标,相同的 SDK 使用其 Fetch 和 Web Crypto 实现。

挂载渠道

渠道仅在 app.ts 挂载它的地方提供 HTTP 路由。挂载模块的命名 channel 导出:

src/app.ts
import { channel as stripe } from './channels/stripe.ts';

app.route('/channels/stripe', stripe.route());

channel.route() 是一个纯路由器工厂,相对于挂载路径提供渠道声明的路由。本指南中的 webhook 路径假定使用常规的 /channels/stripe 挂载路径;不同的挂载路径会相应调整。分发目标智能体模块携带 'use agent' 指令——该指令会注册它,因此仅用于分发的智能体不需要自己的 HTTP 挂载。

配置

变量用途
STRIPE_WEBHOOK_SECRET必需 — 验证入站交付。
STRIPE_SECRET_KEY必需 — 验证出站 SDK 调用。

它安装 @flue/stripe 和 Stripe 官方的 stripe SDK。SDK 验证入站 payload,并作为项目自有的客户端处理出站 API 调用。蓝图创建 src/channels/stripe.ts,包含命名的 channel 和 client 导出。

将 Stripe 事件目标配置为:

https://example.com/channels/stripe/webhook

如果 flue() 挂载在外层前缀之下,请包含该前缀。仅订阅应用处理的事件类型。将两个凭据保存在项目现有的密钥系统中。

渠道模块

快照事件是默认的:

src/channels/stripe.ts
import Stripe from 'stripe';
import { createStripeChannel } from '@flue/stripe';
import { defineTool, dispatch, useModel } from '@flue/runtime';
import { Billing } from '../agents/billing.ts';

export const client = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  httpClient: Stripe.createFetchHttpClient(),
});

export const channel = createStripeChannel({
  client,
  webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,

  // 路径:/channels/stripe/webhook
  async webhook({ event }) {
    switch (event.type) {
      case 'checkout.session.completed':
      case 'checkout.session.async_payment_succeeded': {
        const session = event.data.object;
        const customerId =
          typeof session.customer === 'string' ? session.customer : session.customer?.id;
        if (!customerId) return;

        await dispatch(Billing, {
          id: customerId,
          message: {
            kind: 'signal',
            type: `stripe.${event.type}`,
            body: `Checkout session ${session.id} reported payment status ${session.payment_status}.`,
            attributes: {
              eventId: event.id,
              customerId,
              sessionId: session.id,
              paymentStatus: session.payment_status,
              ...(session.amount_total === null
                ? {}
                : { amountTotal: String(session.amount_total) }),
              ...(session.currency === null ? {} : { currency: session.currency }),
            },
          },
        });
        return;
      }
      default:
        return;
    }
  },
});

export function retrieveCustomer(customerId: string) {
  return defineTool({
    name: 'retrieve_stripe_customer',
    description: '检索绑定到此计费智能体的 Stripe 客户。',
    async run() {
      const customer = await client.customers.retrieve(customerId);
      return {
        output:
          'deleted' in customer
            ? { id: customer.id, deleted: true }
            : { id: customer.id, name: customer.name, email: customer.email },
      };
    },
  });
}

@flue/stripe 在调用 webhook 之前将精确的请求字节和 Stripe-Signature 头提供给 Stripe 的 SDK。不返回任何内容会产生一个空的 200 响应。兼容 JSON 的值会变成响应体,普通的 Hono 或 Fetch Response 会原样传递。

该示例使用客户 ID 作为单个 Stripe 账户的智能体实例 ID。Stripe 没有通用的对话标识。选择代表应用工作单元的客户、订阅、账户、Checkout Session 或其他资源。当资源命名空间要求时,Connect 和组织目标应包含已验证的 event.account 或 event.context。

绑定工具

src/agents/billing.ts
'use agent';
import { type AgentProps, useModel, useTool } from '@flue/runtime';
import { retrieveCustomer } from '../channels/stripe.ts';

export function Billing({ id: customerId }: AgentProps) {
  useModel('anthropic/claude-haiku-4-5');
  useTool(retrieveCustomer(customerId));
  return 'Review the completed Checkout event and summarize any billing follow-up that is needed.';
}

模型可以调用查找但不能选择另一个客户、账户或凭据。受信任的应用代码绑定这些值。渠道 - 智能体导入循环是受支持的,因为两个导入的绑定在延迟回调或智能体函数体内都是只读的。

精简事件通知

仅当事件目标配置为发送 Stripe 精简事件通知时,设置 eventPayload: 'thin':

export const channel = createStripeChannel({
  client,
  webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
  eventPayload: 'thin',

  // 路径:/channels/stripe/webhook
  async webhook({ event }) {
    const relatedObject = await event.fetchRelatedObject();
    await handleRelatedObject(event, relatedObject);
  },
});

回调接收 Stripe 原生的 Stripe.V2.Core.EventNotification。其 fetchEvent() 和 fetchRelatedObject() 方法使用项目自有的客户端并保留 Stripe 上下文。快照和精简目标使用不同的签名 payload 格式;包会拒绝与配置模式不匹配的 payload。

交付行为

Stripe 在最多三天内重试失败的实时模式 webhook 交付,在几小时内重试沙箱交付三次。排序不保证且可能重复交付。当不允许重复入站时,在分发之前在应用自有的持久存储中声明 event.id。业务操作应保持幂等,因为单独的 Event 对象可能描述相同的资源变更。

快照事件对象绑定到事件目标选择的 API 版本。保持该版本与已安装的 SDK 类型一致,或在应用代码中缩小和验证资源字段。

Flue 转发比已安装 Stripe 声明更新的已验证事件类型。在项目升级 Stripe 之前,使用 switch (event.type as string) 来观察该未来类型,并将其资源字段视为不受信任,而不是削弱每个已知事件的原生缩小。

官方 Stripe SDK 在 Cloudflare Workers 中选择其 Fetch 和 Web Crypto 实现。该示例在 workerd 中使用 Flue 所需的 nodejs_compat 配置执行该路径。项目可以通过 process.env 或类型化的 Worker 绑定初始化凭据,但仍应验证其完整的目标构建和 workerd 测试。Stripe 的声明引用了 @types/node;该包仅是类型依赖,不会向 Worker 包添加 Node 代码。

渠道不注册事件目标、不轮换签名密钥、不管理 OAuth 或 API 密钥、不去重事件、不恢复排序,也不定义通用 Stripe 工具。它也不声明支持专门的延迟敏感工作流,如同步实时 Issuing 授权决策。

参见 @flue/stripe README。