For AI agents and LLMs: a structured documentation index is available at /llms.txt. Every page has a Markdown sibling — append .md to any URL.

Skip to content
Docs

Bill for non-catalog items

Charge for an item without adding it to your product catalog by passing price or product attributes when working with a transaction or a subscription.

AI summary

Bill for non-catalog items by passing inline price or product objects directly on a transaction, without adding them to your Paddle product catalog.

  • • Pass a price object inline within transaction items instead of a price_id to create a non-catalog charge — Paddle creates ephemeral price and product entities automatically.
  • • Non-catalog items are useful for bespoke enterprise pricing, frequently changing prices, or when your catalog is managed externally (e.g., by a games platform).
  • • Inline prices can include all standard price fields like billing_cycle, trial_period, and unit_price_overrides — they behave identically to catalog prices on the transaction.

As well as creating transactions for items in your product catalog, you can create transactions for non-catalog items. This is useful for one-off or bespoke items that are specific to that transaction. For example, you may agree a custom price with an enterprise customer.

You may also like to bill for non-catalog items if you work with products where the price changes often, or where you need to manage your product catalog outside of Paddle. For example, games companies typically manage their product catalog centrally because they need to work with app stores.

How it works

Transactions calculate and capture revenue in Paddle. To bill for an item, you add it to a transaction. You can do this in two ways:

Using your product catalog

Key features

  • Manage items using the product catalog in Paddle.
  • Items can be reused across transactions easily.
  • Useful for companies who sell a set of digital products at the same price points.

Example use cases

  • SaaS companies who sell subscription plans and addons. Prices may vary by country, but items remain the same.
  • Companies who sell a selection of digital products or software licenses where the items remain the same.

Billing for non-catalog items

How it works

Pass price and product attributes directly to a transaction when creating or updating to bill for them.

Key features

  • Manage items using your own product database.
  • Items are specific to a transaction.
  • Useful for companies with lots of items, or where item prices may change a lot.

Example use cases

  • Games companies who maintain a large catalog of items and may show different prices to different user segments.
  • eBook retailers, where publishers set prices and they may change daily.

How do non-catalog items relate to catalog items?

A complete product in Paddle is made up of a product entity that describes the item, and a related price entity that describes how much and how often a product is billed.

You can add non-catalog items to a transaction where:

  • Only the price is custom.
    This is great where the products you offer stay the same, but you might offer bespoke pricing from time to time. Your non-catalog price relates an existing catalog product entity in Paddle, sharing the same product name, image, and tax category.
  • Both the price and the product are custom.
    Where you manage your product catalog outside of Paddle, you can create entirely custom products. Your item uses a non-catalog price and a non-catalog product.

When you create or update a transaction with non-catalog items, Paddle creates a price entity and (optionally) a related product entity. They have a Paddle ID as normal, meaning you can use the get a product or get a price operations to work with them, but they're not added to your product catalog.

This means they're not returned by default when listing products or prices, and they're not shown in the Paddle dashboard.

Non-catalog price and product entities have a type of custom, so you can differentiate between entities in your catalog.

Subscriptions

This guide walks through adding non-catalog items to transactions, but you can also:

You can configure non-catalog items for a subscriptions in the same way as transactions.

Before you begin

To create a transaction, you'll need to first set your default payment link under Paddle > Checkout > Checkout settings > Default payment link and get it approved.

Bill for a non-catalog price for an existing product

You can add a non-catalog price for an existing product in your catalog to a transaction. In this case, the product a customer is purchasing is the same, but you have a specific price for it.

Bill for a non-catalog price using the API in two steps:

  1. Preview transaction Optional
    Preview tax and localized pricing before creating the transaction.
  2. Create transaction
    Send a request to create the transaction with your non-catalog item.

In your request, build an items array with price objects and quantity for each item. Relate your custom price to an existing catalog product using product_id.

You can also include existing catalog items using price_id and quantity.

Include customer_id and address_id (and optionally business_id) to create a ready transaction.

Preview transaction Optional

Send a POST request to the /transactions/preview endpoint to preview the transaction.

