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

# Quickstart

Get a step-by-step overview of how to get started with Paddle — including creating your catalog, previewing your pricing page, opening a checkout, and listening to webhooks.

---

This quickstart walks through integrating Paddle end to end, including sandbox setup, product catalog, pricing page, checkout, and webhooks. It's framework-agnostic, with all the moving parts in one place.

If you'd rather start from a working app or jump straight to your SDK, skip to [Pick a starting point](#pick-a-starting-point) at the bottom.

{% callout type="note" title="Working with AI?" %}
Install the [Paddle MCP server](https://developer.paddle.com/sdks/ai/paddle-mcp.md) and [docs MCP server](https://developer.paddle.com/sdks/ai/docs-mcp.md) in your AI client to integrate faster.
{% /callout %}

## What we're building

By the end of this quickstart, you'll have a typical three-tier pricing page connected to [Paddle Checkout](https://developer.paddle.com/concepts/sell/self-serve-checkout.md), with webhooks flowing for provisioning.

You'll learn how to:

- Sign up for Paddle and set up an account.
- Create products and prices.
- Work with Paddle.js to present localized prices.
- Open a checkout and take a test payment.
- Create a notification destination and preview webhooks.

[Explore the working code for this quickstart using our getting started CodePen.](https://codepen.io/heymcgovern/pen/raBZRvz)

## Overview

1. [**Sign up for Paddle**](#sign-up-for-paddle)  
   Create a sandbox account.
2. [**Set up your product catalog**](#set-up-your-product-catalog)  
   Create products and prices for the items you offer.
3. [**Build your pricing page**](#build-your-pricing-page)  
   Show products from your catalog on a pricing page.
4. [**Open a checkout**](#open-a-checkout)  
   Launch a checkout from your pricing page, then take a test payment.
5. [**Listen for webhooks**](#listen-for-webhooks)  
   Preview the webhooks that occur during checkout for handling provisioning.

## Sign up for Paddle {% step=true %}

Paddle has two types of account:

- [Sandbox](https://developer.paddle.com/sdks/sandbox.md) — for testing and evaluation.
- Live — for selling to customers.

For the best experience while testing, **sign up for a sandbox account**. You can sign up for a live account later when your integration is ready.

## Set up your product catalog {% step=true %}

Your [product catalog](https://developer.paddle.com/build/products/create-products-prices.md) includes subscription plans, recurring addons, one-time charges, and things like additional seats. There's no rigid hierarchy — everything you offer is a product.

Create products and related prices to start billing.

### Model your pricing

{% instruction-steps %}

A complete product in Paddle is made up of two parts:

1. A [product entity](https://developer.paddle.com/api-reference/products/overview.md) that describes the item — name, description, image.
2. At least one related [price entity](https://developer.paddle.com/api-reference/prices/overview.md) that describes how much and how often a product is billed.

You can create as many prices for a product as you want to describe all the ways it's billed.

{% /dashboard-instructions %}

We'll start with a three-tier pricing structure — `Starter`, `Pro`, and `Enterprise` — each with monthly and annual options:

|             | Starter |     Pro | Enterprise |
|-------------|--------:|--------:|-----------:|
| **Monthly** |  $10.00 |  $30.00 |    $300.00 |
| **Annual**  | $100.00 | $300.00 |   $3000.00 |

We'll model this in Paddle as three products with two prices each:

```mermaid
graph LR
  Starter["Product: Starter"]
  Pro["Product: Pro"]
  Enterprise["Product: Enterprise"]

  Starter_Monthly["Price: Starter (monthly)"]
  Starter_Yearly["Price: Starter (yearly)"]
  Pro_Monthly["Price: Pro (monthly)"]
  Pro_Yearly["Price: Pro (yearly)"]
  Enterprise_Monthly["Price: Enterprise (monthly)"]
  Enterprise_Yearly["Price: Enterprise (yearly)"]

  Starter --> Starter_Monthly
  Starter --> Starter_Yearly
  Pro --> Pro_Monthly
  Pro --> Pro_Yearly
  Enterprise --> Enterprise_Monthly
  Enterprise --> Enterprise_Yearly
```
<!--mermaid-->

### Create products and prices

You can [create products and prices](https://developer.paddle.com/build/products/create-products-prices.md) using the Paddle dashboard or the API.

For now, we'll create products and prices for `Starter` and `Pro` only. Instead of letting customers self-serve `Enterprise`, we'll ask them to contact us.

{% instruction-steps %}

1. Go to **Paddle > Catalog > Products**.
2. Click {% mock-button icon="carbon:add" %}New product
3. Enter details for your new product, then click Save when you're done.
4. Under the **Prices** section on the page for your product, click New price
5. Enter details for your new price. Set the billing period to **Monthly** to create a monthly price.
6. Click Save when you're done.
7. Create another price, setting the billing period to **Annually** and Save

{% /instruction-steps %}

{% /dashboard-instructions %}

Repeat so you have two products for `Starter` and `Pro`, each with a monthly and annual price.

## Build your pricing page {% step=true %}

[Pricing pages](https://developer.paddle.com/build/checkout/build-pricing-page.md) show potential customers the subscription plans you offer and how much they cost. They're typically a key part of customer conversion.

Paddle includes [Paddle.js](https://developer.paddle.com/paddle-js.md), a lightweight JavaScript library for securely interacting with Paddle in your frontend. Use Paddle.js to build pricing pages that show prospects prices localized for their country, displayed in their local currency with estimated taxes.

### Get a client-side token

[Client-side tokens](https://developer.paddle.com/paddle-js/client-side-tokens.md) let you interact with the Paddle platform in frontend code, like webpages or mobile apps. They have limited access to the data in your system, so they're safe to publish.

{% instruction-steps %}

1. Go to **Paddle > Developer tools > Authentication**.
2. Click the **Client-side tokens** tab.
3. Click {% mock-button icon="carbon:add" %}New client-side token
4. Give your client-side token a name and description, then click Save
5. From the list, click the  button next to the token you just created, then choose Copy token from the menu.

{% /instruction-steps %}

{% /dashboard-instructions %}

We'll use your client-side token in the next step.

### Update constants

Now we've created a client-side token and products and prices, let's add them to a pricing page. We'll use the **getting started CodePen**.

[Open the getting started CodePen](https://codepen.io/heymcgovern/pen/raBZRvz)

In the CodePen, change the values in the `CONFIG` constant at the top of the JavaScript section:

| Value                       | Description                                                                               |
|------------------------|-------------------------------------------------------------------------------|
| `clientToken`          | Client-side token you copied in the last step.                                |
| `prices.starter.month` | Paddle ID for the monthly price of the starter product we created previously. |
| `prices.starter.year`  | Paddle ID for the annual price for the starter product we created previously. |
| `prices.pro.month`     | Paddle ID for the monthly price for the pro product we created previously.    |
| `prices.pro.year`      | Paddle ID for the annual price for the pro product we created previously.     |

You can get Paddle IDs for your prices using the dashboard:

{% instruction-steps %}

1. Go to **Paddle > Catalog > Products**, then click the product you want to get a price ID for.
2. Click the  button next to a price in the list, then choose {% mock-button icon="carbon:copy" %}Copy price ID from the menu.
3. Paste the ID as a value for `month` or `year` in `prices.starter` or `prices.pro`.

{% /instruction-steps %}

{% /dashboard-instructions %}

{% callout type="info" %}
[Paddle IDs](https://developer.paddle.com/api-reference/about/paddle-ids.md) are designed to be easily recognizable. Price IDs start with `pri_` and product IDs start with `pro_`. Check that you've copied price IDs and not product IDs.
{% /callout %}

### Test your pricing page

If you've added a valid client-side token and passed your price IDs correctly, you should see your prices on your pricing page. Prices are fetched dynamically from Paddle.js, so changes you make in the dashboard show up on the next call.

Use the monthly/annual toggle to change prices, then test how localized pricing works using the country dropdown at the bottom.

{% callout type="note" %}
We've included a country dropdown to simulate price localization for demo purposes. In [real implementations](https://developer.paddle.com/build/checkout/build-pricing-page.md), let Paddle.js auto-localize.
{% /callout %}

{% accordion %}
{% accordion-item title="How does this work?" %}

1. We define variables for elements in our pricing page using `document.getElementById()`.
2. We set `currentBillingCycle` to `month` and `currentCountry` to `US` — the defaults shown when customers first visit the page.
3. We call our `InitializePaddle()` function. This calls [`Paddle.Environment.set()`](https://developer.paddle.com/paddle-js/methods/paddle-environment-set.md) to set the sandbox environment, and [`Paddle.Initialize()`](https://developer.paddle.com/paddle-js/methods/paddle-initialize.md) to authenticate with our client-side token. We also call `updatePrices()` to fetch prices from Paddle.js.
4. To handle plan switching, `updateBillingCycle()` updates `currentBillingCycle`, changes the visual state of the buttons, and calls `updatePrices()`.
5. In `updatePrices()`, we build a `request` object with our prices and `currentCountry`, call [`Paddle.PricePreview()`](https://developer.paddle.com/paddle-js/methods/paddle-pricepreview.md), and update the UI.
6. To handle country changes, an event listener updates `currentCountry` and calls `updatePrices()`.

{% /accordion-item %}
{% accordion-item title="Not working?" %}

If prices don't appear, open the console for specific Paddle.js error messages.

#### Common problems

Check that:

- Your [client-side token](https://developer.paddle.com/paddle-js/client-side-tokens.md) is correct. Sandbox tokens start with `test_`.
- The Paddle IDs for [price entities](https://developer.paddle.com/api-reference/prices/overview.md) are correct. Price IDs start with `pri_`.
- You haven't duplicated any IDs in your `Paddle.PricePreview()` request — they must be unique.

{% /accordion-item %}
{% /accordion %}

## Open a checkout {% step=true %}

[Paddle Checkout](https://developer.paddle.com/concepts/sell/self-serve-checkout.md) is where customers make purchases. You can use [Paddle.js](https://developer.paddle.com/paddle-js.md) to add an [overlay checkout](https://developer.paddle.com/concepts/sell/overlay-checkout.md) — a full-page checkout that's optimized for conversion.

### Set a default payment link

Before opening a checkout, you need [a default payment link](https://developer.paddle.com/build/transactions/default-payment-link.md). Paddle uses your default payment link to generate URLs for customers to manage payments and subscriptions.

For now, set your default payment link to your homepage or development environment URL. You can always change it later.

{% instruction-steps %}

1. Go to **Paddle > Checkout > Checkout settings**.
2. Enter your website homepage under the **Default payment link** heading. If you don't have one, enter `https://localhost/`.
3. Click {% mock-button %}Save when you're done.

{% /instruction-steps %}

{% /dashboard-instructions %}

{% callout type="note" %}
You can turn on other payment methods on this screen, too. We'll see eligible payment methods when we open a test checkout in the next step.
{% /callout %}

### Take a test payment

In the CodePen, click **Get started** for a plan to open an overlay checkout. Take a test payment using our [test card details](https://developer.paddle.com/concepts/payment-methods/credit-debit-card.md):

{% definition-list %}
{% definition term="Email address" %}
An email address you own
{% /definition %}
{% definition term="Country" %}
Any valid country supported by Paddle
{% /definition %}
{% definition term="ZIP code (if required)" %}
Any valid ZIP or postal code
{% /definition %}
{% definition term="Card number" %}
`4242 4242 4242 4242`
{% /definition %}
{% definition term="Name on card" %}
Any name
{% /definition %}
{% definition term="Expiration date" %}
Any valid date in the future.
{% /definition %}
{% definition term="Security code" %}
`100`
{% /definition %}
{% /definition-list %}

{% accordion %}
{% accordion-item title="How does this work?" %}

1. Each pricing card has a button with an `onClick` handler that calls `openCheckout()`, passing the plan name as a variable.
2. We initialize Paddle as described in the previous step using `InitializePaddle()`.
3. `openCheckout()` checks Paddle is initialized, then calls [`Paddle.Checkout.open()`](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open.md) with an [array of `items`](https://developer.paddle.com/build/checkout/pass-update-checkout-items.md) and [object of `settings`](https://developer.paddle.com/build/checkout/set-up-checkout-default-settings.md).

{% /accordion-item %}
{% accordion-item title="Not working?" %}

If checkout doesn't load or you see "Something went wrong," open the console for Paddle.js errors.

#### Common problems

Check that:

- You added [a default payment link](https://developer.paddle.com/build/transactions/default-payment-link.md) under **Paddle > Checkout > Checkout settings > Default payment link**.
- Your [client-side token](https://developer.paddle.com/paddle-js/client-side-tokens.md) is correct. Sandbox tokens start with `test_`.
- The price IDs you passed are correct. Price IDs start with `pri_`.
- You haven't duplicated any price IDs in your items list.
- You're opening a checkout from [a supported country](https://developer.paddle.com/concepts/sell/supported-countries-locales.md).

{% /accordion-item %}
{% /accordion %}

## Listen for webhooks {% step=true %}

[Webhooks](https://developer.paddle.com/webhooks/overview.md) tell you when something important happens in your Paddle account. Paddle includes webhooks for the full purchase and subscription lifecycle — from new customer to cancellation.

You'll use webhooks to [handle provisioning and fulfillment](https://developer.paddle.com/build/subscriptions/provision-access-webhooks.md) and to keep your app in sync with Paddle. For example: provision an account when a subscription is created, revoke access when one cancels.

### Create a webhook destination

To start receiving webhooks, [create a notification destination](https://developer.paddle.com/webhooks/notification-destinations.md) — where you tell Paddle which events you want and where to deliver them.

For this quickstart, we'll use **Hookdeck Console** instead of spinning up a webhook endpoint server. Hookdeck Console lets you receive webhooks in a friendly interface, with no account or setup required.

[Open Hookdeck Console](https://console.hookdeck.com/)

{% instruction-steps %}

1. Go to [Hookdeck Console](https://console.hookdeck.com/), then copy the webhook endpoint URL. Keep this tab open.
2. In a new tab, go to **Paddle > Developer Tools > Notifications**.
3. Click {% mock-button icon="carbon:add" %}New destination
4. Give your destination a memorable name.
5. Make sure notification type is set to **webhook** and usage type to **platform** — these are the defaults.
6. Paste the webhook endpoint URL you copied from Hookdeck Console.
7. Check the **select all events** box.
8. Click Save destination when you're done.

{% /instruction-steps %}

{% /dashboard-instructions %}

### Take another test payment

Now we have a notification destination, run through checkout again to see the events.

Open your CodePen and take another test payment. As you move through checkout, you should see webhooks land in Hookdeck.

{% callout type="note" %}
[Paddle.js also emits events](https://developer.paddle.com/paddle-js/events.md) during the checkout lifecycle. Frontend events contain information about items and totals you can use to build advanced workflows.
{% /callout %}

{% accordion %}
{% accordion-item title="How does this work?" %}

As you move through checkout, Paddle creates and updates entities in your account. Webhooks fire each time an entity is created or updated.

For provisioning and order fulfillment, these core webhooks are useful:

| Webhook                                                                        | Useful for                                                                                                                                                                                                             |
|-------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`transaction.created`](https://developer.paddle.com/webhooks/transactions/transaction-created.md)     | Transactions handle capturing payment and calculating revenue. Paddle Checkout creates a transaction, then updates it as the customer enters information and completes payment.                              |
| [`customer.created`](https://developer.paddle.com/webhooks/customers/customer-created.md)              | When a customer enters their email address, Paddle creates a customer for you.                                                                                                                               |
| [`address.created`](https://developer.paddle.com/webhooks/addresses/address-created.md)                | When a customer enters their country and ZIP/postal code, Paddle creates an address related to this customer.                                                                                                |
| [`business.created`](https://developer.paddle.com/webhooks/addresses/address-created.md)               | If a customer chooses to enter a tax/VAT number, Paddle creates a business. The option to add a tax number is presented in regions that require it, like most of Europe.                                     |
| [`transaction.paid`](https://developer.paddle.com/webhooks/transactions/transaction-paid.md)           | When payment goes through successfully, the transaction status changes to `paid`. At this point you can be sure the customer paid and start provisioning.                                                    |
| [`subscription.created`](https://developer.paddle.com/webhooks/subscriptions/subscription-created.md)  | If a checkout is for recurring items, Paddle automatically creates a subscription for the customer, address, and business. Status is `active` or `trialing`, depending on the items on the subscription.     |
| [`transaction.completed`](https://developer.paddle.com/webhooks/transactions/transaction-completed.md) | Once payment is received and a subscription is created, Paddle continues processing — adding subscription details, an invoice number, and information about fees, payouts, and earnings.                     |

{% /accordion-item %}
{% accordion-item title="Not working?" %}

If you don't see webhooks in Hookdeck Console, check the notification destination in Paddle to see if they were sent and whether they're queued for retry.

#### Common problems

Check that:

- You set up [a notification destination](https://developer.paddle.com/webhooks/notification-destinations.md) correctly. Your webhook endpoint should look like `https://hkdk.events/azz5twg6es4g41`, not `https://console.hookdeck.com/`.
- Usage type is set to **platform only** or **both**. The simulation-only option only works with the webhook simulator.
- All events are checked.
- Hookdeck accepted your webhooks. Go to **Paddle > Notifications**, click the  button next to your destination, and choose View logs.

{% /accordion-item %}
{% /accordion %}

## Pick a starting point

If you'd rather skip the framework-agnostic walkthrough and start from a working app or a specific SDK, pick a starting point:

### Starter kits

{% card-group cols=2 %}
{% card title="Next.js SaaS starter kit" icon="carbon:application-web" url="/get-started/starter-kits/nextjs-saas" %}
Deploy a complete Paddle + Supabase + Vercel app. Includes a three-tier subscriptions, customer portal, webhook handling.
{% /card %}
{% card title="Web monetization kit" icon="carbon:rocket" url="/get-started/starter-kits/web-monetization" %}
The recommended starter for mobile apps. Includes marketing, legal, and pricing pages built in.
{% /card %}
{% /card-group %}

### Backend SDK quickstarts

{% card-group cols=2 %}
{% card title="Node.js" icon="nodejs" url="/get-started/quickstart/node" %}
Install the Paddle Node SDK, initialize a client, and make your first request.
{% /card %}
{% card title="Python" icon="python" url="/get-started/quickstart/python" %}
Install the Paddle Python SDK — recommended for AI, data, and internal tooling.
{% /card %}
{% card title="Go" icon="go" url="/get-started/quickstart/go" %}
Install the Paddle Go SDK — designed for scale and `context.Context`-aware backends.
{% /card %}
{% card title="PHP" icon="php" url="/get-started/quickstart/php" %}
Install the Paddle PHP SDK. Using Laravel? Use Cashier Paddle instead.
{% /card %}
{% /card-group %}

## Next steps

That's it. Now you've covered the basics, we recommend starting your integration or learning more about the Paddle platform.

{% card-group cols=2 %}
{% card title="Set-up checklist" url="/build/onboarding/set-up-checklist" %}
Pre-flight checks before going live with Paddle. Make sure your integration is ready.
{% /card %}
{% card title="Go-live checklist" url="/build/onboarding/go-live-checklist" %}
Move from sandbox to live and start accepting real payments on Paddle.
{% /card %}
{% card title="Customer portal" url="/concepts/sell/customer-portal" %}
Let customers self-serve: manage their subscriptions and payments.
{% /card %}
{% card title="Paddle Retain" url="/concepts/retain/overview" %}
Minimize churn with dunning, payment recovery, and cancellation flows.
{% /card %}
{% /card-group %}