testing-and-go-live について
Dodo Payments を組み込む開発者向けに、決済フローの検証と本番公開の準備方法を案内します。テスト環境と本番環境の分離、決済や Webhook のテスト、商品移行、公開前チェックを扱います。
主な機能
- 01テスト環境と本番環境の分離
- 02テストカードと地域別決済方法
- 03サブスクリプション更新のテスト
- 04Webhook のローカル受信と発火
- 05テスト商品を本番へ移行
- 06本番公開チェックリスト
活用シーン
- 01決済成功・拒否・更新失敗の検証
- 02ローカルやステージングでの Webhook テスト
- 03テストモードから本番への切り替え準備
- 04商品設定の本番環境への移行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dodopayments/ skills --skill testing-and-go-liveインストール後、Claude Code で/testing-and-go-liveを入力して読み込まれたか確認します。
詳細
テストと本番公開
このスキルでは、テストモード、テスト用の決済手段、Webhook テスト、本番公開チェックリストを扱います。本番公開前に検証が必要な決済フローを構築するときや、テスト環境から本番環境への切り替え準備をするときに使用してください。
このスキルを使用する場面
- カード決済の成功・拒否シナリオ、サブスクリプションの更新、または地域限定の決済手段をテストする必要がある。
- ローカル環境またはステージング環境で Webhook テストを設定する。
- 本番公開の準備をしていて、公開前チェックリストが必要である。
- テスト環境と本番環境が適切に分離されていることを確認したい。
- テスト環境から本番環境に商品をコピーする。
主な概念
テストモードと本番モード: Dodo Payments には、完全に分離された 2 つの環境があります。それぞれに独自のベース URL、API キー、Webhook、商品、顧客、取引があります。データは環境間で引き継がれません。
- テストモード:
https://test.dodopayments.com - 本番モード:
https://live.dodopayments.com
各環境には、ダッシュボードから発行される別々の API キーが必要です。SDK は environment を指定しない場合、デフォルトで live_mode を使用します。これは開発時に重大な問題を招く可能性があります。
テスト用決済手段: Dodo は、テスト用の特定のカード番号、VPA、決済手段のシナリオを提供しています。これらはテストモードでのみ機能します。
Webhook テスト: CLI には、ローカルで Webhook をリッスンし、実際の決済を行わずにテストイベントをトリガーするコマンドが用意されています。
テストモードの設定
開発中は必ず environment: 'test_mode' を明示的に設定してください。デフォルトは live_mode です。
import DodoPayments from 'dodopayments';
const client = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
environment: 'test_mode', // REQUIRED — defaults to 'live_mode'
});
import os
from dodopayments import DodoPayments
client = DodoPayments(
bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),
environment="test_mode", # defaults to "live_mode"
)
client := dodopayments.NewClient(
option.WithBearerToken("dodo_test_..."),
option.WithEnvironmentTestMode(), // defaults to WithEnvironmentLiveMode()
)
Dodo ダッシュボードからテスト用 API キーを取得してください。テスト用キーには dodo_test_ というプレフィックスが付きます。
テスト用決済手段
カード決済の成功・拒否シナリオ
テストモードで、以下のカード番号を有効期限 06/32(または 12/34)、CVV 123 とともに使用してください。
| シナリオ | カード番号 | 結果 |
|---|---|---|
| 成功 | 4242 4242 4242 4242 | 決済が成功します |
| 拒否 | 4000 0000 0000 0002 | 決済が拒否されます |
| 拒否(残高不足) | 4000 0000 0000 9995 | 残高不足エラーになります |
Dodo のテストプロセスページに記載されているカードのみを使用してください。その他の Stripe 形式のテスト用番号(たとえば「カード紛失」などのバリエーション)は、Dodo 向けには記載されていません。
サブスクリプション更新の失敗
サブスクリプション更新の失敗をテストするには、次のカードを使用してください。
| カード番号 | 有効期限 | CVV | 動作 |
|---|---|---|---|
4000 0000 0000 0341 | 12/34 | 123 | サブスクリプションの次回請求時(更新、アップグレード、またはダウングレード時)に拒否されます |
まず成功するカードでサブスクリプションを作成してから、Customer Portal でこのカードに支払い方法を切り替えてください。
UPI(インド)
次の VPA を使用して、UPI の成功と失敗をテストしてください。請求先の国は IN、通貨は INR である必要があります(インド国外の加盟店では Adaptive Currency も有効にする必要があります)。
| VPA | 結果 |
|---|---|
success@upi | 決済が成功します |
failure@upi | 決済が失敗します |
BNPL、ウォレット、地域限定の決済手段
BNPL、Apple Pay、Google Pay、ヨーロッパの決済手段(Giropay、iDEAL、Bancontact)はテストモードで利用できます。具体的なテストシナリオは決済手段によって異なります。最新のテスト一覧については、テストプロセスのドキュメントを参照してください。
サブスクリプション更新のテスト
待たずに特定の日付にサブスクリプションを更新させるには、next_billing_date を更新します。
await client.subscriptions.update('sub_123', {
next_billing_date: '2026-05-03T00:00:00Z',
});
client.subscriptions.update(
'sub_123',
next_billing_date='2026-05-03T00:00:00Z'
)
// NextBillingDate is param.Field[time.Time], not a string. Passing a string
// literal compiles to param.Field[string] and will not type-check.
client.Subscriptions.Update(ctx, "sub_123", dodopayments.SubscriptionUpdateParams{
NextBillingDate: dodopayments.F(time.Date(2026, time.May, 3, 0, 0, 0, 0, time.UTC)),
})
これにより、更新が直ちにスケジュールされます。サブスクリプション更新失敗用のカードを使用した場合、請求に失敗すると payment.failed が発行され、対象のサブスクリプションは on_hold に移行し、subscription.on_hold が発行されます。
Webhook テスト
CLI は SDK とは別に配布されています。
npm install -g dodopayments-cli
dodo login
dodo login は API Keys ページを開き、貼り付けたキーを受け付けて、それがテストモードか本番モードかを確認します。それぞれのモードのキーを 1 つずつ、同時に認証状態にしておくことができます。
Webhook をローカルでリッスンする
dodo wh listen http://localhost:3000/webhook
アウトバウンドリレーを介して、実際のテストモードのイベントをローカル URL に転送します。これはトンネルではありません。公開状態でリッスンすることはなく、ダッシュボードに貼り付ける URL も表示されません。登録可能な HTTPS URL が必要な場合は、代わりに ngrok を使用してください。その手順は webhook-integration スキルで説明されています。
実行前に確認しておくべき制約が 2 つあります。
- テストモードのキーが必要です。 リッスンのフローではライブモードのキーはサポートされていません。
- ダイレクトモードでは URL 引数が必要です。 引数なしの
dodo wh listenが使えるのは、インタラクティブ TUI 内で/wh listenとして実行した場合のみです。この場合、ウィザードが開きます。
この方法で届くイベントには有効な署名が付いているため、通常どおり webhooks.unwrap() で検証できます。
モックの webhook イベントをトリガーする
dodo wh trigger payment.success http://localhost:3000/webhook
指定したイベントの、実際のケースに即したモックペイロードを送信します。オフラインで実行でき、ログアウト中でも機能します。ここが重要なポイントです。これらのペイロードには署名がありません。 検証可能な有効な署名がないため、unwrap() は拒否します。
トリガーされたイベントに限り unsafeUnwrap() を使用してください。また、実際のトラフィックも受信するエンドポイントでは絶対に使用しないでください。トリガー名は <category>.<event> 形式です。例:payment.success、subscription.active、dispute.opened。
トリガー名とペイロードの type は常に一致するとは限りません。 payment.success は type: "payment.succeeded" を、refund.success は refund.succeeded を、licence.created は license_key.created を送信します。ハンドラーではペイロードの型で分岐してください。case 'payment.success' が一致することはありません。
listen と同様に、ダイレクトモードでは両方の引数が必要です。TUI 内で /wh trigger を実行すると、代わりにウィザードが開きます。
Webhook の署名検証
webhook-integration スキルで説明しています。テストモード、ライブモードを問わず、ネットワーク経由で届くすべての webhook を検証してください。唯一の例外は、上記の dodo wh trigger が生成する署名のないペイロードです。
テストモードからライブモードへの製品のコピー
製品は環境ごとに異なります。テスト用の製品 ID を本番環境で再利用することはできません。代わりに、ライブモードで製品を作り直すか、ダッシュボードからエクスポートして再インポートしてください。
手動で行う場合:
- テストモードで製品の詳細(名前、価格、税区分など)を控えます。
- 同じ設定でライブモードに新しい製品を作成します。
- 新しいライブ製品 ID を使うようにコードを更新します。
プログラムで行う場合:
テストモードから製品を取得し、その設定を抽出してライブモードで作成します。API キーはモードごとに異なります。テストキーでライブモードの認証はできず、その逆も同様です。そのため、異なる 2 つのキーが必要です。
// In test mode
const testClient = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_TEST_API_KEY,
environment: 'test_mode',
});
const testProduct = await testClient.products.retrieve('pdt_test_123');
// In live mode
const liveClient = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_LIVE_API_KEY,
environment: 'live_mode',
});
const liveProduct = await liveClient.products.create({
name: testProduct.name,
price: testProduct.price,
tax_category: testProduct.tax_category,
// ... other fields
});
本番移行チェックリスト
本番環境に切り替える前に、各項目を確認してください。
ビジネスとコンプライアンス
- Dodo ダッシュボードで KYC(顧客確認)が完了している。
- ビジネスの確認が承認されている。
- ダッシュボードのビジネス情報が正確である。
API とキー
- ダッシュボードからライブ API キーを取得している(
dodo_live_がプレフィックス)。 - 誤ってコミットしたテストキーをローテーションするか、無効化している。
- コードで
environment: 'live_mode'を使用している(またはライブモードがデフォルトのため省略している)。
Webhook
- webhook エンドポイントに HTTPS 経由でパブリックアクセスできる。
- ダッシュボードの webhook URL を本番ドメインに更新している。
- 環境変数の webhook シークレットを更新している。
- webhook ハンドラーで
client.webhooks.unwrap()またはstandardwebhooksパッケージを使って署名を検証している。 - 本番環境(またはライブキーを使用するステージング環境)で、webhook のフローをエンドツーエンドでテストしている。
製品とチェックアウト
- すべての製品をライブモードで作成している(テストモードからコピーしていない)。
- チェックアウトのコードでライブ製品 ID を使用している。
- リターン URL が本番ドメインを指している。
- 製品の税区分が正しい。
監視とサポート
- 決済の失敗、Webhook の配信、API エラーを監視する仕組みを整えています。
- Dodo ダッシュボードにアクセスして、取引と異議申し立てを確認する方法を把握しています。
- 返金とチャージバックに対応する計画を立てています。
よくある間違い
environment を設定し忘れる
SDK のデフォルトは live_mode です。開発中に environment: 'test_mode' を設定し忘れると、テストコードが本番環境に接続し、実際に請求が発生します。
// WRONG — this hits live mode
const client = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
});
// CORRECT
const client = new DodoPayments({
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
environment: 'test_mode',
});
テスト環境の商品 ID を本番環境で再利用する
テスト環境と本番環境は完全に分離されています。テストモードの商品 ID は、本番モードには存在しません。本番モードで新しい商品を必ず作成するか、ダッシュボードを使って移行してください。
// WRONG — pdt_test_123 does not exist in live mode
const session = await liveClient.checkoutSessions.create({
product_cart: [{ product_id: 'pdt_test_123', quantity: 1 }],
});
// CORRECT — use a live product ID
const session = await liveClient.checkoutSessions.create({
product_cart: [{ product_id: 'pdt_live_456', quantity: 1 }],
});
本番環境用の Webhook を再設定し忘れる
テストモードと本番モードでは、Webhook エンドポイントとシークレットが別々です。URL とシークレットを更新せずにテスト用の Webhook 設定を本番環境にコピーすると、Webhook の配信に失敗するか、誤った場所に送信されます。
- 本番環境の環境変数で
DODO_PAYMENTS_WEBHOOK_KEYを更新します。 - ダッシュボードで Webhook URL を本番ドメインに更新します。
- 本番環境で Webhook の配信をテストします。
本番環境で Webhook の署名を検証しない
client.webhooks.unwrap() または standardwebhooks パッケージを使って、必ず Webhook の署名を検証してください。Dodo から届いたものであっても、検証せずに Webhook を信頼してはいけません。
// WRONG — no verification
app.post('/webhook', (req, res) => {
const event = req.body;
handleEvent(event);
res.json({ received: true });
});
// CORRECT
app.post('/webhook', async (req, res) => {
try {
const unwrapped = client.webhooks.unwrap(req.body.toString(), {
headers: {
'webhook-id': req.headers['webhook-id'] as string,
'webhook-signature': req.headers['webhook-signature'] as string,
'webhook-timestamp': req.headers['webhook-timestamp'] as string,
},
});
handleEvent(unwrapped);
res.json({ received: true });
} catch (error) {
res.status(401).json({ error: 'Invalid signature' });
}
});
テスト用のキーと本番用のキーを混在させる
テスト用のキー(dodo_test_ が先頭に付くもの)は https://test.dodopayments.com でのみ使用できます。本番用のキーは、ダッシュボードからモードごとに発行されます。本番モードでテスト用のキーを使用すると、認証エラーが発生します。