> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Subscription & Recurring

> Providing automated, high-success-rate billing solutions for recurring payment scenarios. Through a mechanism of one-time authorization and multiple automated deductions, we support flexible billing cycle configurations and smart retries.

export const CardGroup = ({children, cols = 2}) => {
  const items = Array.isArray(children) ? children.filter(Boolean) : [children];
  const layoutColumns = items.length === 3 ? 3 : cols === 1 ? 1 : 2;
  return <div className="waffo-guide-cards not-prose my-4 grid gap-4" data-columns={layoutColumns}>
      <style>{`
        .waffo-guide-cards {
          grid-template-columns: minmax(0, 1fr) !important;
        }
        .waffo-guide-cards .waffo-clickable-card {
          transition:
            transform 180ms ease,
            border-color 180ms ease,
            box-shadow 180ms ease,
            background 180ms ease !important;
        }
        html:not(.dark) .waffo-guide-cards .waffo-clickable-card:hover {
          border-color: rgba(109, 145, 245, 0.45) !important;
        }
        html.dark .waffo-guide-cards .waffo-clickable-card:hover,
        .dark .waffo-guide-cards .waffo-clickable-card:hover {
          border-color: rgba(109, 145, 245, 0.45) !important;
        }
        @media (min-width: 768px) {
          .waffo-guide-cards[data-columns="2"],
          .waffo-guide-cards[data-columns="3"] {
            grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
          }
          .waffo-guide-cards[data-columns="3"] .waffo-guide-card:nth-of-type(3) {
            grid-column: 1 / -1 !important;
          }
        }
      `}</style>
      {items}
    </div>;
};

