メインコンテンツへスキップ
支払いが失敗したとき、Dodo Paymentsは標準化されたerror_codeと人間が読めるerror_messageによって理由を通知します。このガイドでは、これらのフィールドを読み取る方法、再試行する価値があるかどうかを判断し、顧客に機密情報を露出せずに支払いを回収する方法を示します。

Dodo Paymentsが報告する障害の方法

一度限りのチェックアウトかサブスクリプションの更新かに関わらず、すべての失敗した支払いには、支払いオブジェクトに同じ失敗フィールドが含まれています。
フィールド説明
statusstring失敗した支払いのfailed。他の非成功状態にはcancelledrequires_customer_actionrequires_payment_methodが含まれます。
error_codestring | null標準化された失敗の理由、例えばINSUFFICIENT_FUNDSPROCESSING_ERROR。完全なリストは取引失敗リファレンスを参照してください。
error_messagestring | null失敗の人間が読める説明。
retry_attemptinteger元の請求に対する01以上はスケジュールされたサブスクリプション更新の再試行を識別します。
error_codeerror_messageは支払いが実際に失敗するまでnullです。最初にstatusを常に確認し、次にエラーフィールドを読み取ります。

payment.failed Webhook

失敗を検出する最も信頼できる方法はpayment.failed webhookです。このイベントはdataにフル支払いオブジェクトをラップします。
payment.failed payload
{
  "business_id": "bus_P3SXLcppjXgagmHS",
  "type": "payment.failed",
  "timestamp": "2025-08-04T05:36:41.609359Z",
  "data": {
    "payload_type": "Payment",
    "payment_id": "pay_2IjeQm4hqU6RA4Z4kwDee",
    "status": "failed",
    "error_code": "PROCESSING_ERROR",
    "error_message": "An error occurred while processing your card. Try again in a little bit.",
    "retry_attempt": 0,
    "subscription_id": null,
    "currency": "USD",
    "total_amount": 400,
    "payment_method": "card",
    "card_last_four": "0119",
    "card_network": "VISA",
    "payment_link": "https://test.checkout.dodopayments.com/cbq",
    "customer": {
      "customer_id": "cus_8VbC6JDZzPEqfB",
      "email": "test@acme.com",
      "name": "Test user"
    }
  }
}
ミニマルハンドラーはerror_codeを読み取り、それにルートします。
import { Webhook } from "standardwebhooks";
import express from "express";

const app = express();
// Mount the raw body parser so the exact payload is available for verification
app.use(express.raw({ type: "application/json" }));

const webhook = new Webhook(process.env.DODO_PAYMENTS_WEBHOOK_KEY);

app.post("/webhooks/dodo", async (req, res) => {
  // Verify the signature against the raw body before trusting the payload
  const payload = req.body.toString();
  await webhook.verify(payload, req.headers);

  const event = JSON.parse(payload);

  if (event.type === "payment.failed") {
    const payment = event.data;

    console.log(
      `Payment ${payment.payment_id} failed: ${payment.error_code} (${payment.error_message})`
    );

    if (payment.subscription_id) {
      // Subscription renewal — Dodo retries soft declines for you
      await flagSubscriptionPaymentIssue(payment.subscription_id, payment.error_code);
    } else {
      // One-time payment — prompt the customer to try again
      await notifyCustomerOfFailedPayment(payment.customer.customer_id, payment.error_code);
    }
  }

  res.json({ received: true });
});
処理前にWebhookの署名を必ず検証してください。完全な設定には署名の検証と冪等性が含まれていますので、Webhookガイドを参照してください。

再試行するかどうかの決定:ソフト拒否とハード拒否

error_codeは、同じ支払い方法を再試行する価値があるかどうかを教えてくれます。
拒否タイプ意味すべきこと
ソフト拒否一時的または修正可能(例えばINSUFFICIENT_FUNDSPROCESSING_ERRORNETWORK_ERRORTRY_AGAIN_LATER)。顧客が入力を修正した後、遅延後に再試行すると成功する可能性があります。
ハード拒否終局的(例えばSTOLEN_CARDLOST_CARDDO_NOT_HONORFRAUDULENT)。同じカードを再試行しないでください。顧客に別の支払い方法を尋ねてください。
取引失敗リファレンスには、すべてのerror_codeの拒否タイプと推奨操作が記載されています。

チェックアウトでの失敗と更新時の失敗の処理

回収方法は、顧客がその場にいるかどうかによって異なります。
顧客が積極的にチェックアウトしています。明確なメッセージを表示し、すぐに再試行するか、別のカードを使用してもらいます。
  • requires_payment_method — 顧客が支払い方法を提供しなかった:カードの詳細を入力しなかったか、プロンプトが表示されたか、何の行動も取らなかった。これは通常、チェックアウトドロップオフであり、拒否ではありません — 顧客を再びエンゲージして支払いを完了させます(放棄されたカートの回収を参照してください)。
  • requires_customer_action — 追加の認証(例えば3DS)が必要です。顧客にそれを完了させます。3D Secureの処理を参照してください。

失敗した支払いの再試行

  • サブスクリプション: サブスクリプション支払い再試行を有効にし、統合作業なしでソフト拒否を回収します。また、顧客が支払い方法更新APIを通じて支払い方法を更新し、未払い金額を請求することで回収をトリガーすることもできます。
  • 一度限りの支払い: チェックアウトを再送信するかpayment_linkを実行し、顧客が別の方法で再試行できるようにします。一度限りの支払いに自動再試行はありません。
同じカードへのハード拒否を再試行しないでください。カードネットワークは繰り返される拒否を乱用として旗を立てる可能性があり、承認率に悪影響を与える可能性があります。

顧客へのエラーを安全に表示する

顧客にフレンドリーなメッセージを表示し、決して生のerror_codeを表示しないでください。
Customer-facing messaging
const CUSTOMER_MESSAGES = {
  INSUFFICIENT_FUNDS: "Your card has insufficient funds. Please use another card.",
  EXPIRED_CARD: "Your card has expired. Please use a card with a valid expiry date.",
  INCORRECT_CVC: "The security code (CVC) is incorrect. Please re-enter it.",
};

function customerMessage(errorCode) {
  // Sensitive declines must never reveal the real reason
  const SENSITIVE = ["STOLEN_CARD", "LOST_CARD", "PICKUP_CARD", "FRAUDULENT"];
  if (SENSITIVE.includes(errorCode)) {
    return "Your card was declined. Please contact your bank or use another card.";
  }
  return CUSTOMER_MESSAGES[errorCode] ?? "Your payment could not be processed. Please try another card.";
}
STOLEN_CARDLOST_CARDPICKUP_CARDFRAUDULENTの実際の理由を決して明らかにしないでください。 これらを表面化すると、不正なアクターへの警告となります。ジェネリックな拒否メッセージを表示し、特定のerror_codeは内部のみにログしてください。

関連情報

Transaction Failures

すべての拒否コード、そのタイプ、および推奨アクション。

Error Codes

カードの拒否でないAPIおよびビジネスロジックエラー。

Subscription Payment Retries

サブスクリプション更新でのソフト拒否の自動回復。

Subscription Dunning

ハード拒否を回収するメールシーケンス。

Payment Webhooks

支払いイベントのフルペイロードスキーマ。

Testing Failures

拒否と更新失敗をシミュレートするテストカード。
最終更新日 2026年6月18日