跳过主要内容
文档目录

支付

学习如何在 MinuteShip 中设置和使用支付

MinuteShip 支持多种支付提供商,您可以根据需要选择合适的支付方案。

支付提供商

共用支付流程

三个支付提供商共用相同的应用路由和已认证的服务端函数:

  • /pricing 发起结账。
  • /settings/payment 等待当前结账创建的支付记录。
  • /settings/billing 显示有效计划,并打开支付提供商的客户门户。

Stripe 使用 session_id 标识订单;Creem 和 Waffo 则通过 request_id 或 checkout_id 传回服务端生成的订单引用。MinuteShip 会同时按该引用和当前登录用户查询,因此旧的已支付订单不会误判为本次结账成功。

结账成功、取消、回调和客户门户返回地址必须是根路径相对地址,或使用 VITE_BASE_URL 配置的完全相同来源。外部来源、协议相对地址、协议变更和子域名都会被拒绝。

自定义支付提供商

MinuteShip 支持扩展新的支付提供商:

  1. 在 src/payment/provider 目录中创建新的文件
  2. 从 types.ts 实现 PaymentProvider 接口
  3. 在 index.ts 中的 providerRegistry 注册新的提供商

接口还包含两个可选的行为标志:

  • requiresCustomerId 默认为 true。只有当支付提供商使用共享门户、且没有独立客户记录时,才设为 false。
  • hostsPostCheckoutPage 默认为 false,即采用 Stripe 的 {CHECKOUT_SESSION_ID} 流程。当支付提供商托管自己的确认页面,并通过 metadata 和 Webhook 返回订单引用时,将其设为 true。

新的支付服务提供商的示例实现:

src/payment/provider/my-provider.ts

import type {
  PaymentProvider,
  CreateCheckoutParams,
  CheckoutResult,
  CreatePortalParams,
  PortalResult,
} from '../types';

export class MyProvider implements PaymentProvider {
  readonly requiresCustomerId = true;
  readonly hostsPostCheckoutPage = false;

  getProviderName(): string {
    return 'my-provider';
  }

  public async createCheckout(params: CreateCheckoutParams): Promise<CheckoutResult> {
    // Create checkout session implementation
  }

  public async createCustomerPortal(params: CreatePortalParams): Promise<PortalResult> {
    // Create customer portal implementation
  }

  public async handleWebhookEvent(payload: string, signature: string): Promise<void> {
    // Handle webhook events implementation
  }
}

然后在 index.ts 中的 providerRegistry 注册新的提供商:

src/payment/index.ts

import { MyProvider } from './provider/my-provider';

const providerRegistry: Record<PaymentProviderName, ProviderFactory> = {
  stripe: () => new StripeProvider(),
  creem: () => new CreemProvider(),
  waffo: () => new WaffoProvider(),
  'my-provider': () => new MyProvider(),
};