Skip to main content

SaaS Billing Quick Start

Time: ~15 minutes | Difficulty: Intermediate This walkthrough matches the tested mini-saas-billing example. Every code block below runs in production.

Prerequisites

  • Node.js 18+
  • A Tagada CRM API key (sk_crm_live_…) — Get an API key
  • A store (store_xxx)

Step 1 — Seed your SaaS plan (backend)

Create a recurring product and a cascade payment flow (sandbox for dev → live TPA for production):
The seed script creates: Verify everything works:

Step 2 — Backend API (node-sdk)

Your server holds the API key and exposes routes the frontend calls.
server/index.ts
Never expose TAGADA_API_KEY to the browser. The frontend only sends tagadaToken to your backend.

Step 3 — Frontend checkout (core-js)

The browser tokenizes the card and calls your API routes.
web/src/App.tsx

Step 4 — Run the demo

Open http://localhost:5173. The right panel shows your payment flow — primary processor and fallbacks.

Test card

Works with the sandbox processor in the cascade flow. For live TPA charges, use a real card.

Handle 3DS (usually nothing to do)

There are two very different 3DS modes, and most SaaS integrations only ever meet the first one:

Option 1 — Platform / PSP-hosted 3DS (the default)

Modern PSPs (Adyen, Stripe, Checkout.com…) host the 3DS challenge themselves. You never call threeds.createSession. Just pass a returnUrl when charging; if the issuer requires SCA, the payment comes back with requireAction: 'redirect' and a redirectUrl pointing at the processor’s own hosted 3DS page:
Whether 3DS triggers is controlled by threeDsEnabled: true on your payment flow (or forced by the issuer). How it runs is the processor’s business — you only handle requireAction.

Option 2 — Standalone 3DS (the exception, rarely needed)

Some gateway-style processors (e.g. NMI) don’t host 3DS but accept pre-authenticated values (CAVV, ECI…) on the charge. Only for those, Tagada runs the 3DS flow itself via threeds.createSession + threedsSessionId. If your flow routes to Adyen, Stripe, or a TagadaPay TPA, skip this entirely. Full explanation: Partners → Payments, Step 3.
When in doubt: don’t pre-create anything. Charge with a returnUrl, then handle whatever requireAction the response carries.

What happens on rebill?

TagadaPay automatically rebills the subscription each cycle. The charge routes through the same payment flow — cascade, weighted, fallback — with no extra code. Manual rebill (support tool, retry script):
Webhook events: subscription/rebillSucceeded, subscription/rebillDeclined, subscription/pastDue.

Stripe mapping

Full migration guide: Migrate from Stripe.