mcpField
F
freemius-customer-portal

freemius-customer-portal

github.com/freemius開発399 回インストール14 週間前に更新
リポジトリ

freemius-customer-portal について

Freemiusの購入後ポータルをアプリに組み込むためのスキルです。開発者向けに、サブスクリプション、請求情報、解約、請求書を扱うサーバー駆動のエンドポイントとReactコンポーネントを案内します。

主な機能

  1. 01ポータル要求用の単一サーバーエンドポイント
  2. 02サブスクリプション表示とライセンスアップグレード
  3. 03継続特典クーポンを伴う解約フロー
  4. 04請求情報の更新と請求書PDF

活用シーン

  1. 01セルフサービスのサブスクリプション管理追加
  2. 02更新解約前のクーポン提示
  3. 03顧客による請求情報の更新
  4. 04支払い履歴の表示と請求書ダウンロード

インストール

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

$npx skills add https://github.com/freemius/freemius-ai --skill freemius-customer-portal

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
billing.md
cancellation-and-coupon.md
headless-endpoint.md
payments-and-invoices.md
subscription-and-upgrade.md

詳細

Freemius カスタマーポータル

サインインしたユーザーが購入後のすべてを管理できるページを用意します。サブスクリプション、アップグレード、キャンセル(継続特典付き)、請求先情報、請求書を管理でき、アプリ側で請求ロジックを再実装する必要はありません。

出典:React Starter Kit Customer Portal コンポーネント https://freemius.com/help/documentation/saas-sdk/react-starter/components/#customer-portal-component