POST /transactions/preview
Request
{
"items": [
{
"quantity": 1,
"price": {
"product_id": "pro_01he5kwnnvgdv2chtpgavk2rf8",
"description": "New user price (FTUE)",
"name": "Invigaron Berries welcome price",
"unit_price": {
"amount": "999",
"currency_code": "USD"
}
}
}
],
"currency_code": "USD"
}
Response (200 OK)
{
"data": {
"customer_id": null,
"address_id": null,
"business_id": null,
"currency_code": "USD",
"address": null,
"customer_ip_address": null,
"discount_id": null,
"items": [
{
"price": {
"id": null,
"description": "New user price (FTUE)",
"type": "custom",
"name": "Invigaron Berries welcome price",
"product_id": "pro_01he5kwnnvgdv2chtpgavk2rf8",
"billing_cycle": null,
"trial_period": null,
"tax_mode": "account_setting",
"unit_price": {
"amount": "999",
"currency_code": "USD"
},
"unit_price_overrides": null,
"custom_data": null,
"quantity": {
"minimum": 1,
"maximum": 100
},
"status": "active"
},
"quantity": 1,
"proration": null,
"include_in_totals": true
}
],
"details": {
"tax_rates_used": [
{
"tax_rate": "0",
"totals": {
"subtotal": "999",
"discount": "0",
"tax": "0",
"total": "999"
}
}
],
"totals": {
"subtotal": "999",
"tax": "0",
"discount": "0",
"total": "999",
"grand_total": "999",
"fee": null,
"credit": "0",
"credit_to_balance": "0",
"balance": "999",
"earnings": null,
"currency_code": "USD"
},
"line_items": [
{
"price_id": "pri_01hj3rny6ayaczq16m477qrg81",
"quantity": 1,
"totals": {
"subtotal": "999",
"tax": "0",
"discount": "0",
"total": "999"
},
"product": {
"id": "pro_01he5kwnnvgdv2chtpgavk2rf8",
"name": "Invigaron Berries Hoard",
"description": "Level up!",
"type": "standard",
"tax_category": "standard",
"image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/XBWZPsQoSc6YyViK5ocI_fire.png",
"custom_data": null,
"status": "active"
},
"tax_rate": "0",
"unit_totals": {
"subtotal": "999",
"tax": "0",
"discount": "0",
"total": "999"
}
}
]
},
"ignore_trials": false,
"available_payment_methods": []
},
"meta": {
"request_id": "5615f928-3486-4933-b3f1-f70246c3b625"
}
}

Create transaction

Send a POST request to the /transactions endpoint to create the transaction.

The created transaction is draft. Pass it to a checkout to capture customer and address information.

POST /transactions
Request
{
"items": [
{
"quantity": 1,
"price": {
"product_id": "pro_01he5kwnnvgdv2chtpgavk2rf8",
"description": "New user price (FTUE)",
"name": "Invigaron Berries welcome price",
"unit_price": {
"amount": "999",
"currency_code": "USD"
}
}
}
],
"currency_code": "USD"
}
Response (201 Created)
{
"data": {
"id": "txn_01hj3rtynv8rdn1zbcjk42z05j",
"status": "draft",
"customer_id": null,
"address_id": null,
"business_id": null,
"custom_data": null,
"origin": "api",
"collection_mode": "automatic",
"subscription_id": null,
"invoice_id": null,
"invoice_number": null,
"billing_details": null,
"billing_period": null,
"currency_code": "USD",
"discount_id": null,
"created_at": "2023-12-20T14:07:25.454915616Z",
"updated_at": "2023-12-20T14:07:25.454915616Z",
"billed_at": null,
"items": [
{
"price": {
"id": "pri_01hj3rtypd6wns6g943kbndswg",
"description": "New user price (FTUE)",
"type": "custom",
"name": "Invigaron Berries welcome price",
"product_id": "pro_01he5kwnnvgdv2chtpgavk2rf8",
"billing_cycle": null,
"trial_period": null,
"tax_mode": "account_setting",
"unit_price": {
"amount": "999",
"currency_code": "USD"
},
"unit_price_overrides": [],
"custom_data": null,
"quantity": {
"minimum": 1,
"maximum": 100
},
"status": "active"
},
"quantity": 1
}
],
"details": {
"tax_rates_used": [
{
"tax_rate": "0",
"totals": {
"subtotal": "999",
"discount": "0",
"tax": "0",
"total": "999"
}
}
],
"totals": {
"subtotal": "999",
"tax": "0",
"discount": "0",
"total": "999",
"grand_total": "999",
"fee": null,
"credit": "0",
"credit_to_balance": "0",
"balance": "999",
"earnings": null,
"currency_code": "USD"
},
"adjusted_totals": {
"subtotal": "999",
"tax": "0",
"total": "999",
"grand_total": "999",
"fee": "0",
"earnings": "0",
"currency_code": "USD"
},
"payout_totals": null,
"adjusted_payout_totals": null,
"line_items": [
{
"id": "txnitm_01hj3rtyqzfh4nf7rb9fs2y8xx",
"price_id": "pri_01hj3rtypd6wns6g943kbndswg",
"quantity": 1,
"totals": {
"subtotal": "999",
"tax": "0",
"discount": "0",
"total": "999"
},
"product": {
"id": "pro_01he5kwnnvgdv2chtpgavk2rf8",
"name": "Invigaron Berries Hoard",
"description": "Level up!",
"type": "standard",
"tax_category": "standard",
"image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/XBWZPsQoSc6YyViK5ocI_fire.png",
"custom_data": null,
"status": "active"
},
"tax_rate": "0",
"unit_totals": {
"subtotal": "999",
"tax": "0",
"discount": "0",
"total": "999"
}
}
]
},
"payments": [],
"checkout": {
"url": "https://aeroedit.com/pay?_ptxn=txn_01hj3rtynv8rdn1zbcjk42z05j"
}
},
"meta": {
"request_id": "a62a5fb8-3f63-4222-9b57-68e16dada004"
}
}

