Billing SDK/Billing SDK
Payment ProcessingPayment Failure

Payment Failure

A payment failure card that explains why a payment could not be processed, with actions to retry, go home, or contact support.

Playground
Payment Failed
We couldn't process your payment.

Common reasons for payment failure:

  • Insufficient funds in your account
  • Incorrect card details or expired card
  • Card declined by your bank
  • Network connection issues

Please check your payment details and try again, or contact your bank for more information.

src/components/payment-failure-demo.tsx
"use client";

import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { PaymentFailure } from "@/registry/billingsdk/payment-failure";

export function PaymentFailureDemo() {
  const [isRetrying, setIsRetrying] = useState(false);
  const router = useRouter();

  const handleRetry = async () => {
    setIsRetrying(true);

    try {
      // TODO: your actual retry logic (redirect to payment, call API, etc.)
      await new Promise((resolve) => setTimeout(resolve, 1500));
      // e.g. router.push("/checkout");
    } finally {
      setIsRetrying(false);
    }
  };

  return (
    <div className="bg-background flex min-h-screen items-center justify-center p-4">
      <PaymentFailure
        isRetrying={isRetrying}
        onRetry={handleRetry}
        onSecondary={() => router.push("/")}
        onTertiary={() => router.push("/support")}
        reasons={[
          "Insufficient funds in your account",
          "Incorrect card details or expired card",
          "Card declined by your bank",
          "Network connection issues",
        ]}
        // Optional overrides:
        // title="Payment declined"
        // subtitle="Your bank declined the transaction."
        // retryButtonText="Retry Payment"
        // secondaryButtonText="Go Home"
        // tertiaryButtonText="Contact Support"
      />
    </div>
  );
}

Installation

bash npx shadcn@latest add @billingsdk/payment-failure

bash pnpm dlx shadcn@latest add @billingsdk/payment-failure

bash yarn dlx shadcn@latest add @billingsdk/payment-failure

bash bunx shadcn@latest add @billingsdk/payment-failure

bash npx @billingsdk/cli add payment-failure

bash pnpm dlx @billingsdk/cli add payment-failure

bash yarn dlx @billingsdk/cli add payment-failure

bash bunx @billingsdk/cli add payment-failure

Usage

import { PaymentFailure } from "@/components/billingsdk/payment-failure";
// Controlled usage (recommended)
const [isRetrying, setIsRetrying] = useState(false);

async function handleRetry() {
  setIsRetrying(true);

  // Add your retry logic here (e.g., redirect to checkout or re-initiate payment)
  await new Promise((resolve) => setTimeout(resolve, 1500));

  setIsRetrying(false);
}

<PaymentFailure
  isRetrying={isRetrying}
  onRetry={handleRetry}
  onSecondary={() => router.push("/")}
  onTertiary={() => router.push("/support")}
/>;

Customizing text

<PaymentFailure
  title="Transaction Declined"
  subtitle="Your bank rejected the payment."
  message="Please try again or use a different payment method."
  retryButtonText="Retry Payment"
  secondaryButtonText="Go Home"
  tertiaryButtonText="Contact Support"
  onRetry={() => console.log("retry")}
  onSecondary={() => router.push("/")}
  onTertiary={() => router.push("/support")}
/>

Props

PropTypeRequiredDescription
titlestringOptional heading (default: "Payment Failed")
subtitlestringOptional subtext (default: "We couldn't process your payment.")
messagestringAdditional explanatory message displayed under the reasons list
reasonsstring[]List of possible failure reasons (defaults to common payment failure causes)
isRetryingbooleanShows loading state and disables retry button
retryButtonTextstringPrimary action label (default: "Try Again")
secondaryButtonTextstringSecondary button label (default: "Home")
tertiaryButtonTextstringTertiary button label (default: "Support")
onRetry() => voidCallback fired when user presses retry
onSecondary() => voidCallback fired when user presses the secondary action
onTertiary() => voidCallback fired when user presses tertiary action
classNamestringAdditional classes for styling / layout

Theming

This dialog inherits BillingSDK theme tokens via getThemeStyles, remaining consistent with other components. Colors adapt to light/dark modes and active theme.

Example

src/components/payment-failure-demo.tsx
"use client";

import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { PaymentFailure } from "@/registry/billingsdk/payment-failure";

export function PaymentFailureDemo() {
  const [isRetrying, setIsRetrying] = useState(false);
  const router = useRouter();

  const handleRetry = async () => {
    setIsRetrying(true);

    try {
      // TODO: your actual retry logic (redirect to payment, call API, etc.)
      await new Promise((resolve) => setTimeout(resolve, 1500));
      // e.g. router.push("/checkout");
    } finally {
      setIsRetrying(false);
    }
  };

  return (
    <div className="bg-background flex min-h-screen items-center justify-center p-4">
      <PaymentFailure
        isRetrying={isRetrying}
        onRetry={handleRetry}
        onSecondary={() => router.push("/")}
        onTertiary={() => router.push("/support")}
        reasons={[
          "Insufficient funds in your account",
          "Incorrect card details or expired card",
          "Card declined by your bank",
          "Network connection issues",
        ]}
        // Optional overrides:
        // title="Payment declined"
        // subtitle="Your bank declined the transaction."
        // retryButtonText="Retry Payment"
        // secondaryButtonText="Go Home"
        // tertiaryButtonText="Contact Support"
      />
    </div>
  );
}