フレームワークに関する注意。 この Skill のルート例は Hono 用に記述されていますが、SDK のポータルプロセッサーは Web Standard の Request/Response ルーティングに対応するあらゆるフレームワークで動作します。アプリで実際に使用している HTTP フレームワークに合わせて、シンプルなルートを調整してください。React Starter Kit の CustomerPortal コンポーネントは React 19+ と shadcn UI + Tailwind を対象としています(npx shadcn@latest add https://shadcn.freemius.com/all.json でインストールしてください)。アプリで shadcn/React を使用していない場合は、参考実装として利用してください。

サンドボックス。 検証中は、プロセッサーの isSandbox を専用の FREEMIUS_SANDBOX 環境変数に接続してください(NODE_ENV は絶対に使用しないでください)。これにより、チェックアウトのサンドボックスモードと一致します。サンドボックスはテスト用クレジットカードを使用するチェックアウトモードで、freemius-core が管理しています。

守るべき重要なルール

  1. ポータルはヘッドレスで、サーバー主導です。 SDK には PortalRequestProcessor が用意されています。バックエンドでエンドポイントを 1 つ(GET|POST /api/portal)公開すると、SDK がデータの取得と、署名付きのアクションごとの URL を介したすべてのアクションを処理します。コンポーネントが Freemius に直接アクセスすることはありません。
  2. アクションにはトークン署名が付与されます。 ポータルデータには署名済みのアクション URL(キャンセル、クーポン、請求先情報の更新、請求書)が含まれます。コンポーネントはそれらの URL にアクセスするだけで、SDK がサーバー側でトークンを検証します。認証済みユーザーの識別情報を渡すだけでかまいません。(アップグレードは例外で、サーバー側で構築したライセンスアップグレード用チェックアウト(setLicenseUpgradeByKey)を経由します。これにより、二重サブスクリプションや更新中のライセンスで発生する 500 エラーを回避できます。)
  3. ユーザーの識別情報はアプリ側で管理し、それ以外はすべて SDK が処理します。 プロセッサーの getUser は、セッションから Freemius ユーザーを特定します(たとえば、メールアドレスから特定します)。Freemius の認証情報はすべてサーバー側に保持されます。
  4. キャンセルの前に、まず継続を促してください。 更新キャンセル用のクーポンが利用可能な場合は、キャンセルを完了する前に提示してください。

1 つのエンドポイント

// src/server/services/freemius/portal.ts
import { freemius, IS_SANDBOX } from './client';
import { env } from '../../env';

const PORTAL_ENDPOINT = `${env.publicAppUrl}/api/portal`;

export async function processPortalRequest(
  request: Request,
  email: string
): Promise<Response> {
  const processor = freemius.customerPortal.request.createProcessor({
    portalEndpoint: PORTAL_ENDPOINT, // must match the public URL the browser hits
    isSandbox: IS_SANDBOX,
    getUser: async () => {
      const fsUser = await freemius.api.user.retrieveByEmail(email);
      return fsUser?.id ? { id: String(fsUser.id), email } : { email };
    },
  });
  return processor(request); // dispatches by ?action= and verifies tokens
}
// src/server/routes/portal.ts — route stays thin: auth, then delegate.
portalRoute.on(['GET', 'POST'], '/', requireUser, async (c) =>
  processPortalRequest(c.req.raw, c.get('user').email)
);

プロセッサーは ?action= クエリパラメーターに基づいて処理を振り分けます。

メソッド?action=結果
GETportal_dataサブスクリプション+請求先情報+支払い+署名付き URL
POSTbilling請求先情報の更新
POSTsubscription_cancellation更新のキャンセル(任意のフィードバック付き)
POSTsubscription_cancellation_coupon継続クーポンの適用
GETinvoice請求書 PDF をストリーミング配信

references/headless-endpoint.md を参照してください。

コンポーネント

CustomerPortal を、編集可能な shadcn/ui スタイルの React ソースとして実装します。?action=portal_data を一度取得し、そのデータに組み込まれた署名付き URL を使って、次の 4 つのセクションを表示します。

セクションユーザーができることリファレンス
サブスクリプション現在のプランを確認し、サーバー側で構築された ライセンスアップグレードのチェックアウト(setLicenseUpgradeByKey)を使ってアップグレードします。これは二重サブスクリプションや更新中のライセンスで発生する 500 エラーを回避できる堅牢な方法です。references/subscription-and-upgrade.md
キャンセル更新をキャンセルします — 免責事項 → 継続特典クーポン → フィードバックreferences/cancellation-and-coupon.md
請求情報事業者名/納税者番号/住所を編集しますreferences/billing.md
支払いと請求書支払い履歴を確認し、請求書の PDF をダウンロードしますreferences/payments-and-invoices.md

クイックスタート(フロントエンド)

import { CustomerPortal } from './react-starter/components/customer-portal';
import { PORTAL_ENDPOINT, portalFetch } from './api';

// portalFetch attaches the auth header; the component does the rest.
<CustomerPortal endpoint={PORTAL_ENDPOINT} fetcher={portalFetch} />;
// Loading portal data:
const res = await fetcher(`${endpoint}?action=portal_data`);
const data = (await res.json()) as PortalData;
// data.subscriptions.{primary,active,past}, data.billing, data.payments,
// data.cancellationCoupons — each carries signed action URLs.

基本的な考え方

Frontend <CustomerPortal>               Backend (one endpoint)                Freemius
  GET  /api/portal?action=portal_data ─▶ processPortalRequest()
  { subscriptions, billing, payments, ◀─ freemius.customerPortal.request
    + signed action URLs }                .createProcessor() → getUser()
  POST <signed cancelRenewalUrl> ───────▶ processor verifies token ──────────▶ cancel renewal
  POST <signed couponUrl> ──────────────▶ processor verifies token ──────────▶ apply coupon
  POST <signed billing updateUrl> ──────▶ processor verifies token ──────────▶ update billing
  GET  <signed invoiceUrl> ─────────────▶ processor verifies token ──────────▶ invoice PDF
  GET  /api/checkout/upgrade ───────────▶ license.retrieve + checkout.create()
  { link } ◀──────────────────────────── .setLicenseUpgradeByKey(secret_key) ─▶ plan-change
                                          .getLink() — browser navigates ─────▶ checkout

⚠️ アップグレードには、上記のサーバー側で構築されたライセンスアップグレードのチェックアウトを使ってください。また、これには checkout.create({ licenseId }) を使わないでください。更新が有効なライセンスでは、このオプションは 500 エラーになります(SDK 内部で支払い方法更新エンドポイントを呼び出しますが、このエンドポイントは expiration: null のライセンスを「無期限」として拒否します)。ライセンスをサーバー側で取得し、代わりに setLicenseUpgradeByKey(license.secret_key) を使ってください。詳しくは、references/subscription-and-upgrade.md を参照してください。

ダッシュボードの設定(担当者に依頼)

  • 製品 → クーポン → 更新キャンセル(継続特典)クーポンを作成し、cancellationCoupons にデータが設定され、ウィザードで提示できるようにします。
  • ローカルのエンタイトルメントを同期する Webhook とリダイレクトの設定は freemius-core が管理します。アップグレード/キャンセルは Webhook イベント(license.plan.changed、license.cancelled など)としてここに届きます。

アクション後の同期(変更がアプリに反映される仕組み)

ポータルでのアクションは、まず Freemius 側の状態を変更します。その後、ローカルの user_fs_entitlement ミラーは次の 2 つの方法で更新されます。

  • ポータル UI では即時に反映 — アクションの後に ?action=portal_data を再取得します(Freemius の最新データを読み込みます)。
  • エンタイトルメントミラーでは — freemius-core の Webhook を通じて更新されます(アップグレード時は license.plan.changed、キャンセル時は license.cancelled/有効期限切れ)。⚠️ ダッシュボードで Webhook URL を設定または変更した後、反映まで 約 5 分かかります。URL が有効になる前に発生したイベントは配信されず、後から再送されることもありません。詳しくは freemius-core の references/webhooks.md(イベントの取りこぼしが疑われる場合は freemius-troubleshooting)を参照してください。

コメント