Polar

Polar 是一个以开发者为先的支付基础设施。它开箱即用地提供了许多以开发者为先的支付、结账等集成。此插件帮助您将 Polar 与 Better Auth 集成,使您的认证 + 支付流程无缝衔接。

此插件由 Polar 团队维护。对于 bug、问题或功能请求, 请访问 Polar GitHub repo

功能

  • 结账集成
  • 客户门户
  • 注册时自动创建客户
  • 事件摄取和客户计量器,用于灵活的使用量计费
  • 使用签名验证安全处理 Polar Webhook
  • 引用系统,用于将购买与组织关联

安装

pnpm add better-auth @polar-sh/better-auth @polar-sh/sdk

准备工作

转到您的 Polar 组织设置,并创建一个组织访问令牌。将它添加到您的环境变量中。

# .env
POLAR_ACCESS_TOKEN=...

配置 BetterAuth 服务端

Polar 插件附带了一些额外的插件,这些插件为您的技术栈添加功能。

  • Checkout - 启用无缝的结账集成
  • Portal - 使您的客户能够管理他们的订单、订阅和已授予的权益
  • Usage - 用于列出客户计量器并摄取事件以进行使用量计费的简单扩展
  • Webhooks - 监听相关的 Polar webhook
import { betterAuth } from "better-auth";
import { polar, checkout, portal, usage, webhooks } from "@polar-sh/better-auth";
import { Polar } from "@polar-sh/sdk";

const polarClient = new Polar({
    accessToken: process.env.POLAR_ACCESS_TOKEN,
    // 如果您使用 Polar Sandbox 环境,请使用 'sandbox'
    // 请记住,访问令牌、产品等在不同环境之间是完全分开的。
    // 例如,在生产环境中获取的访问令牌无法在 Sandbox 环境中使用。
    server: 'sandbox'
});

const auth = betterAuth({
    // ... Better Auth 配置
    plugins: [
        polar({
            client: polarClient,
            createCustomerOnSignUp: true,
            use: [
                checkout({
                    products: [
                        {
                            productId: "123-456-789", // 来自 Polar 仪表板的产品的 ID
                            slug: "pro" // 用于结账 URL 的自定义 slug,例如 /checkout/pro,便于引用
                        }
                    ],
                    successUrl: "/success?checkout_id={CHECKOUT_ID}",
                    authenticatedUsersOnly: true
                }),
                portal(),
                usage(),
                webhooks({
                    secret: process.env.POLAR_WEBHOOK_SECRET,
                    onCustomerStateChanged: (payload) => // 当客户相关任何内容更改时触发
                    onOrderPaid: (payload) => // 当订单支付时触发(购买、订阅续订等)
                    ...  // 超过 25 个细粒度的 webhook 处理程序
                    onPayload: (payload) => // 捕获所有事件的通用处理程序
                })
            ],
        })
    ]
});

配置 BetterAuth 客户端

您将使用 BetterAuth 客户端与 Polar 功能交互。

import { createAuthClient } from "better-auth/react";
import { polarClient } from "@polar-sh/better-auth";

// 这就是所有需要的内容
// 所有 Polar 插件等应附加到服务端 BetterAuth 配置中
export const authClient = createAuthClient({
  plugins: [polarClient()],
});

配置选项

import { betterAuth } from "better-auth";
import {
  polar,
  checkout,
  portal,
  usage,
  webhooks,
} from "@polar-sh/better-auth";
import { Polar } from "@polar-sh/sdk";

const polarClient = new Polar({
  accessToken: process.env.POLAR_ACCESS_TOKEN,
  // 如果您使用 Polar Sandbox 环境,请使用 'sandbox'
  // 请记住,访问令牌、产品等在不同环境之间是完全分开的。
  // 例如,在生产环境中获取的访问令牌无法在 Sandbox 环境中使用。
  server: "sandbox",
});

const auth = betterAuth({
  // ... Better Auth 配置
  plugins: [
    polar({
      client: polarClient,
      createCustomerOnSignUp: true,
      getCustomerCreateParams: ({ user }, request) => ({
        metadata: {
          myCustomProperty: 123,
        },
      }),
      use: [
        // 这就是您添加 Polar 插件的地方
      ],
    }),
  ],
});

必需选项

  • client: Polar SDK 客户端实例

可选选项

  • createCustomerOnSignUp: 当用户注册时自动创建 Polar 客户
  • getCustomerCreateParams: 自定义函数,用于提供额外的客户创建元数据