Bill for a non-catalog price and a non-catalog-product

You can add a non-catalog price for a non-catalog product in your catalog to a transaction. This is useful if you manage your product catalog outside of Paddle, or you want to sell something entirely bespoke.

Bill for a non-catalog price and product using the API in two steps:

  1. Preview transaction Optional
    Preview tax and localized pricing before creating the transaction.
  2. Create transaction
    Send a request to create the transaction with your non-catalog price and product.

In your request, build an items array with price objects (each including a nested product object) and quantity for each item.

You can also include existing catalog items using price_id and quantity.

Include customer_id and address_id (and optionally business_id) to create a ready transaction.

Preview transaction Optional

Send a POST request to the /transactions/preview endpoint to preview the transaction.

POST /transactions/preview
Request
{
"items": [
{
"quantity": 1,
"price": {
"description": "Battle pass",
"name": "Monthly",
"billing_cycle": {
"interval": "month",
"frequency": 1
},
"unit_price": {
"amount": "1099",
"currency_code": "USD"
},
"product": {
"name": "Invigaron VIP pass",
"tax_category": "standard",
"description": "Lock in 200x Invigaron Berries a month, plus faster gem spawns, exclusive skins, and early access to the leaderboard."
}
}
}
],
"currency_code": "USD"
}
Response (200 OK)
{
"data": {
"customer_id": null,
"address_id": null,
"business_id": null,
"currency_code": "USD",
"address": null,
"customer_ip_address": null,
"discount_id": null,
"items": [
{
"price": {
"id": null,
"description": "Battle pass",
"type": "custom",
"name": "Monthly",
"product_id": null,
"billing_cycle": {
"interval": "month",
"frequency": 1
},
"trial_period": null,
"tax_mode": "account_setting",
"unit_price": {
"amount": "1099",
"currency_code": "USD"
},
"unit_price_overrides": null,
"custom_data": null,
"quantity": {
"minimum": 1,
"maximum": 100
},
"status": "active"
},
"quantity": 1,
"proration": null,
"include_in_totals": true
}
],
"details": {
"tax_rates_used": [
{
"tax_rate": "0",
"totals": {
"subtotal": "1099",
"discount": "0",
"tax": "0",
"total": "1099"
}
}
],
"totals": {
"subtotal": "1099",
"tax": "0",
"discount": "0",
"total": "1099",
"grand_total": "1099",
"fee": null,
"credit": "0",
"credit_to_balance": "0",
"balance": "1099",
"earnings": null,
"currency_code": "USD"
},
"line_items": [
{
"price_id": "pri_01hj3sbfnr0t7eat8na0pqyapv",
"quantity": 1,
"totals": {
"subtotal": "1099",
"tax": "0",
"discount": "0",
"total": "1099"
},
"product": {
"id": null,
"name": "Invigaron VIP pass",
"description": "Lock in 200x Invigaron Berries a month, plus faster gem spawns, exclusive skins, and early access to the leaderboard.",
"type": "custom",
"tax_category": "standard",
"image_url": null,
"custom_data": null,
"status": "active"
},
"tax_rate": "0",
"unit_totals": {
"subtotal": "1099",
"tax": "0",
"discount": "0",
"total": "1099"
}
}
]
},
"ignore_trials": false,
"available_payment_methods": []
},
"meta": {
"request_id": "4459e3d0-1d65-4f9f-8b34-1e3f3faf5cbd"
}
}

Create transaction

Send a POST request to the /transactions endpoint to create the transaction.

The created transaction is draft. Pass it to a checkout to capture customer and address information. Paddle automatically creates a subscription for recurring items — use webhooks to provision your app.

