polar-migration について
Polar の課金への移行を計画・実装する開発者向けのガイドです。Stripe の支援付き移行と他社からの移行を分け、顧客の紐付け、切り替え、照合の手順を説明します。
主な機能
- 01Stripe 移行の手順
- 02他社課金サービスからの移行案内
- 03顧客とサブスクリプションの紐付け
- 04切り替えイベントの処理
- 05テストと照合のガイダンス
活用シーン
- 01Stripe から Polar への移行計画
- 02他社からのサブスクリプション移行
- 03切り替え中の Webhook 処理の実装
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ polarsource/ agent-toolkit --skill polar-migrationインストール後、Claude Code で/polar-migrationを入力して読み込まれたか確認します。
詳細
Polar の移行ガイド
Polar の移行ガイドが正式な情報源です。何かを推奨する前に必ずお読みください。このスキルでは、アプリケーションで必要な対応をまとめています。
移行方法を選ぶ
- Stripe からの移行: Polar の Settings → Migrations から、サポート付きの移行を利用します。Polar が商品、価格、顧客をインポートし、Stripe が保存済みカードを Polar の決済処理システムに直接コピーします。その後、Polar が各サブスクリプションを、同じ支払い期間を維持したまま切り替えます。ほとんどの顧客は何もする必要がありません。移行機能は段階的に提供されています。タブが表示されない場合は、Polar サポートにお問い合わせください。
- Paddle、Lemon Squeezy、その他のサービスからの移行: 自動移行には対応していません。まず Polar サポートにお問い合わせのうえ、以下の「その他のプロバイダー」の手順に従ってください。顧客は Polar で再度チェックアウトして移行します。
すべての移行に共通するルール
- Polar の切り替え処理以外で、旧プロバイダーの請求を停止、キャンセル、一時停止したり、移行済みの Polar サブスクリプションを有効化したりしないでください。独自の切り替えスクリプトを作成しないでください。二重請求が発生します。
- カードの生データを扱わないでください。また、チャットで Stripe や Polar のシークレットを尋ねないでください。
- Polar の顧客
external_idには、アプリケーションの変更不可能な顧客 ID を使用します(チェックアウト時にはexternal_customer_idとして渡します)。メールアドレスや、旧プロバイダーの ID は使用しないでください。ただし、それがすでにアプリの正規 ID である場合は除きます。external_idは一度設定すると変更できません。 - 各サブスクリプションの次回更新を担当するシステムは、必ず 1 つだけにしてください。設定されている ID から推測するのではなく、担当するシステムを記録してください。
- 過去の支払いは旧プロバイダーに残ります。Polar が処理していない取引の注文を Polar で作成しないでください。また、返金、異議申し立て、会計処理のために旧アカウントを維持してください。
Stripe からの移行
Stripe との接続、商品カタログのインポート、カードのコピー、サブスクリプションの切り替えはダッシュボードで処理します。アプリケーションでは最初と最後の段階、およびその間に発生するイベントを処理します。
1. 新規販売を Polar に移行する
まず Polar のチェックアウトと Webhook を統合し(polar-integration)、すべてのチェックアウトで external_customer_id を渡します。新規顧客は Polar でサブスクリプションを開始し、既存のサブスクリプションは引き続き Stripe で更新されます。Stripe の ID は、Stripe で更新されるサブスクリプションがなくなるまでデータベースに保持してください。
併用期間中は、いずれかのプロバイダーで有効な利用権があればアクセスを許可する必要があります。また、キャンセルやプラン変更は、そのサブスクリプションの請求を担当するシステムに対して行ってください。
2. インポートした顧客を対応付ける
インポート時に Polar の顧客が新規作成または再利用されますが、Polar はアプリケーションの顧客 ID を把握できません。インポートした各顧客は、完全一致する一意のメールアドレスを使って一度だけ照合し、external_id がまだ空の顧客にアプリの ID を設定してください。メールアドレスがない、重複している、または変更されている場合は、推測せず確認に回してください。
import { polar } from "./polar"; // client from polar-integration
const customer = await polar.customers.get(polarCustomerId);
if (customer.external_id === null) {
await polar.customers.update(polarCustomerId, { external_id: appCustomerId });
}
インポートされた商品は新しい Polar 商品です。各内部プランを新しい Polar の商品 ID と価格 ID に明示的に対応付けてください。名前による対応付けは避けてください。特典はインポートされないため、アクセス権が特典に依存する場合は、切り替え前にインポートした商品に特典を追加してください。
3. 切り替えの準備
Polar は、切り替え対象の Stripe の各サブスクリプションを、日割り計算や最終請求書なしで即時解約します。切り替えの前に、次の対応を行ってください。
-
Stripe のサブスクリプション解約メール(Settings → Billing → Subscriptions and emails)をオフにし、解約をトリガーとする Stripe の自動処理を一時停止します。
-
Stripe の
customer.subscription.deletedハンドラーで、切り替え対象のサブスクリプションを無視するようにします。アクセス権の取り消しや解約メールの送信が行われないようにしてください。if (subscription.cancellation_details?.comment?.startsWith("Migrated to Polar")) { return; // billing moved to Polar; reconcile through subscription.migrated instead } -
Polar の
subscription.migratedイベントを切り替えのシグナルとして処理します。このイベントにはproviderとprovider_subscription_idが含まれます。冪等なアップサートとして処理し、Polar のサブスクリプション ID を Stripe のサブスクリプションに関連付け、次回の請求を行うシステムとして Polar を記録します。このイベントによるアクセス権の付与や取り消しは行わず、ウェルカムメールも送信しないでください。case "subscription.migrated": await recordMigratedSubscription({ stripeSubscriptionId: event.provider_subscription_id, polarSubscriptionId: event.data.id, }); break;
切り替え対象の各サブスクリプションについて、subscription.updated、subscription.migrated、customer.state_changed が任意の順序で届くことを想定してください。移行時に subscription.created や subscription.active は送信されず、インポート時に product.created や customer.created も送信されません。
4. 切り替え、照合、後片付け
ダッシュボードから切り替えを実行します。元に戻すことはできません。24 時間以内に更新予定のサブスクリプションは、次回の請求が試みられるまで Stripe に残ります。切り替え後は、移行したすべてのサブスクリプションの請求が Polar のみで行われ、顧客と利用権がそれぞれ 1 つに対応していることを確認してください。Stripe で更新されるサブスクリプションがなくなってから、Stripe のチェックアウトとサブスクリプションのコードを廃止してください。
事前に把握しておくべき制限事項:Stripe Connect のプラットフォームアカウントとインドの Stripe アカウントでは、自動移行フローを利用できません。Stripe Managed Payments を通じて販売されたサブスクリプション、および複数のアイテムがあるもの、数量が 1 を超えるもの、支払い遅延・未払い・一時停止のステータスにあるものは、個別の対応が必要か、Stripe に残ります。コピーされるのはカードのみで、実際のカード情報をコピーするには本番環境の Stripe アカウントが必要です。また、Stripe キーのモードは Polar の環境と一致している必要があります。
詳細な評価については、Polar のガイドにある コーディングアシスタントのプロンプトを使用すると、コードを変更する前に移行計画と照合要件を作成できます。
その他のプロバイダー
カタログの再作成
請求間隔は商品に設定され、商品には通貨ごとに固定価格が 1 つあります。月払いと年払いは、それぞれ別の商品にします。
await polar.products.create({
name: "Pro (Monthly)",
recurring_interval: "month",
prices: [{ amount_type: "fixed", price_amount: 2900, price_currency: "usd" }],
});
await polar.products.create({
name: "Pro (Yearly)",
recurring_interval: "year",
prices: [{ amount_type: "fixed", price_amount: 29000, price_currency: "usd" }],
});
特典(ライセンスキー、ファイルのダウンロード、Discord のロールなど)を再作成し、polar.products.updateBenefits(productId, { benefits: [benefitId] }) を使って商品に関連付けます。
顧客の移行
顧客がチェックアウトする前に Polar に登録しておきたい場合は、あらかじめ顧客を作成します。
await polar.customers.create({ external_id: appCustomerId, email, name });
有料サブスクリプションは API 経由で作成できず、Stripe のコピー機能を使う場合を除き、保存済みのカードを別の決済プロセッサーに移すこともできません。顧客は Polar でチェックアウトし、そこでカード情報を入力します。external_customer_id を使って作成したチェックアウトリンクを送信してください。
同じ期間に二重で課金されないよう、旧サブスクリプションは期間終了時に解約されるよう設定し、残りの日数をカバーするトライアルを Polar のチェックアウトに設定します。その際は、trial_interval: "day" と trial_interval_count を使用します。この方法がお客様のケースに適しているか、Polar サポートに確認してください。
ライセンスキー
ライセンスキーはインポートできません。移行期間中は既存のキーを旧プロバイダーで引き続き検証し、新規購入には Polar のキーを使用してください。
顧客への案内
- Stripe からの移行: 顧客側での対応は不要です。Polar は、最初の更新時の領収書など、最初の請求メールに移行に関するお知らせを追加します。Polar から案内される前に顧客へ伝えておきたい場合は、切り替えの前に簡潔なお知らせを送ってください。
- その他のプロバイダー: 顧客は再度チェックアウトする必要があります。Polar でカード情報を入力すること、請求日、旧サブスクリプションが支払い済み期間の終了時に終了することを、明確に伝えてください。
テスト
まず、Stripe のテストモードアカウントを使って、Polar のサンドボックスで移行を実行してください。サンドボックスでは、アプリケーション側(顧客のマッピング、subscription.migrated の処理、アクセスチェック)を検証できますが、実際のカード情報はコピーできません。サンドボックスのセットアップとローカルでの Webhook テストについては、polar-testing を参照してください。