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

# Migrate from Stripe Billing

> Map Stripe objects to TagadaPay and cut over without re-collecting cards

# Migrate from Stripe Billing

**Time**: \~15 minutes to read | **Difficulty**: Intermediate

TagadaPay is not a drop-in Stripe replacement, but the object model maps cleanly. The biggest win: **payment flows let you route across multiple processors** — something Stripe cannot do without re-architecting.

***

## Object mapping

| Stripe                           | TagadaPay                              | Notes                                                 |
| -------------------------------- | -------------------------------------- | ----------------------------------------------------- |
| `Customer` (`cus_`)              | `Customer` (`cus_`)                    | `tagada.customers.create`                             |
| `PaymentMethod` (`pm_`)          | `PaymentInstrument` (`inst_`)          | Created via `createFromToken` — not attached directly |
| `SetupIntent`                    | `core-js tokenize` + `createFromToken` | No separate SetupIntent object                        |
| `PaymentIntent` (`pi_`)          | `Payment` (`pay_`)                     | `tagada.payments.process`                             |
| `Price` (`price_`)               | `Price` (`price_`)                     | Lives inside a product variant                        |
| `Product` (`prod_`)              | `Product` (`product_`)                 | `tagada.products.create` with recurring variant       |
| `Subscription` (`sub_`)          | `Subscription` (`sub_`)                | `tagada.subscriptions.create`                         |
| `Invoice`                        | —                                      | Build from `orders` + `payments` + webhooks           |
| `BillingPortal`                  | —                                      | Build your own with headless SDK                      |
| `stripe.webhooks.constructEvent` | `tagada.webhooks.constructEvent`       | Same ergonomics, `sha256=` HMAC                       |

***

## Code mapping

### Create a customer

```ts theme={null}
// Stripe
const customer = await stripe.customers.create({ email: 'user@saas.com' });

// TagadaPay
const customer = await tagada.customers.create({
  storeId: 'store_xxx',
  email: 'user@saas.com',
  firstName: 'Alex',
  lastName: 'Founder',
});
```

### Save a card

```ts theme={null}
// Stripe (browser)
const { paymentMethod } = await stripe.createPaymentMethod({ type: 'card', card: element });
await stripe.paymentMethods.attach(paymentMethod.id, { customer: customer.id });

// TagadaPay (browser → server)
// FRONTEND:
const { tagadaToken } = await tokenizeCard({ cardNumber, expiryDate, cvc });

// BACKEND:
const { paymentInstrument } = await tagada.paymentInstruments.createFromToken({
  tagadaToken, storeId, customerData: { email, firstName, lastName },
});
```

### Charge + subscribe

```ts theme={null}
// Stripe
const paymentIntent = await stripe.paymentIntents.create({
  amount: 1900, currency: 'eur', customer: customer.id,
  payment_method: paymentMethod.id, confirm: true,
});
const subscription = await stripe.subscriptions.create({
  customer: customer.id, items: [{ price: 'price_xxx' }],
});

// TagadaPay
const { payment } = await tagada.payments.process({
  amount: 1900, currency: 'EUR', storeId,
  paymentInstrumentId: paymentInstrument.id,
  customerId: customer.id, initiatedBy: 'customer',
  paymentFlowId: 'flow_xxx',
});
const { subscription } = await tagada.subscriptions.create({
  customerId: customer.id, priceId: 'price_xxx', storeId,
  currency: 'EUR', defaultPaymentInstrumentId: paymentInstrument.id,
  paymentId: payment.id,
});
```

### Webhooks

```ts theme={null}
// Stripe
const event = stripe.webhooks.constructEvent(rawBody, sig, secret);

// TagadaPay
const event = tagada.webhooks.constructEvent(rawBody, req.headers['x-tagadapay-signature'], secret);
```

***

## Migration phases

### Phase 1 — New subscriptions on TagadaPay

* Keep existing Stripe subs running
* Route new signups through TagadaPay (SaaS quick start)
* Use a **cascade payment flow**: sandbox for dev → live TPA for production
* Map Stripe webhook handlers to TagadaPay events:

| Stripe event                    | TagadaPay event                |
| ------------------------------- | ------------------------------ |
| `invoice.paid`                  | `subscription/rebillSucceeded` |
| `invoice.payment_failed`        | `subscription/rebillDeclined`  |
| `customer.subscription.deleted` | `subscription/canceled`        |
| `payment_intent.succeeded`      | `payment/succeeded`            |

### Phase 2 — Processor flexibility (TagadaPay advantage)

This is what Stripe cannot offer:

```
Stripe:  locked to Stripe
TagadaPay: sandbox → TPA → Stripe → Checkout.com (one vault)
```

Add processors to your payment flow as you grow. If one TPA is banned, switch the flow — cards stay vaulted.

### Phase 3 — Migrate existing subscriptions

TagadaPay supports processor migration without re-vaulting:

```ts theme={null}
await tagada.subscriptions.changeProcessor({
  subscriptionIds: ['sub_xxx'],
  processorId: 'processor_new',
});
```

For bulk card migration from Stripe, contact support — the vault model supports importing tokenized instruments in some configurations.

***

## What Stripe has that TagadaPay doesn't (yet)

| Feature                   | Workaround                                       |
| ------------------------- | ------------------------------------------------ |
| Invoices / PDF            | Build from payments + orders; email via your app |
| Usage/metered billing     | Custom metering in your app + `payments.process` |
| Customer billing portal   | Build with headless SDK customer hooks           |
| Subscription plan changes | Manual cancel + re-create (upgrade API coming)   |

***

## Get started

<CardGroup cols={2}>
  <Card title="SaaS Quick Start" icon="rocket" href="/developer-tools/saas-billing/quick-start">
    Working example tested in production
  </Card>

  <Card title="Payment Flows" icon="route" href="/developer-tools/saas-billing/payment-flows">
    Multi-TPA routing — the reason to switch
  </Card>
</CardGroup>