POST /transactions
Request
{
"items": [
{
"quantity": 1,
"price": {
"description": "Battle pass",
"name": "Monthly",
"billing_cycle": {
"interval": "month",
"frequency": 1
},
"unit_price": {
"amount": "1099",
"currency_code": "USD"
},
"product": {
"name": "Invigaron VIP pass",
"tax_category": "standard",
"description": "Lock in 200x Invigaron Berries a month, plus faster gem spawns, exclusive skins, and early access to the leaderboard."
}
}
}
],
"currency_code": "USD"
}
Response (201 Created)
{
"data": {
"id": "txn_01hj3sct9my6jsx9zt55thzpfw",
"status": "draft",
"customer_id": null,
"address_id": null,
"business_id": null,
"custom_data": null,
"origin": "api",
"collection_mode": "automatic",
"subscription_id": null,
"invoice_id": null,
"invoice_number": null,
"billing_details": null,
"billing_period": null,
"currency_code": "USD",
"discount_id": null,
"created_at": "2023-12-20T14:17:10.858871798Z",
"updated_at": "2023-12-20T14:17:10.858871798Z",
"billed_at": null,
"items": [
{
"price": {
"id": "pri_01hj3sctd36bwevs47dw8jxdkn",
"description": "Battle pass",
"type": "custom",
"name": "Monthly",
"product_id": "pro_01hj3sctbh6r2hyga7qg29dznq",
"billing_cycle": {
"interval": "month",
"frequency": 1
},
"trial_period": null,
"tax_mode": "account_setting",
"unit_price": {
"amount": "1099",
"currency_code": "USD"
},
"unit_price_overrides": [],
"custom_data": null,
"quantity": {
"minimum": 1,
"maximum": 100
},
"status": "active"
},
"quantity": 1
}
],
"details": {
"tax_rates_used": [
{
"tax_rate": "0",
"totals": {
"subtotal": "1099",
"discount": "0",
"tax": "0",
"total": "1099"
}
}
],
"totals": {
"subtotal": "1099",
"tax": "0",
"discount": "0",
"total": "1099",
"grand_total": "1099",
"fee": null,
"credit": "0",
"credit_to_balance": "0",
"balance": "1099",
"earnings": null,
"currency_code": "USD"
},
"adjusted_totals": {
"subtotal": "1099",
"tax": "0",
"total": "1099",
"grand_total": "1099",
"fee": "0",
"earnings": "0",
"currency_code": "USD"
},
"payout_totals": null,
"adjusted_payout_totals": null,
"line_items": [
{
"id": "txnitm_01hj3scte0r426j1nbaheptrtj",
"price_id": "pri_01hj3sctd36bwevs47dw8jxdkn",
"quantity": 1,
"totals": {
"subtotal": "1099",
"tax": "0",
"discount": "0",
"total": "1099"
},
"product": {
"id": "pro_01hj3sctbh6r2hyga7qg29dznq",
"name": "Invigaron VIP pass",
"description": "Lock in 200x Invigaron Berries a month, plus faster gem spawns, exclusive skins, and early access to the leaderboard.",
"type": "custom",
"tax_category": "standard",
"image_url": null,
"custom_data": null,
"status": "active"
},
"tax_rate": "0",
"unit_totals": {
"subtotal": "1099",
"tax": "0",
"discount": "0",
"total": "1099"
}
}
]
},
"payments": [],
"checkout": {
"url": "https://aeroedit.com/pay?_ptxn=txn_01hj3sct9my6jsx9zt55thzpfw"
}
},
"meta": {
"request_id": "69845039-96b9-4ab5-a339-bc21dc401cee"
}
}

Update a non-catalog price or product

Non-catalog products and prices are created for specific transactions. They're not considered part of your product catalog. You shouldn't ordinarily need to update them.

Non-catalog products and prices have Paddle IDs, so you can update them using the update a product or update a price operations if needed. For example, you might correct a spelling error in a name or description — especially where an item is recurring.

To learn more, see Create products and prices

Add a non-catalog item to your catalog

If you find yourself adding similar non-catalog prices or products to transactions, you might like to add a custom item you've previously worked with to your product catalog.

We recommend that you create a new product or price in your catalog where you're adding an item to your standard offering.

You can also get an existing custom price or product using its ID, then change the type to standard.

Set type to standard to add the item to your product catalog. The type field exists against both product and price entities.

PATCH /products/{product_id}
Request
{
"type": "standard"
}
Response (200 OK)
{
"data": {
"id": "pro_01hj3sctbh6r2hyga7qg29dznq",
"name": "Invigaron VIP pass",
"tax_category": "standard",
"type": "standard",
"description": "Lock in 200x Invigaron Berries a month, plus faster gem spawns, exclusive skins, and early access to the leaderboard.",
"image_url": null,
"custom_data": null,
"status": "active",
"import_meta": null,
"created_at": "2023-12-20T14:17:10.769Z",
"updated_at": "2023-12-20T14:18:35.093Z"
},
"meta": {
"request_id": "dc625fb7-38b8-47b5-8497-fe51e5c1a2e3"
}
}

Events

transaction.created Occurs when a transaction is created.
price.created Occurs when a price is created.
product.created Occurs when a product is created.

Was this page helpful?