客户

启用 createCustomerOnSignUp 时,当 Better-Auth 数据库中添加新用户时,会自动创建新的 Polar 客户。

所有新客户都将与关联的 externalId 创建,该 ID 是您数据库中用户的 ID。这允许我们跳过任何 Polar 到用户数据库的映射。

Checkout 插件

要在您的应用中支持结账,只需将 Checkout 插件传递到 use 属性。

import { polar, checkout } from "@polar-sh/better-auth";

const auth = betterAuth({
    // ... Better Auth 配置
    plugins: [
        polar({
            ...
            use: [
                checkout({
                    // 可选字段 - 将使其可能传递 slug 到结账而不是产品 ID
                    products: [ { productId: "123-456-789", slug: "pro" } ],
                    // 结账成功完成后返回的相对 URL
                    successUrl: "/success?checkout_id={CHECKOUT_ID}",
                    // 是否允许未经认证的结账会话
                    authenticatedUsersOnly: true
                })
            ],
        })
    ]
});

启用结账后,您可以使用 BetterAuth 客户端上的 checkout 方法初始化 Checkout 会话。这将重定向用户到产品结账页面。

await authClient.checkout({
  // 可以在此处传递任何 Polar 产品 ID
  products: ["e651f46d-ac20-4f26-b769-ad088b123df2"],
  // 或者,如果您在 Checkout 配置中设置了 "products",您可以传递 slug
  slug: "pro",
});

结账会自动将已认证用户作为客户携带到结账中。电子邮件地址将被“锁定”。

如果 authenticatedUsersOnlyfalse - 则可以触发没有关联客户的结账会话。

组织支持

此插件支持 Organization 插件。如果您将组织 ID 传递到 Checkout 的 referenceId,则可以跟踪组织成员的购买。

const organizationId = (await authClient.organization.list())?.data?.[0]?.id,

await authClient.checkout({
    // 可以在此处传递任何 Polar 产品 ID
    products: ["e651f46d-ac20-4f26-b769-ad088b123df2"],
    // 或者,如果您在 Checkout 配置中设置了 "products",您可以传递 slug
    slug: 'pro',
    // 参考 ID 将保存为结账、订单和订阅对象的元数据中的 `referenceId`
    referenceId: organizationId
});

Portal 插件

一个启用客户管理其购买、订单和订阅的插件。

import { polar, checkout, portal } from "@polar-sh/better-auth";

const auth = betterAuth({
    // ... Better Auth 配置
    plugins: [
        polar({
            ...
            use: [
                checkout(...),
                portal()
            ],
        })
    ]
});

portal 插件为 BetterAuth 客户端提供了一组客户管理方法,这些方法位于 authClient.customer 下。

客户门户管理

以下方法将重定向用户到 Polar 客户门户,在那里他们可以看到订单、购买、订阅、权益等。

await authClient.customer.portal();

客户状态

portal 插件还添加了一个便捷的状态方法,用于检索一般的客户状态。

const { data: customerState } = await authClient.customer.state();

客户状态对象包含:

  • 所有关于客户的数据。
  • 他们的活跃订阅列表
    • 注意:这不包括由父组织完成的订阅。有关更多信息,请参阅下面的订阅列表方法。
  • 他们的已授予权益列表。
  • 他们的活跃计量器列表,以及当前余额。

因此,通过该单个对象,您拥有检查是否应提供对您服务的访问所需的所有信息。

您可以在 Polar 文档中了解更多关于 Polar 客户状态的信息

权益、订单和订阅

portal 插件添加了 3 个便捷方法,用于列出与已认证用户/客户相关的权益、订单和订阅。

所有这些方法都使用 Polar CustomerPortal API

权益

此方法仅列出已认证用户/客户的已授予权益。

const { data: benefits } = await authClient.customer.benefits.list({
  query: {
    page: 1,
    limit: 10,
  },
});

订单

此方法列出已认证用户/客户的订单,如购买和订阅续订。

const { data: orders } = await authClient.customer.orders.list({
  query: {
    page: 1,
    limit: 10,
    productBillingType: "one_time", // 或 'recurring'
  },
});

订阅

此方法列出与已认证用户/客户关联的订阅。

const { data: subscriptions } = await authClient.customer.subscriptions.list({
  query: {
    page: 1,
    limit: 10,
    active: true,
  },
});

重要 - 组织支持