export const Card = ({title, icon, href, children}) => {
  const resolvedHref = (() => {
    if (!href || typeof href !== "string") return href;
    if (!href.startsWith("/") || href.startsWith("//")) return href;
    if (typeof window === "undefined") return href;
    const docsPrefixMatch = window.location.pathname.match(/^\/docs(?=\/|$)/);
    const docsPrefix = docsPrefixMatch ? docsPrefixMatch[0] : "";
    if (!docsPrefix) {
      return href.startsWith("/docs/") ? href.slice(5) : href;
    }
    return href.startsWith(`${docsPrefix}/`) ? href : `${docsPrefix}${href}`;
  })();
  const Wrapper = resolvedHref ? "a" : "div";
  const interactiveClass = resolvedHref ? "waffo-clickable-card" : "";
  return <Wrapper href={resolvedHref} className={`waffo-guide-card waffo-hover-card block rounded-xl border border-slate-200 dark:border-neutral-700 bg-gradient-to-b from-slate-50 to-white dark:from-neutral-900 dark:to-neutral-950 p-6 no-underline ${interactiveClass}`}>
      <div className="flex flex-col items-start gap-3">
        <span className="inline-flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 dark:border-neutral-700 bg-white dark:bg-neutral-900 text-blue-700 dark:text-[#4D7CFF]">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            {icon === "arrow-right" && <path d="M5 12h14M13 5l7 7-7 7" />}
            {icon === "bell" && <path d="M10 21h4M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9" />}
            {icon === "code" && <>
                <path d="m16 18 6-6-6-6" />
                <path d="m8 6-6 6 6 6" />
              </>}
            {icon === "globe" && <>
                <circle cx="12" cy="12" r="10" />
                <path d="M2 12h20" />
                <path d="M12 2a15.3 15.3 0 0 1 0 20" />
                <path d="M12 2a15.3 15.3 0 0 0 0 20" />
              </>}
            {icon === "gear" && <>
                <circle cx="12" cy="12" r="3" />
                <path d="M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.6V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.6 1.7 1.7 0 0 0-1.9.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.9 1.7 1.7 0 0 0-1.6-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.6-1 1.7 1.7 0 0 0-.3-1.9l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.9.3H9a1.7 1.7 0 0 0 1-1.6V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.6 1.7 1.7 0 0 0 1.9-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.9v.1a1.7 1.7 0 0 0 1.6 1h.1a2 2 0 1 1 0 4H21a1.7 1.7 0 0 0-1.6 1Z" />
              </>}
            {icon === "shield-check" && <>
                <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z" />
                <path d="m9 12 2 2 4-4" />
              </>}
            {icon === "circle-check" && <>
                <circle cx="12" cy="12" r="10" />
                <path d="m9 12 2 2 4-4" />
              </>}
            {icon === "arrow-trend-up" && <path d="m3 17 6-6 4 4 8-8M14 7h7v7" />}
            {icon === "arrows-rotate" && <>
                <path d="M21 12a9 9 0 0 1-15.5 6.2" />
                <path d="M3 12A9 9 0 0 1 18.5 5.8" />
                <path d="M21 3v6h-6" />
                <path d="M3 21v-6h6" />
              </>}
            {icon === "calendar" && <>
                <rect x="3" y="4" width="18" height="17" rx="2" />
                <path d="M16 2v4M8 2v4M3 10h18" />
              </>}
            {icon === "clock" && <>
                <circle cx="12" cy="12" r="10" />
                <path d="M12 6v6l4 2" />
              </>}
            {icon === "desktop" && <>
                <rect x="3" y="4" width="18" height="12" rx="2" />
                <path d="M8 20h8M12 16v4" />
              </>}
            {icon === "calculator" && <>
                <rect x="5" y="2" width="14" height="20" rx="2" />
                <path d="M8 6h8M8 10h.01M12 10h.01M16 10h.01M8 14h.01M12 14h.01M16 14h.01M8 18h.01M12 18h.01M16 18h.01" />
              </>}
            {icon === "plug" && <>
                <path d="M12 22v-5" />
                <path d="M9 8V2" />
                <path d="M15 8V2" />
                <path d="M18 8v5a6 6 0 0 1-12 0V8Z" />
              </>}
            {icon === "gauge" && <>
                <path d="M12 14l4-4" />
                <path d="M3.3 19a10 10 0 1 1 17.4 0" />
              </>}
            {icon === "layer-group" && <>
                <path d="m12 3 9 5-9 5-9-5 9-5Z" />
                <path d="m3 12 9 5 9-5" />
                <path d="m3 16 9 5 9-5" />
              </>}
            {icon === "laptop-mobile" && <>
                <rect x="3" y="4" width="13" height="10" rx="2" />
                <path d="M2 18h12" />
                <rect x="17" y="8" width="5" height="12" rx="1" />
              </>}
            {icon === "paintbrush" && <>
                <path d="m14 5 5 5" />
                <path d="M4 20c2 0 4-1 4-3 0-1.1-.9-2-2-2-2 0-3 2-3 4 0 .6.4 1 1 1Z" />
                <path d="m6 15 9-9a2.1 2.1 0 0 1 3 3l-9 9" />
              </>}
            {icon === "key" && <>
                <circle cx="7.5" cy="14.5" r="4.5" />
                <path d="m11 11 8-8" />
                <path d="m15 7 2 2" />
              </>}
            {icon === "circle-minus" && <>
                <circle cx="12" cy="12" r="10" />
                <path d="M8 12h8" />
              </>}
            {icon === "wallet" && <>
                <path d="M3 7h15a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H3Z" />
                <path d="M3 7V5a2 2 0 0 1 2-2h11" />
                <path d="M16 14h.01" />
              </>}
            {icon === "users" && <>
                <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
                <circle cx="9" cy="7" r="4" />
                <path d="M22 21v-2a4 4 0 0 0-3-3.9" />
                <path d="M16 3.1a4 4 0 0 1 0 7.8" />
              </>}
            {icon === "link" && <>
                <path d="M10 13a5 5 0 0 0 7.1 0l2-2a5 5 0 0 0-7.1-7.1l-1.1 1.1" />
                <path d="M14 11a5 5 0 0 0-7.1 0l-2 2a5 5 0 0 0 7.1 7.1l1.1-1.1" />
              </>}
            {icon === "eye" && <>
                <path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z" />
                <circle cx="12" cy="12" r="3" />
              </>}
            {icon === "file-lines" && <>
                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
                <path d="M14 2v6h6" />
                <path d="M8 13h8M8 17h6" />
              </>}
            {icon === "sliders" && <>
                <path d="M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3" />
                <path d="M2 14h4M10 8h4M18 16h4" />
              </>}
            {icon === "folder" && <path d="M3 6a2 2 0 0 1 2-2h5l2 2h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z" />}
            {icon === "dollar-sign" && <>
                <path d="M12 2v20" />
                <path d="M17 5H9.5a3.5 3.5 0 0 0 0 7H14a3.5 3.5 0 0 1 0 7H6" />
              </>}
            {icon === "toggle-on" && <>
                <rect x="2" y="7" width="20" height="10" rx="5" />
                <circle cx="16" cy="12" r="3" />
              </>}
            {icon === "infinity" && <path d="M18.2 8.2c2.1 0 3.8 1.7 3.8 3.8s-1.7 3.8-3.8 3.8c-4.2 0-8.2-7.6-12.4-7.6C3.7 8.2 2 9.9 2 12s1.7 3.8 3.8 3.8c4.2 0 8.2-7.6 12.4-7.6Z" />}
            {icon === "book-open" && <>
                <path d="M2 4h7a3 3 0 0 1 3 3v14a3 3 0 0 0-3-3H2Z" />
                <path d="M22 4h-7a3 3 0 0 0-3 3v14a3 3 0 0 1 3-3h7Z" />
              </>}
            {icon === "circle-play" && <>
                <circle cx="12" cy="12" r="10" />
                <path d="m10 8 6 4-6 4Z" />
              </>}
            {icon === "gamepad" && <>
                <rect x="3" y="8" width="18" height="10" rx="5" />
                <path d="M8 13h3M9.5 11.5v3M16 13h.01M18 11h.01" />
              </>}
            {icon === "rocket" && <>
                <path d="M4.5 16.5c-1.5 1.3-2 3.5-2 5 1.5 0 3.7-.5 5-2" />
                <path d="M9 15 4 10l6-6c4-4 9-2 10-1 1 1 3 6-1 10l-6 6-5-5Z" />
                <path d="M15 9h.01" />
              </>}
            {(icon === "flask" || icon === "flask-vial") && <>
                <path d="M9 2v6L4 20a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2L15 8V2" />
                <path d="M8 2h8" />
                <path d="M7 16h10" />
              </>}
            {icon === "credit-card" && <>
                <rect x="3" y="5" width="18" height="14" rx="2" />
                <path d="M3 10h18" />
                <path d="M7 15h4" />
              </>}
            {icon === "puzzle-piece" && <path d="M14 7V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v3H3a1 1 0 0 0-1 1v4a2 2 0 0 0 2 2h2v3a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-3h3a2 2 0 0 0 2-2V8a1 1 0 0 0-1-1Z" />}
            {(icon === "arrows-spin" || icon === "repeat") && <>
                <path d="M17 2l4 4-4 4" />
                <path d="M3 11V9a4 4 0 0 1 4-4h14" />
                <path d="M7 22l-4-4 4-4" />
                <path d="M21 13v2a4 4 0 0 1-4 4H3" />
              </>}
            {icon === "coins" && <>
                <ellipse cx="8" cy="7" rx="5" ry="3" />
                <path d="M3 7v6c0 1.7 2.2 3 5 3s5-1.3 5-3V7" />
                <path d="M13 10c2.8 0 5 1.3 5 3v4c0 1.7-2.2 3-5 3-1.2 0-2.3-.2-3.1-.7" />
              </>}
            {icon === "triangle-exclamation" && <>
                <path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3Z" />
                <path d="M12 9v4M12 17h.01" />
              </>}
            {icon === "list" && <>
                <path d="M8 6h13M8 12h13M8 18h13" />
                <path d="M3 6h.01M3 12h.01M3 18h.01" />
              </>}
            {icon === "star" && <path d="m12 2 3.1 6.3 6.9 1-5 4.9 1.2 6.8-6.2-3.3L5.8 21 7 14.2 2 9.3l6.9-1Z" />}
            {(icon === "rotate" || icon === "arrow-rotate-left") && <>
                <path d="M3 12a9 9 0 1 0 3-6.7" />
                <path d="M3 4v6h6" />
              </>}
            {icon === "clock-rotate-left" && <>
                <path d="M3 12a9 9 0 1 0 3-6.7" />
                <path d="M3 4v6h6" />
                <path d="M12 7v5l3 2" />
              </>}
            {icon === "circle-xmark" && <>
                <circle cx="12" cy="12" r="10" />
                <path d="m15 9-6 6M9 9l6 6" />
              </>}
            {icon === "paper-plane" && <path d="m22 2-7 20-4-9-9-4Z" />}
            {icon === "signal" && <>
                <path d="M2 20h.01M7 20v-4M12 20v-8M17 20V8M22 20V4" />
              </>}
            {icon === "circle-question" && <>
                <circle cx="12" cy="12" r="10" />
                <path d="M9.1 9a3 3 0 1 1 5.8 1c0 2-3 2-3 4" />
                <path d="M12 17h.01" />
              </>}
            {icon === "palette" && <>
                <path d="M12 22a10 10 0 1 1 7.5-3.4c-.9 1-2.4.4-2.4-.9 0-1.1-.9-2-2-2h-1.4c-1.2 0-2.2 1-2.2 2.2 0 1.1.9 2.1 2.1 2.1" />
                <circle cx="7.5" cy="10.5" r=".8" />
                <circle cx="12" cy="7.5" r=".8" />
                <circle cx="16.5" cy="10.5" r=".8" />
              </>}
            {(!icon || !["arrow-right", "bell", "code", "globe", "gear", "shield-check", "circle-check", "arrow-trend-up", "arrows-rotate", "calendar", "clock", "desktop", "calculator", "plug", "gauge", "layer-group", "laptop-mobile", "paintbrush", "key", "circle-minus", "wallet", "users", "link", "eye", "file-lines", "sliders", "folder", "dollar-sign", "toggle-on", "infinity", "book-open", "circle-play", "gamepad", "rocket", "flask", "flask-vial", "credit-card", "puzzle-piece", "arrows-spin", "repeat", "coins", "triangle-exclamation", "list", "star", "rotate", "arrow-rotate-left", "clock-rotate-left", "circle-xmark", "paper-plane", "signal", "circle-question", "palette"].includes(icon)) && <path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z" />}
          </svg>
        </span>
        <div className="flex flex-col gap-2">
          <h4 className="m-0 text-base font-semibold text-slate-900 dark:text-slate-100">
            {title}
          </h4>
          <div className="m-0 text-sm leading-6 text-slate-600 dark:text-slate-300">
            {children}
          </div>
        </div>
      </div>
    </Wrapper>;
};

export const PM = {
  VISA: {
    alt: "Visa",
    src: "https://cdn.waffo.com/payment-method/PMI_CC001.png"
  },
  MASTERCARD: {
    alt: "Mastercard",
    src: "https://cdn.waffo.com/payment-method/PMI_CC008.png"
  },
  JCB: {
    alt: "JCB",
    src: "https://cdn.waffo.com/payment-method/PMI_CC068.png"
  },
  UNIONPAY: {
    alt: "UnionPay",
    src: "https://cdn.waffo.com/payment-method/PMI_CC762.png"
  },
  AMEX: {
    alt: "American Express",
    src: "https://cdn.waffo.com/payment-method/PMI_CC015.png"
  },
  BANCONTACT: {
    alt: "Bancontact",
    src: "/images/essentials/one-time-payment/bancontact-logo.svg"
  },
  APPLE_PAY: {
    alt: "Apple Pay",
    src: "https://cdn-dev.waffo.com/payment-method/PMI_155.png"
  },
  GOOGLE_PAY: {
    alt: "Google Pay",
    src: "https://cdn-dev.waffo.com/payment-method/PMI_161.png"
  },
  WECHAT_PAY: {
    alt: "WeChat Pay",
    src: "https://cdn.waffo.com/payment-method/PMI_170.png"
  },
  ALIPAY: {
    alt: "Alipay",
    src: "https://cdn.waffo.com/payment-method/PMI_168.png"
  },
  DANA: {
    alt: "DANA",
    src: "https://cdn.waffo.com/payment-method/PMI_001.png"
  },
  PAYPAY: {
    alt: "PayPay",
    src: "https://cdn.waffo.com/payment-method/PMI_247.png"
  },
  ZALOPAY: {
    alt: "ZaloPay",
    src: "https://cdn.waffo.com/payment-method/PMI_084.png"
  },
  PIX: {
    alt: "PIX",
    src: "https://cdn.waffo.com/payment-method/PMI_040.png"
  },
  BANK_LOCAL_SEPA: {
    alt: "SEPA",
    src: "/images/essentials/one-time-payment/SEPA.png"
  },
  BANK_LOCAL_IDEAL: {
    alt: "iDEAL",
    src: "/images/essentials/one-time-payment/ideal.png"
  },
  BANK_LOCAL_BANCONTACT: {
    alt: "Bancontact",
    src: "/images/essentials/one-time-payment/Bancontact.png"
  },
  BANK_LOCAL_MORE: {
    alt: "More payment methods",
    src: "/images/essentials/one-time-payment/Payment%20logo.png"
  },
  LOCAL_PAYMENT: {
    alt: "Local Payment",
    src: "/images/essentials/one-time-payment/bank-transfer-2.svg"
  }
};

export const CheckoutFeatures = ({scenarioLabel = "Scenario:", scenarioText = ""}) => {
  const [language, setLanguage] = useState("en");
  useEffect(() => {
    const pathname = window.location.pathname;
    if (pathname.startsWith("/zh/")) setLanguage("zh"); else if (pathname.startsWith("/ja/")) setLanguage("ja"); else setLanguage("en");
  }, []);
  const alt = {
    en: {
      checkout: "Hosted checkout: users are redirected to Waffo's secure checkout page to complete the initial signing payment",
      seamless: "Seamless handling for zero-amount authorization and first-period payment logic",
      customization: "Checkout customization: supports brand logo and payment page colors"
    },
    zh: {
      checkout: "托管收银台：用户跳转到 Waffo 安全收银台完成首次签约支付",
      seamless: "无缝处理零金额预授权和首期扣款逻辑",
      customization: "收银台品牌定制：支持品牌 Logo 和页面颜色配置"
    },
    ja: {
      checkout: "ホスト型Checkout: ユーザーはWaffoの安全なCheckoutページで初回契約決済を完了します",
      seamless: "ゼロ金額承認と初回決済ロジックをシームレスに処理します",
      customization: "Checkoutのブランドカスタマイズ: ロゴとページカラーに対応します"
    }
  };
  const copy = alt[language] || alt.en;
  return <div className="not-prose mt-4 flex flex-col gap-3">
      {scenarioText && <p className="mb-1 text-sm leading-6 text-slate-500 dark:text-slate-300">
          <span className="font-semibold text-slate-700 dark:text-slate-100">
            {scenarioLabel}
          </span>{" "}
          {scenarioText}
        </p>}

      <div className="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-neutral-700 dark:bg-neutral-900">
        <img src="/images/essentials/subscription-recurring/checkout-integration/panel-checkout.png?v=20260429-1618" alt={copy.checkout} className="my-0 block w-full" />
      </div>

      <div className="grid gap-3 md:grid-cols-2">
        <div className="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-neutral-700 dark:bg-neutral-900">
          <img src="/images/essentials/subscription-recurring/checkout-integration/panel-seamless.png?v=20260429-1618" alt={copy.seamless} className="my-0 block w-full" />
        </div>
        <div className="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-neutral-700 dark:bg-neutral-900">
          <img src="/images/essentials/subscription-recurring/checkout-integration/panel-customization.png?v=20260429-1618" alt={copy.customization} className="my-0 block w-full" />
        </div>
      </div>
    </div>;
};

export const SubscriptionModelsTable = () => {
  const getCurrentLanguage = () => {
    if (typeof window === "undefined") return "en";
    const pathname = window.location.pathname.replace(/^\/docs(?=\/|$)/, "");
    const firstSegment = pathname.split("/").filter(Boolean)[0];
    const htmlLanguage = document.documentElement.lang?.toLowerCase() || "";
    if (firstSegment === "zh" || htmlLanguage.startsWith("zh")) return "zh";
    if (firstSegment === "ja" || htmlLanguage.startsWith("ja")) return "ja";
    return "en";
  };
  const [isDark, setIsDark] = useState(false);
  const [language, setLanguage] = useState(getCurrentLanguage);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  useEffect(() => {
    setLanguage(getCurrentLanguage());
  }, []);
  const copy = {
    en: {
      mechanism: "Mechanism",
      bestFor: "Best for",
      models: [{
        label: "A",
        name: "Service-First",
        tagline: "Prioritize service continuity; tolerate payment latency.",
        gradientFrom: "rgba(25,87,255,0.12)",
        badgeDarkBg: "#172554",
        badgeDarkBorder: "#1d4ed8",
        mechanism: 'If the current deduction fails, the service is not interrupted. The next deduction is created as planned; "concurrent billing cycles" (accumulated bills) are allowed.',
        bestFor: "Video streaming, SaaS software, and services focused on user retention."
      }, {
        label: "B",
        name: "Payment-First",
        tagline: 'Strictly "pay before service"; zero tolerance for arrears.',
        gradientFrom: "rgba(65,183,163,0.12)",
        badgeDarkBg: "#064e3b",
        badgeDarkBorder: "#047857",
        mechanism: "If the current deduction fails, service is suspended and future billing tasks pause until payment succeeds.",
        bestFor: "Physical subscription boxes, game items, and cost-sensitive businesses."
      }]
    },
    zh: {
      mechanism: "扣款机制",
      bestFor: "适用场景",
      models: [{
        label: "A",
        name: "服务优先型",
        tagline: "优先保障服务连续性；可容忍扣款延迟。",
        gradientFrom: "rgba(25,87,255,0.12)",
        badgeDarkBg: "#172554",
        badgeDarkBorder: "#1d4ed8",
        mechanism: "当期扣款失败时，服务不中断。下期扣款按原计划创建，并允许“多期账单并存”。",
        bestFor: "视频流媒体、SaaS 软件，以及更关注用户留存的服务。"
      }, {
        label: "B",
        name: "支付优先型",
        tagline: "严格遵循“先付款后服务”；零欠费容忍。",
        gradientFrom: "rgba(65,183,163,0.12)",
        badgeDarkBg: "#064e3b",
        badgeDarkBorder: "#047857",
        mechanism: "当前周期扣款失败时立即暂停服务，并停止生成后续扣款任务，直到支付成功。",
        bestFor: "实物订阅盒、游戏道具，以及成本敏感型业务。"
      }]
    },
    ja: {
      mechanism: "仕組み",
      bestFor: "適した用途",
      models: [{
        label: "A",
        name: "サービス優先型",
        tagline: "サービス継続を優先し、決済遅延を許容します。",
        gradientFrom: "rgba(25,87,255,0.12)",
        badgeDarkBg: "#172554",
        badgeDarkBorder: "#1d4ed8",
        mechanism: "当期の引き落としに失敗してもサービスは中断されません。次回の引き落としは予定どおり作成され、複数の請求が並存することを許容します。",
        bestFor: "動画配信、SaaS ソフトウェア、ユーザー維持を重視するサービス。"
      }, {
        label: "B",
        name: "決済優先型",
        tagline: "「支払い後にサービス提供」を厳格に適用し、未払いを許容しません。",
        gradientFrom: "rgba(65,183,163,0.12)",
        badgeDarkBg: "#064e3b",
        badgeDarkBorder: "#047857",
        mechanism: "当期の引き落としに失敗した場合、サービスを停止し、支払いが成功するまで後続の請求タスクも停止します。",
        bestFor: "物理的なサブスクリプションボックス、ゲームアイテム、コスト感度の高い事業。"
      }]
    }
  };
  const content = copy[language] || copy.en;
  return <div className="flex flex-col gap-6 w-full mt-2 md:flex-row">
      {content.models.map(m => <div key={m.label} className="waffo-hover-card subscription-model-card flex-1 flex flex-col rounded-xl border border-slate-200 dark:border-neutral-700 overflow-hidden" style={{
    background: `linear-gradient(to bottom, ${m.gradientFrom} 0%, rgba(255,255,255,0) 100%)`
  }}>
          <div className="flex flex-col gap-3 px-6 pt-6 pb-4">
            <div className="flex items-center gap-2">
              <div className="w-[42px] h-[42px] rounded-full border flex items-center justify-center text-white font-semibold text-base shrink-0" style={{
    backgroundColor: isDark ? m.badgeDarkBg : "#0f172a",
    borderColor: isDark ? m.badgeDarkBorder : "transparent"
  }}>
                {m.label}
              </div>
              <span className="text-slate-900 dark:text-slate-100 font-semibold text-lg">
                {m.name}
              </span>
            </div>
            <p className="text-slate-500 dark:text-slate-300 text-sm leading-5">{m.tagline}</p>
          </div>
          <div className="flex flex-col gap-4 mx-4 mb-6 px-5 py-4 rounded-xl border border-white dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80">
            <div className="flex flex-col gap-1">
              <p className="text-slate-900 dark:text-slate-100 font-semibold text-sm">{content.mechanism}</p>
              <p className="text-slate-500 dark:text-slate-300 text-sm leading-5">{m.mechanism}</p>
            </div>
            <div className="flex flex-col gap-1">
              <p className="text-slate-900 dark:text-slate-100 font-semibold text-sm">{content.bestFor}</p>
              <p className="text-slate-500 dark:text-slate-300 text-sm leading-5">{m.bestFor}</p>
            </div>
          </div>
        </div>)}
    </div>;
};

## Overview

Providing automated, high-success-rate billing solutions for recurring payment scenarios. Through a mechanism of "one-time authorization, multiple automated deductions," we support flexible billing cycle configurations and smart retries. This helps merchants achieve sustained growth in subscription revenue while optimizing the user experience.

<div className="flex gap-4 mt-2 mb-2">
  <a href="/api-reference/introduction" className="inline-flex items-center gap-2 px-6 py-2 rounded-lg text-white text-base font-medium no-underline bg-primary hover:opacity-90">
    Start Integration →
  </a>

  <a href="mailto:support@waffo.com" className="inline-flex items-center px-4 py-2 rounded-lg border border-slate-200 bg-white text-slate-600 text-base font-medium no-underline hover:bg-slate-50 dark:border-neutral-700 dark:bg-neutral-800 dark:text-slate-300 dark:hover:bg-neutral-700">
    Contact Sales
  </a>
</div>

***

## What is Subscription Payment?

**Subscription Payment**, also known as automatic billing or recurring billing, is a payment model where users sign an agreement/authorization during the initial payment, and the system automatically initiates deductions based on an agreed cycle (e.g., weekly/monthly/yearly).

By automating the "payment action," it significantly reduces the friction of renewal operations, serving as the core infrastructure for SaaS services, streaming memberships, and content monetization businesses.

## Core capabilities

<CardGroup cols={2}>
  <Card title="Flexible Billing Cycles" icon="calendar">
    Supports standard (weekly, monthly, quarterly, yearly) and custom day intervals to meet diverse business needs.
  </Card>

  <Card title="Smart Retry Mechanism" icon="rotate-right">
    Built-in configurable retry strategies (e.g., 24h/48h intervals) that optimize success rates through detailed failure code analysis.
  </Card>

  <Card title="Full Lifecycle Management" icon="clock">
    Provides complete management capabilities from subscription creation, trial periods (free/discounted), automatic deductions, and upgrades/downgrades, to cancellation.
  </Card>

  <Card title="Account Updater" icon="arrows-rotate">
    Integrated with VAU/ABU services. When a user's card expires or is replaced, card information is automatically updated to maintain subscription continuity.
  </Card>
</CardGroup>

***

## Use cases

<CardGroup cols={2}>
  <Card title="Streaming Services" icon="circle-play">
    Monthly/Annual auto-renewal for video and music platforms.
  </Card>

  <Card title="SaaS Software" icon="desktop">
    Periodic subscription billing for office tools and productivity software.
  </Card>

  <Card title="Content Monetization" icon="book-open">
    Membership services for knowledge columns and online courses.
  </Card>

  <Card title="Gaming Subscriptions" icon="gamepad">
    Auto-renewal for monthly passes, season passes, and game items.
  </Card>
</CardGroup>

***

## Supported payment methods

Through Waffo, you can access mainstream payment methods that support "Credentials on File" and "Merchant Initiated Transactions (MIT)."

**Bank Cards (Credit/Debit Cards)**

<div className="flex flex-wrap gap-2 p-4 border border-slate-200 dark:border-neutral-700 rounded-xl bg-gradient-to-t from-slate-50 to-white dark:from-neutral-900 dark:to-neutral-800 mb-4">
  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.JCB.src} alt={PM.JCB.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>

  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.VISA.src} alt={PM.VISA.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>

  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.MASTERCARD.src} alt={PM.MASTERCARD.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>
</div>

Key security features for bank cards:

* **Tokenization Security** — A token is created upon the first payment. Subsequent deductions use MIT (Merchant Initiated Transaction) mode, requiring no CVV re-entry.
* **3DS Smart Verification** — Mandatory 3DS verification for the initial signing ensures legal authorization, while subsequent auto-debits are exempted to balance security and experience.
* **Auto-Update** — Supports VAU (Visa Account Updater) and ABU (Automatic Billing Updater).

**Digital Wallets**

<div className="flex flex-wrap gap-2 p-4 border border-slate-200 dark:border-neutral-700 rounded-xl bg-gradient-to-t from-slate-50 to-white dark:from-neutral-900 dark:to-neutral-800 mb-4">
  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.APPLE_PAY.src} alt={PM.APPLE_PAY.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>

  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.GOOGLE_PAY.src} alt={PM.GOOGLE_PAY.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>
</div>

* **Native Experience** — Utilize device biometrics for the initial authorization, providing a frictionless user experience.
* **Token Status Awareness** — Receive real-time notifications on token status changes (e.g., updates, suspensions, restorations) to maintain subscription continuity.

**Local Payment Methods**

<div className="flex flex-wrap gap-2 p-4 border border-slate-200 dark:border-neutral-700 rounded-xl bg-gradient-to-t from-slate-50 to-white dark:from-neutral-900 dark:to-neutral-800 mb-4">
  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.PAYPAY.src} alt={PM.PAYPAY.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>

  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.PIX.src} alt={PM.PIX.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>

  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.ZALOPAY.src} alt={PM.ZALOPAY.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>

  <span className="inline-flex items-center justify-center w-[42px] h-7 border border-slate-200 dark:border-neutral-300 rounded bg-white dark:bg-white">
    <img src={PM.DANA.src} alt={PM.DANA.alt} style={{width:"auto", height:"100%", objectFit:"contain"}} />
  </span>
</div>

Supports subscription binding and auto-debit capabilities, aligning with local user habits.

[View full list of supported payment methods →](/en/essentials/payment-methods)

***

## Subscription models & experience

Waffo Subscription Payment offers flexible business model configurations to adapt to different commercial strategies.

### Core business models

You can select the subscription model via the Dashboard or API:

<SubscriptionModelsTable />

***

## Trial & promotion configuration

<div className="bg-slate-50 dark:bg-neutral-900 border-l-4 border-slate-400 dark:border-blue-500 px-6 py-4 mb-3 rounded-r-lg">
  <p className="text-slate-900 dark:text-slate-100 font-medium mb-1 mt-0">Free Trials</p>
  <p className="text-slate-600 dark:text-slate-300 text-sm my-0">Supports 0-amount pre-authorization (immediately reversed after verifying card validity) to lower the barrier to entry.</p>
</div>

<div className="bg-slate-50 dark:bg-neutral-900 border-l-4 border-slate-400 dark:border-blue-500 px-6 py-4 rounded-r-lg">
  <p className="text-slate-900 dark:text-slate-100 font-medium mb-1 mt-0">Discounted Trials</p>
  <p className="text-slate-600 dark:text-slate-300 text-sm my-0">Supports setting special prices for the first N periods, automatically reverting to the original price thereafter.</p>
</div>

***

## Deduction & retry logic

The system automatically handles the billing flow to maximize success and minimize manual intervention.

**Billing Flow**

<Steps>
  <Step title="Expiry Detection">
    The system detects when a billing cycle is due and prepares the deduction task.
  </Step>

  <Step title="Generate MIT Order">
    A Merchant Initiated Transaction order is created using the stored payment credentials.
  </Step>

  <Step title="Initiate Deduction">
    The deduction is submitted to the payment network for processing.
  </Step>

  <Step title="Success notification / Failure retry">
    On success, a confirmation notification is sent. On failure, the retry strategy is triggered.
  </Step>
</Steps>

<Danger>
  **Failure Handling**
  <p>Default strategy retries 24 hours after failure, and again 48 hours later (parameters configurable). Supports triggering automatic payment failure notifications via email to guide users to update their payment method.</p>
</Danger>

***

## Integration

We provide multiple integration methods to help you seamlessly embed subscription capabilities into your business system.

### Hosted checkout

<CheckoutFeatures scenarioLabel="Scenario:" scenarioText="Teams with limited development resources who need to launch subscription features quickly." />

### API integration

<CardGroup cols={1}>
  <Card title="Best for" icon="code">
    Large enterprises requiring deep UI customization or specific business logic.
  </Card>
</CardGroup>

The following core APIs are available for subscription management:

| Endpoint                           | Description                                  |
| ---------------------------------- | -------------------------------------------- |
| `POST /api/v1/subscription/create` | Create subscription order, initiate signing. |
| `POST /api/v1/subscription/cancel` | Cancel subscription.                         |
| `POST /api/v1/subscription/change` | Support plan upgrades/downgrades.            |

Complete control over the frontend interaction flow; use Webhooks to handle subsequent logic.

[View Subscription Payment API documentation →](/api-reference/introduction)

***

## Security & compliance

Waffo follows global financial data security standards to ensure the safety of recurring billing.

<CardGroup cols={3}>
  <Card title="Tokenized storage" icon="shield-check">
    User card numbers are encrypted and stored. All recurring deductions are based on tokens, reducing the risk of data leakage.
  </Card>

  <Card title="Compliant transaction tagging" icon="badge-check">
    Strictly follows card scheme regulations by distinguishing between CIT (Customer Initiated) and MIT (Merchant Initiated) transaction tags to ensure deductions are compliant and success rates meet expectations.
  </Card>

  <Card title="Risk control" icon="shield-exclamation">
    Built-in risk rules to intercept high-frequency trial abuse and abnormal high-value subscriptions in real-time.
  </Card>
</CardGroup>

***

## Frequently asked questions

<AccordionGroup>
  <Accordion title="What is 0-amount pre-authorization?">
    For "Free Trial" scenarios, the system needs to verify the validity of the payment method. We initiate a 0-amount pre-authorization (Verify). If certain banks do not support this, the system automatically degrades to a low-amount (e.g., 1 unit) authorization and immediately voids/reverses it to ensure the user's card is real and valid.
  </Accordion>

  <Accordion title="How does the payment failure retry mechanism work?">
    Under the default strategy, the system automatically retries 24 hours after the 1st failure, and again 48 hours after the 2nd failure. After the 3rd failure, the subscription is frozen, and the service is suspended. You can customize the maximum retry count and time intervals in the Dashboard.
  </Accordion>

  <Accordion title="How are card changes (e.g., expiration, replacement) handled?">
    The system integrates Visa Account Updater and Mastercard Automatic Billing Updater. When a user's card expires or is replaced/lost, the card network automatically syncs the new card information to us. This ensures your subscription billing is not interrupted by card expiration, requiring no manual intervention from the user.
  </Accordion>
</AccordionGroup>

***

Need help? [Contact support](mailto:support@waffo.com)
