All purchases are transactions. They hold all the information about a customer purchase, including customer details, items, calculated tax and localized pricing, and payments.
Paddle automatically creates transactions for subscription lifecycle events and when checkouts are opened, but you can create your own transactions using the API or Paddle dashboard.
How it works
Transactions are at the heart of Paddle. They tie together products, prices, and discounts with customers to calculate and capture revenue for checkouts, invoices, and subscriptions.
All revenue in Paddle is calculated and captured using transactions. Paddle creates transactions automatically for subscription lifecycle events and when checkouts are opened, and you may also create your own transactions using the API or Paddle dashboard.
Transaction lifecycle
Transactions are initially created as draft or ready, depending on the information supplied. As you work with a transaction entity, they move to completed:
Draft
A transaction is in the draft state when it’s missing required fields for billing. For example, checkouts opened by Paddle.js with only items will create draft transactions, since they initially lack customer and address information.
Ready
A transaction moves to ready once it has all required billing fields. For Paddle Checkout, this happens when details like the customer’s name, country, and (in some regions) ZIP or postal code have been captured.
Billed
You can optionally mark a transaction as billed, making it a financial record that can’t be changed. This is usually part of an invoicing workflow to issue an invoice, or to lock items and quantities at checkout so customers can’t edit them.
Paid
When Paddle successfully collects payment, the transaction moves to paid. This is a brief, interim state while Paddle finishes transaction processing—updating things like fees, earnings, payout totals, and setting related fields like subscription_id or invoice_number for automatically-collected transactions.
Transaction processing typically takes less than a second, so you’ll rarely see transactions in the paid state when using the API.
Completed
Once all transaction processing is finished, the transaction becomes completed.
Paddle automatically sets transactions as draft, ready, paid, and completed. You can set transactions as billed or canceled using the API.
This guide focuses on creating automatically-collected transactions. You can also create manually-collected transactions, which send invoice documents the customer must pay manually.
Before you begin
- Set your default payment link
Set your default payment link under Paddle > Checkout > Checkout settings > Default payment link and get it approved. - Create products and prices
Transactions work with products and prices to say what a customer is purchasing, so you'll also need to create a product and a related price to bill for an item in your catalog.
If you're working with the Paddle dashboard, you can create all the entities that you'll be working with as you create your invoice (manually-collected transaction). If you're working with the API, you'll need to:
- Create a customer and a related address
- Optionally create a related business
Create a draft or ready transaction
Draft transactions contain an items list, but don't include address or customer details which are required for billing. Ready transactions contain an items list and all required fields for billing, including address and customer details.
You may pass a draft or ready transaction to a checkout to capture customer or address information, and collect for payment.
- Go to Paddle > Invoices.
- Click New invoice .
- Set customer details, including the customer, address, and business that this transaction is for.
- Use the Currency dropdown box to select a currency for this transaction.
- Choose a product, related price, and quantity for your first item.
- Click Add line item to add more items if you want.
- Under the How do you want the customer to pay? section, choose Automatically, using a stored payment method.
- Click Continue , then review the summary.
- Click Generate payment link to create a ready transaction.
- Use the Copy button to copy the link to send to your customer to collect payment using Paddle Checkout.
Create a draft or ready transaction using the API in two steps:
- Preview the transaction Optional
Preview charging information before creating the transaction. - Create the transaction
Send the request to create the transaction.
Build an items array with an object containing a price ID and quantity (catalog items) or price objects (non-catalog items) to specify what the customer is purchasing.
Include customer_id and address_id to create a ready transaction. Paddle automatically marks it as ready when both are present. Omit them for a draft transaction you'll pass to a checkout later.
Include business_id if the transaction is for a business.
Recurring items on a transaction must have the same billing interval. For example, you can't have a transaction with some prices that are billed monthly and some products that are billed annually.
Preview transaction Optional
Send a POST request to the /transactions/preview endpoint to see tax and localized pricing before creating a transaction.
Paddle returns a preview of the new transaction entity, but doesn't create it at this point.
{ "items": [ { "quantity": 10, "price_id": "pri_01gsz8x8sawmvhz1pv30nge1ke" } ], "customer_id": "ctm_01h8441jn5pcwrfhwh78jqt8hk", "address_id": "add_01h848pep46enq8y372x7maj0p"}{ "data": { "customer_id": "ctm_01h8441jn5pcwrfhwh78jqt8hk", "address_id": "add_01h848pep46enq8y372x7maj0p", "business_id": null, "subscription_id": null, "currency_code": "USD", "address": { "postal_code": "10021", "country_code": "US" }, "customer_ip_address": null, "discount_id": null, "items": [ { "price": { "id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "description": "Monthly (per seat)", "name": "Monthly (per seat)", "product_id": "pro_01gsz4t5hdjse780zja8vvr7jg", "billing_cycle": { "interval": "month", "frequency": 1 }, "trial_period": null, "tax_mode": "account_setting", "unit_price": { "amount": "3000", "currency_code": "USD" }, "unit_price_overrides": [ { "country_codes": ["AU"], "unit_price": { "amount": "5000", "currency_code": "AUD" } } ], "custom_data": { "features": { "crm": true, "data_retention": false, "reports": true }, "suggested_addons": [ "pro_01h1vjes1y163xfj1rh1tkfb65", "pro_01gsz97mq9pa4fkyy0wqenepkz" ], "upgrade_description": "Move from Basic to Pro to take advantage of advanced reporting and a CRM that's right where you're chatting." }, "quantity": { "minimum": 1, "maximum": 999 }, "status": "active" }, "quantity": 10, "proration": null, "include_in_totals": true } ], "details": { "tax_rates_used": [ { "tax_rate": "0.08875", "totals": { "subtotal": "30000", "discount": "0", "tax": "2662", "total": "32662" } } ], "totals": { "subtotal": "30000", "tax": "2662", "discount": "0", "total": "32662", "grand_total": "32662", "fee": null, "credit": "0", "balance": "32662", "earnings": null, "currency_code": "USD" }, "line_items": [ { "price_id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "quantity": 10, "totals": { "subtotal": "30000", "tax": "2662", "discount": "0", "total": "32662" }, "product": { "id": "pro_01gsz4t5hdjse780zja8vvr7jg", "name": "ChatApp Pro", "description": "Everything in basic, plus access to a suite of powerful tools and features designed to take your team's productivity to the next level.", "tax_category": "standard", "image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/2nmP8MQSret0aWeDemRw_icon1.png", "custom_data": { "features": { "crm": true, "data_retention": false, "reports": true }, "suggested_addons": [ "pro_01h1vjes1y163xfj1rh1tkfb65", "pro_01gsz97mq9pa4fkyy0wqenepkz" ], "upgrade_description": "Move from Basic to Pro to take advantage of advanced reporting and a CRM that's right where you're chatting." }, "status": "active" }, "tax_rate": "0.08875", "unit_totals": { "subtotal": "3000", "tax": "266", "discount": "0", "total": "3266" } } ] }, "ignore_trials": false, "available_payment_methods": [] }, "meta": { "request_id": "a47ce991-b4aa-47fe-b91e-a28ea05d0788" }}Create transaction
Send a POST request to the /transactions endpoint to create a transaction.
In your request, include the same body as the preview request.
Paddle responds with a copy of the new transaction entity with the status of draft or ready, depending on the information you sent. The new transaction has collection_mode: automatic. If no payment method is saved, pass this transaction to a checkout to collect payment.
{ "items": [ { "quantity": 10, "price_id": "pri_01gsz8x8sawmvhz1pv30nge1ke" } ], "customer_id": "ctm_01h8441jn5pcwrfhwh78jqt8hk", "address_id": "add_01h848pep46enq8y372x7maj0p"}{ "data": { "id": "txn_01hgk505qdyvbrmhpp14b97jgz", "status": "ready", "customer_id": "ctm_01h8441jn5pcwrfhwh78jqt8hk", "address_id": "add_01h848pep46enq8y372x7maj0p", "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-01T16:57:12.591685111Z", "updated_at": "2023-12-01T16:57:12.591685111Z", "billed_at": null, "items": [ { "price": { "id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "description": "Monthly (per seat)", "name": "Monthly (per seat)", "product_id": "pro_01gsz4t5hdjse780zja8vvr7jg", "billing_cycle": { "interval": "month", "frequency": 1 }, "trial_period": null, "tax_mode": "account_setting", "unit_price": { "amount": "3000", "currency_code": "USD" }, "unit_price_overrides": [ { "country_codes": ["AU"], "unit_price": { "amount": "5000", "currency_code": "AUD" } } ], "custom_data": { "features": { "crm": true, "data_retention": false, "reports": true }, "suggested_addons": [ "pro_01h1vjes1y163xfj1rh1tkfb65", "pro_01gsz97mq9pa4fkyy0wqenepkz" ], "upgrade_description": "Move from Basic to Pro to take advantage of advanced reporting and a CRM that's right where you're chatting." }, "quantity": { "minimum": 1, "maximum": 999 }, "status": "active" }, "quantity": 10 } ], "details": { "tax_rates_used": [ { "tax_rate": "0.08875", "totals": { "subtotal": "30000", "discount": "0", "tax": "2662", "total": "32662" } } ], "totals": { "subtotal": "30000", "tax": "2662", "discount": "0", "total": "32662", "grand_total": "32662", "fee": null, "credit": "0", "balance": "32662", "earnings": null, "currency_code": "USD" }, "adjusted_totals": { "subtotal": "30000", "tax": "2662", "total": "32662", "grand_total": "32662", "fee": "0", "earnings": "0", "currency_code": "USD" }, "payout_totals": null, "adjusted_payout_totals": null, "line_items": [ { "id": "txnitm_01hgk506447jwy5zfzwxcg8tgr", "price_id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "quantity": 10, "totals": { "subtotal": "30000", "tax": "2662", "discount": "0", "total": "32662" }, "product": { "id": "pro_01gsz4t5hdjse780zja8vvr7jg", "name": "ChatApp Pro", "description": "Everything in basic, plus access to a suite of powerful tools and features designed to take your team's productivity to the next level.", "tax_category": "standard", "image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/2nmP8MQSret0aWeDemRw_icon1.png", "custom_data": { "features": { "crm": true, "data_retention": false, "reports": true }, "suggested_addons": [ "pro_01h1vjes1y163xfj1rh1tkfb65", "pro_01gsz97mq9pa4fkyy0wqenepkz" ], "upgrade_description": "Move from Basic to Pro to take advantage of advanced reporting and a CRM that's right where you're chatting." }, "status": "active" }, "tax_rate": "0.08875", "unit_totals": { "subtotal": "3000", "tax": "266", "discount": "0", "total": "3266" } } ] }, "payments": [], "checkout": { "url": "https://aeroedit.com/pay?_ptxn=txn_01hgk505qdyvbrmhpp14b97jgz" } }, "meta": { "request_id": "a494e29b-97d2-4786-8c8a-5af4ba7a9735" }}Update a transaction
While a transaction is draft or ready, you can make changes to it and the items on it. You can work with items, apply a discount, change customer information, or add or remove custom data.
If you're working with a draft transaction, Paddle automatically marks it as ready when you add customer_id and address_id.
Transactions are financial records. You can't edit them if they're billed, canceled, or completed. Cancel a transaction and create another or create an adjustment if you need to make changes to a billed or completed transaction.
- Go to Paddle > Transactions.
- Find a transaction in the list, then click the button and choose View transaction .
- Click Edit transaction
- Change customer details or items on the transaction.
- Click Continue , then review the change summary.
- Click Save when you're done.
Send a PATCH request to the /transactions/{transaction_id} endpoint to update a transaction.
In your request, include the fields you want to change. When working with items, send the complete list you want against the transaction — Paddle removes any items you omit. To learn more, see Work with lists.
This example adds a discount to a transaction using discount_id.
{ "discount_id": "dsc_01gy7qp5pqhnyd22yspwane77h"}{ "data": { "id": "txn_01gzkcdstcwq4cj8waj812v9my", "status": "ready", "customer_id": "ctm_01gzgmxdmgkgc7p94b5kgqq82p", "address_id": "add_01gzkce0amtjsqv8xxd1rv3dna", "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": "GBP", "discount_id": "dsc_01gy7qp5pqhnyd22yspwane77h", "created_at": "2025-05-04T12:40:07.834144Z", "updated_at": "2025-05-18T13:59:56.611406607Z", "billed_at": null, "items": [ { "price": { "id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "description": "Monthly (per seat)", "product_id": "pro_01gsz4t5hdjse780zja8vvr7jg", "billing_cycle": { "interval": "month", "frequency": 1 }, "trial_period": null, "tax_mode": "account_setting", "unit_price": { "amount": "3000", "currency_code": "GBP" }, "unit_price_overrides": [], "quantity": { "minimum": 10, "maximum": 999 }, "status": "active" }, "quantity": 10 }, { "price": { "id": "pri_01gsz95g2zrkagg294kpstx54r", "description": "Monthly (recurring addon)", "product_id": "pro_01gsz92krfzy3hcx5h5rtgnfwz", "billing_cycle": { "interval": "month", "frequency": 1 }, "trial_period": null, "tax_mode": "account_setting", "unit_price": { "amount": "25000", "currency_code": "GBP" }, "unit_price_overrides": [], "quantity": { "minimum": 1, "maximum": 1 }, "status": "active" }, "quantity": 1 }, { "price": { "id": "pri_01gsz98e27ak2tyhexptwc58yk", "description": "One-time charge", "product_id": "pro_01gsz97mq9pa4fkyy0wqenepkz", "trial_period": null, "tax_mode": "account_setting", "unit_price": { "amount": "19900", "currency_code": "GBP" }, "unit_price_overrides": [], "quantity": { "minimum": 1, "maximum": 1 }, "status": "active" }, "quantity": 1 } ], "details": { "tax_rates_used": [ { "tax_rate": "0.2", "totals": { "subtotal": "74900", "discount": "7490", "tax": "13482", "total": "80892" } } ], "totals": { "subtotal": "74900", "tax": "13482", "discount": "7490", "total": "80892", "fee": null, "credit": "0", "balance": "80892", "earnings": null, "currency_code": "GBP" }, "payout_totals": null, "line_items": [ { "id": "txnitm_01h0qjj0ds7arpp88m5b2c399g", "price_id": "pri_01gsz8x8sawmvhz1pv30nge1ke", "quantity": 10, "totals": { "subtotal": "30000", "tax": "5400", "discount": "3000", "total": "32400" }, "product": { "id": "pro_01gsz4t5hdjse780zja8vvr7jg", "name": "ChatApp Pro", "description": "Everything in basic, plus access to a suite of powerful tools and features designed to take your team's productivity to the next level.", "tax_category": "standard", "image_url": "https://twemoji.maxcdn.com/v/latest/72x72/2708.png", "status": "active" }, "tax_rate": "0.2", "unit_totals": { "subtotal": "3000", "tax": "540", "discount": "300", "total": "3240" } }, { "id": "txnitm_01h0qjj0ds7arpp88m5cpvrx0p", "price_id": "pri_01gsz95g2zrkagg294kpstx54r", "quantity": 1, "totals": { "subtotal": "25000", "tax": "4500", "discount": "2500", "total": "27000" }, "product": { "id": "pro_01gsz92krfzy3hcx5h5rtgnfwz", "name": "Reporting module", "description": "Get access to comprehensive reports and customizable analytics dashboards.", "tax_category": "standard", "image_url": "https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/72x72/1f481-1f3fe.png", "status": "active" }, "tax_rate": "0.2", "unit_totals": { "subtotal": "25000", "tax": "4500", "discount": "2500", "total": "27000" } }, { "id": "txnitm_01h0qjj0ds7arpp88m5gacvc0q", "price_id": "pri_01gsz98e27ak2tyhexptwc58yk", "quantity": 1, "totals": { "subtotal": "19900", "tax": "3582", "discount": "1990", "total": "21492" }, "product": { "id": "pro_01gsz97mq9pa4fkyy0wqenepkz", "name": "Custom domains", "description": "Make ChatApp truly your own with custom domains! Custom domains reinforce your brand identity and make it easy for your team to access ChatApp.", "tax_category": "standard", "image_url": "https://twemoji.maxcdn.com/v/latest/72x72/1f30e.png", "status": "active" }, "tax_rate": "0.2", "unit_totals": { "subtotal": "19900", "tax": "3582", "discount": "1990", "total": "21492" } } ] }, "payments": [], "checkout": { "url": "https://aeroedit.com/pay?_ptxn=txn_01gzkcdstcwq4cj8waj812v9my" } }, "meta": { "request_id": "415a5995-bece-4775-8fb6-54be15c004d6" }}Change collection mode
While a transaction is draft or ready, you can switch between automatic and manual collection modes.
To learn more, see Change transaction collection mode
Mark a transaction as billed
You can mark a transaction as billed using the API to say it's finalized, meaning it's considered a financial record and can't be changed.
This is typically used for manually-collected transactions (invoices), as part of an invoicing workflow. Marking a transaction as billed is the same as issuing an invoice. It gets an invoice number and is sent to the customer.
You don't need to mark an automatically-collected transaction as billed, and it's not typically part of a self-service workflow. However, you may like to do this if you plan to create a checkout for this transaction to prevent a customer from changing items or quantities at checkout.
To learn more, see Issue an invoice
You can create a transaction and mark it as billed by including "status": "billed" in your initial request, along with the other required fields — no need to make a separate request.
Pass a transaction to a checkout
Automatically-collected transactions include checkout.url, which you can send to customers to open a checkout to capture customer information and collect payment for this transaction.
You can also pass a transaction to a checkout using Paddle.js to collect for it.
Revise customer information for billed or completed transactions
Billed and completed transactions are considered financial records for compliance purposes. This means they can't be deleted or changed directly. You can revise customer information for billed or completed transactions to update information like tax or VAT number, address details, or customer name.
To learn more, see Revise customer details on a billed or completed transaction
Events
transaction.created | Occurs when a transaction is created. |
transaction.updated | Occurs when a transaction is updated. |
transaction.ready | Occurs when a transaction is ready to be billed. Its status field changes to ready. |
transaction.billed | Occurs when a transaction is billed. Its status field changes to billed and billed_at is populated. |