mcpField
S
subscriptions-best-practices

subscriptions-best-practices

github.com/getpaykit開発155 回インストール29 週間前に更新
リポジトリ

subscriptions-best-practices について

PayKit でサブスクリプションを実装する開発者向けのスキルです。状態に応じたプラン変更、決済、ライフサイクル更新、顧客の請求管理を、サーバーとクライアント双方の例で説明します。

主な機能

  1. 01現在の状態に応じた変更処理
  2. 02アップグレード、ダウングレード、解約、再開
  3. 03サーバーとクライアントの使用例
  4. 04状態確認と決済画面への遷移
  5. 05Webhook と顧客ポータルの説明

活用シーン

  1. 01ユーザーのプラン開始や変更
  2. 02アプリへのサブスクリプション状態同期
  3. 03決済画面へのユーザー誘導
  4. 04顧客による支払い方法や請求書の管理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/getpaykit/skills --skill subscriptions-best-practices

インストール後、Claude Code で/subscriptions-best-practicesを入力して読み込まれたか確認します。

詳細

サブスクリプション

PayKit はすべてのサブスクリプションの切り替えに、単一の subscribe() メソッドを使用します。

subscribe()

const result = await paykit.subscribe({
  customerId: "user_123",
  planId: "pro",
  successUrl: "https://example.com/billing?success=true",
  cancelUrl: "https://example.com/billing",
})
パラメーター
パラメーター必須説明
customerIdはいアプリのユーザー ID
planIdはい対象のプラン ID(型安全)
successUrlはいチェックアウト成功後のリダイレクト先
cancelUrlいいえユーザーがチェックアウトをキャンセルした場合のリダイレクト先
forceCheckoutいいえ支払い方法が登録済みでも、常にチェックアウトへリダイレクトします
戻り値
interface SubscribeResult {
  paymentUrl: string | null
  invoice?: {
    providerInvoiceId: string
    hostedUrl: string | null
    currency: string
    totalAmount: number
    status: string | null
  }
  requiredAction?: {
    type: string
    paymentIntentId?: string
    clientSecret?: string
  } | null
}

切り替えの動作

subscribe() は、顧客の現在の状態に基づいて適切な処理を判断します。

現在の状態対象動作
サブスクリプションなし無料プラン即時に有効化します
サブスクリプションなし有料プラン、支払い方法なしStripe Checkout 用の paymentUrl を返します
サブスクリプションなし有料プラン、支払い方法ありサブスクリプションを直接作成します
無料プラン利用中有料プランチェックアウトまたはサブスクリプションを直接作成します
有料プラン利用中同じグループのより高価格なプランアップグレード:即時に切り替えます
有料プラン利用中同じグループのより低価格なプランダウングレード:期間終了時に適用するよう予約します
有料プラン利用中同じグループの無料プランキャンセル:期間終了時に適用するよう予約します
キャンセル待ち同じプラン再開:キャンセルを取り消します
ダウングレード待ち現在のプラン再開:予約された変更を取り消します
現在のプラン利用中同じプラン、保留中の変更なし何もしません

サーバーサイドでの使用

// New subscription (may require checkout)
const { paymentUrl } = await paykit.subscribe({
  customerId: "user_123",
  planId: "pro",
  successUrl: "/billing?success=true",
})

if (paymentUrl) {
  // Redirect user to Stripe Checkout
  redirect(paymentUrl)
}

// Upgrade (immediate, no checkout needed)
await paykit.subscribe({
  customerId: "user_123",
  planId: "enterprise",
  successUrl: "/billing",
})

// Downgrade (scheduled for period end)
await paykit.subscribe({
  customerId: "user_123",
  planId: "free",
  successUrl: "/billing",
})

// Resume a pending cancellation
await paykit.subscribe({
  customerId: "user_123",
  planId: "pro", // same plan they're on
  successUrl: "/billing",
})

クライアントサイドでの使用

identify によって解決されるため、クライアント SDK では customerId を省略します。

import { paykitClient } from "@/lib/paykit-client"

// Subscribe to a plan
await paykitClient.subscribe({
  planId: "pro",
  successUrl: `${window.location.origin}/billing?success=true`,
  cancelUrl: `${window.location.origin}/billing`,
})

// Open Stripe Customer Portal (manage payment methods, invoices)
await paykitClient.customerPortal({
  returnUrl: window.location.href,
})

サブスクリプションの状態を取得する

const customer = await paykit.getCustomer({ id: "user_123" })

for (const sub of customer.subscriptions) {
  console.log(sub.planId)              // "pro"
  console.log(sub.status)             // "active", "canceled", etc.
  console.log(sub.cancelAtPeriodEnd)  // true if pending cancellation
  console.log(sub.currentPeriodEnd)   // when the current period ends
}

チェックアウトのリダイレクト処理

subscribe() が paymentUrl を返したら、支払いを完了できるようユーザーをリダイレクトします。

サーバーコンポーネント/API ルート:

import { redirect } from "next/navigation"

const { paymentUrl } = await paykit.subscribe({
  customerId: userId,
  planId: "pro",
  successUrl: `${process.env.NEXT_PUBLIC_APP_URL}/billing?success=true`,
})

if (paymentUrl) {
  redirect(paymentUrl)
}

クライアントサイド:

const result = await paykitClient.subscribe({
  planId: "pro",
  successUrl: `${window.location.origin}/billing?success=true`,
})

paymentUrl が返された場合、クライアント SDK がリダイレクトを自動的に処理します。


Webhook

Stripe はサブスクリプションのライフサイクルイベントについて Webhook を送信します。PayKit はルートハンドラーを介してこれらを自動的に処理します。

Stripe で Webhook エンドポイントを {your-domain}/paykit/api/webhook に設定してください。

アプリでサブスクリプションの変更に対応するには、次のようにします。

export const paykit = createPayKit({
  // ...
  on: {
    "customer.updated": ({ payload }) => {
      // Sync subscription state to your app
      await updateUserRole(payload.customerId, payload.subscriptions)
    },
  },
})

Stripe Customer Portal

顧客が請求情報を管理できるようにします(支払い方法の更新、請求書の確認、キャンセル)。

// Server-side
const { url } = await paykit.customerPortal({
  customerId: "user_123",
  returnUrl: "https://example.com/billing",
})

// Client-side
await paykitClient.customerPortal({
  returnUrl: window.location.href,
})

コメント