不会返回由父组织为已认证用户完成的订阅。

但是,您可以向此方法传递 referenceId。这将返回与该 referenceId 关联的所有订阅,而不是与用户关联的订阅。

因此,为了确定用户是否应有访问权限,请传递用户的组织 ID,以查看该组织是否有活跃订阅。

const organizationId = (await authClient.organization.list())?.data?.[0]?.id,

const { data: subscriptions } = await authClient.customer.orders.list({
    query: {
	    page: 1,
		limit: 10,
		active: true,
        referenceId: organizationId
    },
});

const userShouldHaveAccess = subscriptions.some(
    sub => // 您的逻辑来检查订阅产品或其他内容。
)

Usage 插件

一个用于使用量计费的简单插件。

import { polar, checkout, portal, usage } from "@polar-sh/better-auth";

const auth = betterAuth({
    // ... Better Auth 配置
    plugins: [
        polar({
            ...
            use: [
                checkout(...),
                portal(),
                usage()
            ],
        })
    ]
});

事件摄取

Polar 的使用量计费完全基于事件摄取。从您的应用中摄取事件,创建计量器来表示该使用量,并将计量价格添加到产品中以收取费用。

在 Polar 文档中了解更多关于使用量计费的信息。

const { data: ingested } = await authClient.usage.ingest({
  event: "file-uploads",
  metadata: {
    uploadedFiles: 12,
  },
});

已认证用户会自动与摄取的事件关联。

客户计量器

一个简单的方法,用于列出已认证用户的 Usage 计量器,或我们称之为客户计量器。

客户计量器包含关于他们在您定义的计量器上消费的所有信息。

  • 客户信息
  • 计量器信息
  • 客户计量器信息
    • 已消耗单位
    • 已计入单位
    • 余额
const { data: customerMeters } = await authClient.usage.meters.list({
  query: {
    page: 1,
    limit: 10,
  },
});

Webhooks 插件

Webhook 插件可用于捕获来自您的 Polar 组织的事件。

import { polar, webhooks } from "@polar-sh/better-auth";

const auth = betterAuth({
    // ... Better Auth 配置
    plugins: [
        polar({
            ...
            use: [
                webhooks({
                    secret: process.env.POLAR_WEBHOOK_SECRET,
                    onCustomerStateChanged: (payload) => // 当客户相关任何内容更改时触发
                    onOrderPaid: (payload) => // 当订单支付时触发(购买、订阅续订等)
                    ...  // 超过 25 个细粒度的 webhook 处理程序
                    onPayload: (payload) => // 捕获所有事件的通用处理程序
                })
            ],
        })
    ]
});

在您的 Polar 组织设置页面配置 Webhook 端点。Webhook 端点配置在 /polar/webhooks。

将密钥添加到您的环境变量中。

# .env
POLAR_WEBHOOK_SECRET=...

该插件支持所有 Polar webhook 事件的处理程序:

  • onPayload - 任何传入 Webhook 事件的通用处理程序
  • onCheckoutCreated - 当结账创建时触发
  • onCheckoutUpdated - 当结账更新时触发
  • onOrderCreated - 当订单创建时触发
  • onOrderPaid - 当订单支付时触发
  • onOrderRefunded - 当订单退款时触发
  • onRefundCreated - 当退款创建时触发
  • onRefundUpdated - 当退款更新时触发
  • onSubscriptionCreated - 当订阅创建时触发
  • onSubscriptionUpdated - 当订阅更新时触发
  • onSubscriptionActive - 当订阅变为活跃时触发
  • onSubscriptionCanceled - 当订阅取消时触发
  • onSubscriptionRevoked - 当订阅被撤销时触发
  • onSubscriptionUncanceled - 当订阅取消被逆转时触发
  • onProductCreated - 当产品创建时触发
  • onProductUpdated - 当产品更新时触发
  • onOrganizationUpdated - 当组织更新时触发
  • onBenefitCreated - 当权益创建时触发
  • onBenefitUpdated - 当权益更新时触发
  • onBenefitGrantCreated - 当权益授予创建时触发
  • onBenefitGrantUpdated - 当权益授予更新时触发
  • onBenefitGrantRevoked - 当权益授予被撤销时触发
  • onCustomerCreated - 当客户创建时触发
  • onCustomerUpdated - 当客户更新时触发
  • onCustomerDeleted - 当客户删除时触发
  • onCustomerStateChanged - 当客户创建时触发

On this page