> For the complete documentation index, see [llms.txt](https://developer.paddle.com/llms.txt).

# Workflow mapping between Paddle Classic and Paddle Billing

Understand how the workflows you've built to integrate with Paddle Classic map to ways of working in Paddle Billing.

---

After you activate Paddle Billing for your account, you get access to the Paddle Billing dashboard, API and webhooks, Paddle.js v2, and developer tools. To move fully to Paddle Billing, you need to replace your integration with Paddle Classic with an integration that uses the Paddle Billing API, webhooks, and Paddle.js v2.

This guide walks through how typical workflows in Paddle Classic map to ways of working in Paddle Billing. You can use it to review your integration with Classic and understand how you should build your integration with Paddle Billing.

## Product catalog

### Model products

#### Paddle Classic

For each item that you offer, create either a product or a plan:

- Create products for one-time items.
- Create plans for subscriptions.

If you offer subscriptions with different billing periods, you need to create a separate plan for each one.

#### Paddle Billing

Everything you offer in Paddle is [a product, with related prices](https://developer.paddle.com/build/products/create-products-prices.md) describing how products are billed:

1. Create products to describe an item that you offer, including name and icon.
2. Create related prices to describe how much and how often a product is billed.

For example, you might have a "Pro plan" product with two price entities for "Month" and "Annual."

### Work with discounts

#### Paddle Classic

Use coupons, modifiers, or pay links depending on the kind of discount you need:

- To create a discount that applies once or forever, create and apply a coupon to a checkout.
- To apply a discount for a limited number of billing periods, create and apply a modifier to a subscription, then manually remove when no longer needed.
- To pass a totally custom price, use the API to generate a pay link and pass to Paddle.js.

#### Paddle Billing

Discounts in Paddle Billing give you [a unified, flexible way to offer discounts](https://developer.paddle.com/build/products/offer-discounts-promotions-coupons.md):

1. Create percentage, fixed fee, or per-seat discounts using the API or the dashboard.
2. Apply to a checkout, transaction, or subscription at any time using Paddle.js, the API, or the dashboard.

Discounts can recur for a set number of billing periods, or indefinitely.

They never add credit to a customer balance, and they can be prorated on redemption.

### Localize your prices

#### Paddle Classic

Localization in Paddle Classic works at the currency level:

- When creating products and plans, manually set overrides for each currency.
- To create overrides for countries that share a currency, create a price for each country, then build your own logic in your frontend to apply the correct price at checkout.

#### Paddle Billing

Paddle Billing includes [new ways to localize prices](https://developer.paddle.com/build/products/offer-localized-pricing.md) based on willingness to pay and purchasing power:

1. Turn on automatic currency conversion at an account level to automatically localize prices at checkout into the best currency for a region.
2. Add country-specific prices to prices in your catalog for markets that are important to you — including separate prices for countries that share a currency.
3. Paddle automatically presents customers with the best price at checkout.

## Billing

### Build a pricing page

#### Paddle Classic

Paddle Classic has different ways of presenting localized prices:

- To get localized prices for one item, use `Paddle.Product.Prices()`.
- To get localized prices for multiple items, or get discounted prices, make an AJAX request to the get prices operation in your frontend.

Multi-product checkouts and subscriptions aren't supported, so you can't natively create shopping carts.

#### Paddle Billing

Use frontend methods that match API operations to calculate localized prices for [pricing pages](https://developer.paddle.com/build/checkout/build-pricing-page.md):

- To get localized prices for multiple items, use [`Paddle.PricingPreview()`](https://developer.paddle.com/paddle-js/methods/paddle-pricepreview.md). You can include a discount.
- To build shopping carts or pricing pages where users can build their own plan, use `Paddle.TransactionPreview()` to get localized prices for multiple items, including totals that mirror those used on a checkout. You can include a discount.

You can also use the [preview prices](https://developer.paddle.com/api-reference/pricing-preview/preview-prices.md) or [preview a transaction](https://developer.paddle.com/api-reference/transactions/preview-transaction.md) operations in the API to work with localized prices in your backend.

### Open and work with a checkout

#### Paddle Classic

Paddle Classic supports single product checkouts, with no way to update an opened checkout.

- Use `Paddle.Checkout.open()` to open a checkout. You may pass one item.
- Prefill customer information, pass a discount, and customize properties as part of the method call.
- To update an item on a checkout, use `Paddle.Checkout.close()` to close it, then reopen. Handle the transition state in your frontend.

#### Paddle Billing

Paddle Checkout includes support for multiple products, and includes [new ways to update a checkout once it's opened](https://developer.paddle.com/build/checkout/pass-update-checkout-items.md).

- Use [`Paddle.Checkout.open()`](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open.md) to open a checkout. You can pass multiple items.
- Prefill customer information, pass a discount, and customize properties as part of the initial method call, or using [`Paddle.Checkout.updateCheckout()`](https://developer.paddle.com/paddle-js/methods/paddle-checkout-updatecheckout.md) once opened.
- Use [`Paddle.Checkout.updateItems()`](https://developer.paddle.com/paddle-js/methods/paddle-checkout-updateitems.md) to dynamically update items or add a discount to an opened checkout.

### Display a one-page checkout

#### Paddle Classic

One-page checkout isn't natively supported in Paddle Classic. As a workaround, you might:

1. Capture email address and location information in a workflow before you launch checkout.
2. Pass email and address details to `Paddle.Checkout.open()`.
3. Paddle Checkout skips the first screen, since all the required information has been captured.

#### Paddle Billing

Paddle Billing fully supports [one-page checkout](https://developer.paddle.com/concepts/sell/overlay-checkout.md), where all checkout fields are on one page:

4. Pass `one-page` as the value for the `variant` checkout setting parameter when calling [`Paddle.Checkout.open()`](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open.md).
5. Paddle presents a new checkout experience where all fields are on one page.

You can still prefill fields when using one-page checkout for an even quicker checkout experience.

### Create a checkout link

#### Paddle Classic

Use pay links to create a link to a checkout:

1. Use the API to generate a pay link with a custom total and description.
2. Pass to Paddle.js using the `override` parameter.

#### Paddle Billing

You can [pass a transaction in Paddle Billing to Paddle.js](https://developer.paddle.com/build/transactions/pass-transaction-checkout.md) to open a checkout for it:

3. [Set a default payment link](https://developer.paddle.com/build/transactions/default-payment-link.md) in your dashboard. You only need to do this once.
4. Use the dashboard or the API to [create a transaction](https://developer.paddle.com/build/transactions/create-transaction.md).
5. Pass the transaction ID to Paddle.js when opening a checkout, or grab the `checkout.url` from the transaction.

Checkout links use your default payment link, but you can pass an approved domain as the URL when creating or updating a transaction to use a different link.

### Offer multi-product checkouts

#### Paddle Classic

Multi-product subscriptions and checkouts aren't natively supported. As a workaround, you might:

1. Create a template package product in the dashboard, then store details about items that you bundle together on your side.
2. When customers purchase multiple items, calculate item totals and create a custom description.
3. Use the API to generate a pay link with the custom total and description.
4. Pass to Paddle.js using the `override` parameter.

#### Paddle Billing

Multi-product subscriptions and checkouts are supported out-of-the-box using [Paddle.js v2](https://developer.paddle.com/paddle-js/overview.md):

5. [Create products and prices](https://developer.paddle.com/build/products/create-products-prices.md) using the API or the dashboard.
6. Pass [multiple price IDs to Paddle.js when opening a checkout](https://developer.paddle.com/build/checkout/pass-update-checkout-items.md), or when [creating a transaction](https://developer.paddle.com/build/transactions/create-transaction.md).

### Save cards for future purchases

#### Paddle Classic

Saving payment methods isn't supported. As a workaround, you might:

1. Create a template package product in the dashboard for $0.
2. When customers want to save a card, use the API to generate a pay link with a custom description.
3. Pass to Paddle.js using the `override` parameter.
4. To let customers pay using their card, build a way for customers to log in, then use the API to create a one-off charge for the subscription to use their card.

#### Paddle Billing

Built-in support for [saving payment methods](https://developer.paddle.com/build/checkout/saved-payment-methods.md) and [working with saved payment methods using the API](https://developer.paddle.com/api-reference/payment-methods/overview.md):

5. Turn on saved payment methods in the dashboard. You only need to do this once.
6. Paddle Checkout automatically presents customers with an option to save their payment method at checkout.
7. To let customers pay using their card, [generate a customer authentication token using the API](https://developer.paddle.com/api-reference/customers/generate-customer-authentication-token.md) then pass to Paddle.js when opening a checkout.

You can present all payment methods that a customer has saved, preselect a single payment method, or pass certain kinds of payment method.

### Bill for custom items

#### Paddle Classic

Use pay links to bill for one-off or bespoke items. A typical workflow might involve:

1. Use the API to generate a pay link with a custom total and description.
2. Pass to Paddle.js using the `override` parameter.

#### Paddle Billing

Use [non-catalog products and prices](https://developer.paddle.com/build/transactions/bill-create-custom-items-prices-products.md) to bill for one-off or bespoke items. When working with transactions or subscriptions:

- Pass a price object, rather than a price ID, to charge a custom amount for an existing product.
- Pass product and price objects, rather than a price ID, to bill for an entirely custom product.

Non-catalog products and prices are discrete entities for reporting purposes.

### Issue invoices

#### Paddle Classic

Paddle Classic uses a separate invoicing module. A typical workflow might involve:

1. Create and maintain a separate product catalog and customer list for invoicing.
2. Use the Paddle dashboard or Paddle invoicing API to create invoices.
3. Issue an invoice to mark it as finalized. Send it to business contacts yourself.
4. Listen for `invoice.issued` and `invoice.completed` for fulfillment.
5. To create invoices for subscriptions, build your own logic to create an invoice on renewal.

#### Paddle Billing

Invoicing and subscriptions are fully integrated in Paddle Billing, with [transactions](https://developer.paddle.com/api-reference/transactions/overview.md) as the central entity for revenue capture:

6. Use the Paddle dashboard to [create invoices](https://developer.paddle.com/build/invoices/create-issue-invoices.md), or [use the API to create a transaction](https://developer.paddle.com/api-reference/transactions/create-transaction.md) where the collection mode is manual.
7. Mark a transaction as `billed` to mark it as finalized. Paddle automatically sends the invoice to any business contacts.
8. Listen for [`transaction.billed`](https://developer.paddle.com/webhooks/transactions/transaction-billed.md) and [`transaction.completed`](https://developer.paddle.com/webhooks/transactions/transaction-completed.md) for fulfillment.
9. Paddle automatically creates a subscription when an invoice for recurring items is issued, and for subscription renewals and other lifecycle events.

### Issue refunds

#### Paddle Classic

Paddle Classic includes different ways of issuing refunds depending on the kind of purchase and revenue source:

- You can refund orders for subscriptions or one-time products purchased through the checkout using the dashboard.
- To refund invoices, use the Paddle invoicing API. You can't refund using the dashboard.

There's no concept of a credit note or credit memo in Paddle Classic.

All refunds must be approved.

#### Paddle Billing

Paddle records post-billing changes to a transaction, including refunds, credits, and chargebacks using a [new adjustment entity](https://developer.paddle.com/api-reference/adjustments/overview.md).

1. Create [a refund using the dashboard](https://developer.paddle.com/build/transactions/create-transaction-adjustments.md), or by [creating an adjustment](https://developer.paddle.com/api-reference/adjustments/create-adjustment.md) using the API.
2. Some [refunds are automatically approved](https://developer.paddle.com/build/transactions/create-transaction-adjustments#background-refunds.md), otherwise refunds are pending until they're approved by the Paddle team.
3. Once approved, Paddle automatically sends the customer a copy of a credit note as a record of the refund.

## Provisioning and fulfillment

### Build checkout success workflows

#### Paddle Classic

Paddle.js v1 comes with multiple ways to pass an event callback, depending on the kind of event. You can also pass a success URL.

- To call a function when a checkout is closed or completed, use `closeCallback` or `successCallback`.
- Use `eventCallback` with a case condition to determine if an event is `Checkout.Complete` and call a function.
- You can pass a `successUrl` to `Paddle.Checkout.open()` to redirect to a page.

#### Paddle Billing

[Paddle.js v2](https://developer.paddle.com/paddle-js/overview.md) comes with a single event callback and a standardized checkout event shape. Passing a success URL works in the same way as Classic.

- Use `eventCallback` with a case condition to determine if an event is [`checkout.completed`](https://developer.paddle.com/paddle-js/events/checkout-completed.md) and call a function.
- You can pass a `successUrl` to [`Paddle.Checkout.open()`](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open.md) to redirect to a page.

### Handle fulfillment for one-time items

#### Paddle Classic

Fulfillment for one-time items in Paddle Classic is Paddle-led:

1. Set up download links or license keys when creating products.
2. When a customer completes a purchase, Paddle sends downloads or license keys.

You can also pass custom URLs to Paddle.js using the `Paddle.Download` method.

#### Paddle Billing

Build your own logic to handle fulfillment in Paddle Billing. A typical workflow involves:

1. Listen for [`transaction.completed`](https://developer.paddle.com/webhooks/transactions/transaction-completed.md) webhooks.
2. Generate a unique download URL and send an email for the customer who paid.

You can also create an event callback function to run on [`checkout.completed`](https://developer.paddle.com/paddle-js/events/checkout-completed.md) to enter into a success workflow.

### Handle fulfillment for subscriptions

#### Paddle Classic

Build your own logic to handle fulfillment in Paddle Classic. A typical workflow involves:

1. Listen for `subscription_payment_succeeded` and `subscription_created` webhooks.
2. Create a record in your database for the subscription.
3. Provision access to your app.

#### Paddle Billing

Build your own logic to handle fulfillment in Paddle Billing. You should:

4. Listen for [`transaction.completed`](https://developer.paddle.com/webhooks/transactions/transaction-completed.md) and [`subscription.created`](https://developer.paddle.com/webhooks/subscriptions/subscription-created.md) webhooks.
5. Create a record in your database for the customer and subscription.
6. [Provision access](https://developer.paddle.com/build/subscriptions/provision-access-webhooks.md) to your app.

[Transactions](https://developer.paddle.com/api-reference/transactions/overview.md) and [subscriptions](https://developer.paddle.com/api-reference/subscriptions/overview.md) are closely related, making matching a checkout or invoice to a subscription easier.

## Subscriptions

### Upgrade and downgrade

#### Paddle Classic

Update a subscription user in Paddle Classic to make changes to a subscription.

1. Use the update user operation in the API, passing the new `plan_id`, `prorate`, and `bill_immediately`. You can also use the dashboard.
2. If you're making prorated changes, Paddle calculates it accurate to the day.
3. Update records in your database and provision access.

#### Paddle Billing

Paddle Billing includes [a new subscription entity](https://developer.paddle.com/api-reference/subscriptions/overview.md), with flexible ways to work with subscription items:

4. Optionally [preview an update to a subscription](https://developer.paddle.com/api-reference/subscriptions/preview-subscription.md) using the API, passing an updated `items` list and `proration_billing_mode`.
5. Use the [update subscription operation](https://developer.paddle.com/api-reference/subscriptions/update-subscription.md) in the API, passing an updated `items` list and `proration_billing_mode`. You can also use the dashboard.
6. If you're making [prorated changes](https://developer.paddle.com/concepts/subscriptions/proration.md), Paddle calculates it accurate to the minute.
7. Update records in your database and [provision access](https://developer.paddle.com/build/subscriptions/provision-access-webhooks.md).

### Cancel subscriptions

#### Paddle Classic

In Classic, the main way to cancel a subscription is to cache links returned by subscription webhooks:

- Subscribe to all subscription webhooks, store the `cancel_url` each time a webhook occurs, then pass this URL to Paddle.js using the `override` parameter.
- To build your own workflow, use the cancel user operation in the API.

#### Paddle Billing

Paddle Billing includes multiple ways to let customers [cancel their subscriptions](https://developer.paddle.com/build/subscriptions/cancel-subscriptions.md):

- [Generate authenticated links to the customer portal](https://developer.paddle.com/build/customers/integrate-customer-portal.md) to let customers cancel.
- To present customers with a cancellation survey that's designed to prevent churn, [use Paddle.js to launch Retain Cancellation Flows](https://developer.paddle.com/build/retain/configure-cancellation-flows-surveys.md).
- To build your own workflow, use the [cancel a subscription operation](https://developer.paddle.com/api-reference/subscriptions/cancel-subscription.md) in the API.

### Pause and resume subscriptions

#### Paddle Classic

Paddle Classic supports basic pause and resume functionality:

- Use the API to update a subscription, passing `pause=true`. You can also use the dashboard.
- Resume a subscription in the same way, passing `pause=false`. You can also use the dashboard.
- To resume on a specific date, build your own workflow that calls the API on a later date.

#### Paddle Billing

In Paddle Billing, you can choose to [pause or resume](https://developer.paddle.com/build/subscriptions/pause-subscriptions.md) right away, or schedule a pause or resume to happen in the future.

- Use the pause a subscription operation to [pause a subscription](https://developer.paddle.com/api-reference/subscriptions/pause-subscription.md). You can also use the dashboard.
- Use the resume a subscription operation to [resume a subscription](https://developer.paddle.com/api-reference/subscriptions/resume-subscription.md). You can also use the dashboard.
- Set a resume date when pausing or resuming a subscription.

When resuming a subscription, you can choose whether to start a new billing period or continue an existing one.

### Update payment method

#### Paddle Classic

In Classic, the main way to update a payment method is to cache links returned by subscription webhooks:

1. Subscribe to all subscription webhooks.
2. Store the `update_url` each time a webhook occurs.
3. Pass the `update_url` to Paddle.js using the `override` parameter to let customers update.
4. Update records in your database, if required.

Checkouts for updating a payment method don't use your checkout customization settings.

#### Paddle Billing

Paddle Billing includes multiple ways to let customers update their payment method:

- [Generate authenticated links to the customer portal](https://developer.paddle.com/build/customers/integrate-customer-portal.md) to let customers update their payment method.
- Use the API to [create a transaction to update a payment method](https://developer.paddle.com/api-reference/subscriptions/update-payment-method.md), then pass it to Paddle.js to open a checkout for payment method update. It uses your checkout customization settings.

[Payment methods](https://developer.paddle.com/api-reference/payment-methods/overview.md) are first-class entities in the API that you can work with.

### Work with trials

#### Paddle Classic

Paddle Classic includes limited trial functionality, but doesn't let you update a subscription during trial. For flexible trials, a typical workflow might look like this:

1. Build your own signup workflow in your frontend.
2. Keep track of the trial period and details yourself in your backend.
3. At the end of the trial period, launch a checkout to collect payment information.

#### Paddle Billing

Paddle Billing lets you work with subscriptions in trial in the same way as active subscriptions.

- Use the dashboard or the API to switch plan, add or remove items, or change trial end date.
- [Activate a subscription](https://developer.paddle.com/api-reference/subscriptions/activate-subscription.md) in one API call.

## Dunning and retention

### Handle payment failures and dunning

#### Paddle Classic

By default, you can configure limited retry rules in Paddle Classic.

- Configure limited retry rules in the dashboard.
- Integrate with Paddle Retain for additional retries.

#### Paddle Billing

[Paddle Retain](https://developer.paddle.com/concepts/retain/overview.md) powers dunning and payment recovery in Paddle Billing.

- [Turn on and set up Retain](https://developer.paddle.com/build/retain/set-up-retain-profitwell.md) to customize [failed payment retries](https://developer.paddle.com/build/retain/configure-payment-recovery-dunning.md) and determine what happens when dunning is exhausted.
- Without Retain, Paddle Billing automatically retries payment for failed subscription renewals, but doesn't email customers.

### Work with Retain in your frontend

#### Paddle Classic

You can integrate Paddle Classic with Paddle Retain, but it requires a separate script.

1. Add the `Profitwell.js` script to the head of any pages on your app or website.
2. Initialize by passing a Retain API key.
3. Pass the email address for a logged-in user to track engagement.
4. Include and initialize Paddle.js v1 as normal after.

#### Paddle Billing

Paddle Retain is bundled with [Paddle.js v2](https://developer.paddle.com/paddle-js/overview.md), so you can include and initialize Paddle.js in one call.

5. [Include and initialize Paddle.js](https://developer.paddle.com/paddle-js/include-paddle-js.md) using a client-side token. Retain is authenticated using your client-side token.
6. Pass the email address of a logged-in customer to [`Paddle.Initialize()`](https://developer.paddle.com/paddle-js/methods/paddle-initialize.md).

You can also use [the Paddle.js wrapper](https://github.com/PaddleHQ/paddle-js-wrapper) to install Paddle.js as a module.