Autumn Billing

Autumn 是一个开源基础设施,用于管理 SaaS 定价方案。它位于你的应用和 Stripe 之间,充当客户订阅状态、使用量计量和功能权限的数据库。

此插件由 Autumn 团队维护。如遇到漏洞、问题或功能请求,请访问 Autumn GitHub 仓库

Get help on Autumn's Discord

我们在线为你解答任何问题。

特性

【Features】

  • 一个功能即可处理所有结账、订阅和支付流程
  • 无需网络钩子:向 Autumn 查询你需要的数据
  • 管理你的应用的免费和付费计划
  • 用于使用计费和周期性限制的使用跟踪
  • 通过Autumn的仪表板自定义计划和定价变更

设置 Autumn 账户

首先,在 Autumn 的控制面板中创建你的定价计划,在那里你可以定义每个计划和产品的访问权限以及计费方式。在这个示例中,我们处理 AI 聊天机器人的免费和专业计划,每个月附带一定数量的 messages

安装 Autumn SDK

npm install autumn-js

If you're using a separate client and server setup, make sure to install the plugin in both parts of your project.

AUTUMN_SECRET_KEY 添加到你的环境变量中

你可以在 Autumn 的仪表板中找到它,路径为“开发者”。

.env
AUTUMN_SECRET_KEY=am_sk_xxxxxxxxxx

将 Autumn 插件添加到你的 auth 配置中

auth.ts
import { autumn } from "autumn-js/better-auth";

export const auth = betterAuth({
  // ...
  plugins: [autumn()],
});
auth.ts
import { autumn } from "autumn-js/better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  // ...
  plugins: [organization(), autumn({ customerScope: "organization" })],
});
auth.ts
import { autumn } from "autumn-js/better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  // ...
  plugins: [
    organization(),
    autumn({ customerScope: "user_and_organization" })
  ],
});
auth.ts
import { autumn } from "autumn-js/better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  // ...
  plugins: [
    organization(),
    autumn({
      identify: async ({ session, organization }) => {
        return {
          customerId: "your_customer_id",
          customerData: {
            name: "Customer Name",
            email: "customer@gmail.com",
          },
        };
      },
    }),
  ],
});

当客户注册时,Autumn 会自动创建他们的账户,并分配你创建的任何默认计划(例如你的免费计划)。你可以选择谁将成为客户:个人用户、组织、两者,或自定义选项,如工作区。

添加 <AutumnProvider />

在客户端,用 AutumnProvider 组件封装你的应用,并传入你在 better-auth 的 authClient 中定义的 baseUrl

app/layout.tsx
import { AutumnProvider } from "autumn-js/react";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        {/* or meta.env.BETTER_AUTH_URL for vite */}
        <AutumnProvider betterAuthUrl={process.env.NEXT_PUBLIC_BETTER_AUTH_URL}>
          {children}
        </AutumnProvider>
      </body>
    </html>
  );
}

用法

【Usage】

处理付款

【Handle payments】

当客户想购买专业版时,调用 attach 将他们重定向到 Stripe 结账页面。

【Call attach to redirect the customer to a Stripe checkout page when they want to purchase the Pro plan.】

如果他们的支付方式已经存档,AttachDialog 将会打开,以便客户确认他们的新订阅或购买,并处理付款。

【If their payment method is already on file, AttachDialog will open instead to let the customer confirm their new subscription or purchase, and handle the payment.】

请确保你已将你的 Stripe 测试密钥 粘贴到 Autumn 仪表板 中。

import { useCustomer, AttachDialog } from "autumn-js/react";

export default function PurchaseButton() {
  const { attach } = useCustomer();

  return (
    <button
      onClick={async () => {
        await attach({
          productId: "pro",
          dialog: AttachDialog,
        });
      }}
    >
      Upgrade to Pro
    </button>
  );
}

AttachDialog 组件可以直接从 autumn-js/react 库中使用(如上例所示),也可以下载为 shadcn/ui 组件 进行自定义。

【The AttachDialog component can be used directly from the autumn-js/react library (as shown in the example above), or downloaded as a shadcn/ui component to customize.】

集成定价逻辑

【Integrate Pricing Logic】

将你的客户端和服务器定价层逻辑与以下功能集成:

【Integrate your client and server pricing tiers logic with the following functions:】

  • check 去查看客户是否为 allowed 以发送消息。
  • 在 Autumn 中“跟踪”一次使用事件(通常在服务器端完成)
  • customer 在你的界面中显示任何相关的账单数据(订阅、功能余额)

在服务器端,你可以通过 auth 对象访问 Autumn 的功能。

【Server-side, you can access Autumn's functions through the auth object.】

import { useCustomer } from "autumn-js/react";

export default function SendChatMessage() {
  const { customer, allowed, refetch } = useCustomer();

  return (
    <>
      <button
        onClick={async () => {
          if (allowed({ featureId: "messages" })) {
            //... send chatbot message server-side, then
            await refetch(); // refetch customer usage data
            alert(
              "Remaining messages: " + customer?.features.messages?.balance
            );
          } else {
            alert("You're out of messages");
          }
        }}
      >
        Send Message
      </button>
    </>
  );
}
import { auth } from "@/lib/auth";

// check on the backend if the customer can send a message
const { allowed } = await auth.api.check({
  headers: await headers(), // pass the request headers
  body: {
    featureId: "messages",
  },
});

// server-side function to send the message

// then track the usage
await auth.api.track({
  headers: await headers(),
  body: {
    featureId: "messages",
    value: 2,
  },
});

附加功能

【Additional Functions】

打开计费门户()

【openBillingPortal()】

打开一个账单门户,客户可以在其中更新付款方式或取消他们的计划。

【Opens a billing portal where the customer can update their payment method or cancel their plan.】

import { useCustomer } from "autumn-js/react";

export default function BillingSettings() {
  const { openBillingPortal } = useCustomer();

  return (
    <button
      onClick={async () => {
        await openBillingPortal({
          returnUrl: "/settings/billing",
        });
      }}
    >
      Manage Billing
    </button>
  );
}

取消()

【cancel()】

取消产品或订阅。

【Cancel a product or subscription.】

import { useCustomer } from "autumn-js/react";

export default function CancelSubscription() {
  const { cancel } = useCustomer();

  return (
    <button
      onClick={async () => {
        await cancel({ productId: "pro" });
      }}
    >
      Cancel Subscription
    </button>
  );
}

获取发票历史

【Get invoice history】

传入 expand 参数到 useCustomer 以获取更多信息。你可以展开 invoicestrials_usedpayment_methodrewards

【Pass in an expand param into useCustomer to get additional information. You can expand invoices, trials_used, payment_method, or rewards.】

import { useCustomer } from "autumn-js/react";

export default function CustomerProfile() {
  const { customer } = useCustomer({ expand: ["invoices"] });

  return (
    <div>
      <h2>Customer Profile</h2>
      <p>Name: {customer?.name}</p>
      <p>Email: {customer?.email}</p>
      <p>Balance: {customer?.features.chat_messages?.balance}</p>
    </div>
  );
}

On this page