framework-adapters について
公式アダプターで Dodo Payments を Web フレームワークに統合する開発者向けガイドです。複数のフレームワークで使うチェックアウト、顧客ポータル、Webhook ハンドラーと、環境設定やセキュリティ上の注意点を説明します。
主な機能
- 01複数フレームワーク向け公式アダプター
- 02チェックアウトのルートハンドラー作成
- 03顧客ポータルのセッションリンク生成
- 04Webhook 署名の検証とイベント処理
- 05環境変数とリクエスト形式の対応
活用シーン
- 01Web フレームワークへの決済ルート追加
- 02認証付き顧客ポータルの作成
- 03決済 Webhook の受信と検証
- 04フレームワークに応じたアダプターと処理方式の選択
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dodopayments/ skills --skill framework-adaptersインストール後、Claude Code で/framework-adaptersを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/astro.mdbun.mdconvex.mdexpress.mdfastify.mdhono.mdnuxt.mdremix.mdsveltekit.mdtanstack-start.md詳細
フレームワークアダプター
公式アダプターパッケージを使用して、Web フレームワークに Dodo Payments を統合する場合は、このスキルを使用してください。フレームワークアダプターは、ルートの配線、環境設定、ハンドラーのセットアップを行うため、チェックアウト、ポータル、Webhook のルートを一から構築する必要はありません。
このスキルを使用する場面
- Next.js、Express、Fastify、Hono、Astro、Remix、SvelteKit、Nuxt、TanStack、Bun、または Convex でチェックアウトフローを構築しています。
- カスタマーポータルのセッションエンドポイントをセットアップする必要があります。
- 署名を検証してイベントをディスパッチする Webhook ハンドラーを追加しています。
- フレームワークに適したルートの配置や環境変数の処理が必要です。
- 静的、動的、セッションのどのチェックアウトモードを選ぶか決める必要があります。
フレームワークアダプターの機能
Dodo は、フレームワーク固有のルートハンドラーでコア SDK をラップする @dodopayments/* パッケージを公開しています。独自の HTTP ハンドラーを記述する代わりに、アダプターのハンドラーをインポートして、ルートに直接マウントします。
各アダプターは、次の 3 種類のハンドラーを提供します。
- Checkout: 静的(GET のみ)、動的(POST。非推奨の
POST /payments/POST /subscriptionsエンドポイントを使って支払いまたはサブスクリプションを作成します。既存の統合向けです)、またはセッション(チェックアウトセッションのペイロードを指定する POST。新しい統合ではこちらを使用してください)。 - CustomerPortal: 有効期限付きのポータルセッションリンクを生成します。
- Webhooks: Webhook の署名を検証し、型付きイベントをディスパッチします。
セキュリティ — CustomerPortal は認証を行いません。 すべての
CustomerPortalハンドラーは、受け取った?customer_id=の値に対応するポータルを開きます。そのままマウントすると、ID を推測または列挙することで、誰でも任意の顧客のポータルを開けてしまいます。このルートには独自の認証を適用し、顧客 ID はサインイン済みセッションからサーバー側で解決してください。クライアントから受け取ってはいけません。以下のポータルの例では、この方法を使用しています。
アダプターによってエクスポート名は統一されていません。 ほとんどのアダプターは Checkout / CustomerPortal / Webhooks をエクスポートしますが、異なるものが 2 つあり、戻り値の形式も異なります。インポートを記述する前に、この表を確認してください。
| アダプター | Checkout のエクスポート | Portal のエクスポート | ハンドラーの形式 |
|---|---|---|---|
nextjs、hono、astro、bun、remix、tanstack | Checkout | CustomerPortal | リクエストハンドラーを返します |
express | checkoutHandler(小文字) | CustomerPortal | (req, res) を返します |
fastify | Checkout | CustomerPortal | { getHandler, postHandler } を返します |
sveltekit | Checkout | CustomerPortal | { GET, POST } / { GET } を返します |
nuxt | checkoutHandler(自動インポート) | customerPortalHandler | インポート文は不要です |
convex | checkout(dodo.api() から) | customerPortal(dodo.api() から、identify を使用) | createDodoWebhookHandler |
アダプターは、Webhook 検証のための生のボディの保持、環境変数のマッピング、フレームワーク固有のリクエスト/レスポンス形式への対応を行います。チェックアウトのペイロード設計には checkout-integration スキルを、Webhook のビジネスロジックには webhook-integration を、ポータルの動作には customer-management を使用してください。
フレームワークの選択とインストール
| フレームワーク | パッケージ | インストール |
|---|---|---|
| Next.js | @dodopayments/nextjs | npm install @dodopayments/nextjs |
| Express | @dodopayments/express | npm install @dodopayments/express |
| Fastify | @dodopayments/fastify | npm install @dodopayments/fastify |
| Hono | @dodopayments/hono | npm install @dodopayments/hono |
| Astro | @dodopayments/astro | npm install @dodopayments/astro |
| Remix | @dodopayments/remix | npm install @dodopayments/remix |
| SvelteKit | @dodopayments/sveltekit | npm install @dodopayments/sveltekit |
| Nuxt | @dodopayments/nuxt | npm install @dodopayments/nuxt |
| TanStack Start | @dodopayments/tanstack | npm install @dodopayments/tanstack |
| Bun | @dodopayments/bun | bun add @dodopayments/bun |
| Convex | @dodopayments/convex | npm install @dodopayments/convex |
環境変数
ほとんどのアダプターでは、次の標準名を使用します。
DODO_PAYMENTS_API_KEY=dodo_test_...
DODO_PAYMENTS_WEBHOOK_KEY=your-webhook-secret
DODO_PAYMENTS_ENVIRONMENT=test_mode
DODO_PAYMENTS_RETURN_URL=https://yourdomain.com/checkout/success
Nuxt では、プライベートランタイム設定のプレフィックスを使用します。
NUXT_PRIVATE_BEARER_TOKEN=dodo_test_...
NUXT_PRIVATE_WEBHOOK_KEY=your-webhook-secret
NUXT_PRIVATE_ENVIRONMENT=test_mode
NUXT_PRIVATE_RETURN_URL=https://yourdomain.com/checkout/success
Convex では、ダッシュボードの環境変数を使用します(ローカルの .env ではありません)。
DODO_PAYMENTS_API_KEY=dodo_test_...
DODO_PAYMENTS_ENVIRONMENT=test_mode
DODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret
Webhook キーの命名: アダプターによって、DODO_PAYMENTS_WEBHOOK_KEY を参照するものと、DODO_PAYMENTS_WEBHOOK_SECRET を使用するものがあります。正しい変数名を使用できるよう、フレームワークのアダプタードキュメントとダッシュボードの設定を確認してください。
environment の型を絞り込む
アダプターの設定では、environment の型として Pick<ClientOptions, "environment">、つまりリテラルユニオン型 "test_mode" | "live_mode" を使用します。process.env.X の型は string | undefined であるため、代入できません。どのアダプターでも、直接渡すと型エラーになります。
アダプターの設定を作成する場所でインポートできるよう、このヘルパーを一度定義してください。
// lib/dodo-env.ts
export const dodoEnvironment =
process.env.DODO_PAYMENTS_ENVIRONMENT === "live_mode" ? "live_mode" : "test_mode";
test_mode をデフォルトにするのは意図的です。変数が存在しない場合や名前に誤りがある場合に、ライブモードに暗黙的に切り替わることがあってはなりません。以下のすべての例では dodoEnvironment を使用します。
Next.js
パッケージ: @dodopayments/nextjs
ルートの配置場所: app/api/checkout/route.ts、app/api/customer-portal/route.ts、app/api/webhook/route.ts
チェックアウト(ルートごとにいずれかのモードを選択)
// app/api/checkout/route.ts
import { Checkout } from "@dodopayments/nextjs";
import { dodoEnvironment } from "@/lib/dodo-env";
export const GET = Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: dodoEnvironment,
type: "static",
});
export const POST = Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: dodoEnvironment,
type: "session",
});
カスタマーポータル
// app/api/customer-portal/route.ts
import { NextRequest } from "next/server";
import { CustomerPortal } from "@dodopayments/nextjs";
import { dodoEnvironment } from "@/lib/dodo-env";
// your auth helper
import { getSessionUser } from "@/lib/auth";
const portal = CustomerPortal({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
environment: dodoEnvironment,
});
export async function GET(req: NextRequest) {
const user = await getSessionUser(req);
if (!user?.dodoCustomerId) return new Response("Unauthorized", { status: 401 });
// Overwrite any client-supplied ?customer_id= with the signed-in user's ID.
const url = new URL(req.url);
url.searchParams.set("customer_id", user.dodoCustomerId);
return portal(new NextRequest(url, req));
}
Webhook
// app/api/webhook/route.ts
import { Webhooks } from "@dodopayments/nextjs";
export const POST = Webhooks({
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
onPayload: async (payload) => {
console.log("Webhook received:", payload.type);
},
});
Express
完全なガイド:references/express.md。
以下を扱います。
- チェックアウト
- カスタマーポータル
- Webhook
Fastify
完全なガイド:references/fastify.md。
以下を扱います。
- チェックアウト
- Webhook
Hono
完全なガイド:references/hono.md。
以下を扱います。
- チェックアウト
- カスタマーポータル
- Webhook
Astro
完全なガイド:references/astro.md。
以下を扱います。
- チェックアウト
- Webhook
Remix
完全なガイド:references/remix.md。
以下を扱います。
- チェックアウト
- カスタマーポータル
- Webhook
SvelteKit
完全なガイド:references/sveltekit.md。
以下を扱います。
- チェックアウト
- Webhook
Nuxt
完全なガイド:references/nuxt.md。
以下を扱います。
- チェックアウト
- Webhook
TanStack Start
完全なガイド:references/tanstack-start.md。
以下を扱います。
- チェックアウト
Bun
完全なガイド:references/bun.md。
以下を扱います。
- チェックアウトとポータル
Convex
完全なガイド:references/convex.md。
よくある間違い
-
POST ハンドラーの重複: Next.js と Astro のドキュメントには、
export const POSTの宣言が 2 つ記載されています。ルートごとにチェックアウトモードを 1 つ選ぶか、両者を振り分けるルーティングロジックを追加してください。 -
Webhook 変数名の誤り: アダプターが
DODO_PAYMENTS_WEBHOOK_KEYとDODO_PAYMENTS_WEBHOOK_SECRETのどちらを使用するか確認してください。ドキュメントには一貫性がないため、アダプターが実際に参照する名前を使用してください。 -
生のボディの保持忘れ: Webhook ハンドラーには、再解析された JSON オブジェクトではなく、リクエストの生のボディを渡す必要があります。Fastify では明示的な文字列ボディパーサーが必要ですが、ほかのフレームワークでは自動的に処理されます。例外は Express です。
Webhooksハンドラーは解析済みのreq.bodyを使って検証するため、ルートの前にexpress.json()を登録し、検証がすべて失敗する原因となるexpress.raw()は使用しないでください。Webhook の署名検証については、webhook-integrationスキルで説明しています。 -
フレームワークごとの規約の混同: 各フレームワークには、それぞれ異なるリクエスト/レスポンス形式があります。Next.js のハンドラーを Express で使用したり、その逆を行ったりしないでください。使用しているフレームワークに対応したアダプターを使ってください。
-
シークレットのハードコード: API キーと Webhook シークレットは、必ず環境変数から読み込み、コードや設定ファイルには記述しないでください。
-
環境設定の省略:
DODO_PAYMENTS_API_KEYとDODO_PAYMENTS_ENVIRONMENTがないと、アダプターは動作しません。テストの前に設定してください。 -
CustomerPortal の未認証公開: ポータルハンドラーは、リクエストに含まれる
?customer_id=を信頼します。上記の例のように、サーバー上でサインイン済みセッションから ID を取得してください。そうしないと、誰でも任意の顧客のポータルを開けてしまいます。 -
@dodopayments/coreの直接使用: core パッケージは内部依存関係であり、公開されているエントリーポイントとしてはドキュメント化されていません。使用するスタックに対応したフレームワークアダプターを使ってください。