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
Paddle Docs home

Set up usage-based billing

Include prepaid usage with subscription plans, report usage as it happens, and let Paddle track each customer's usage balance.

AI summary

Set up metered usage tracking with Paddle to grant customers an allowance of measurable actions—like API calls or tokens—that draws down as they use your product.

  • •Create usage balance units and meters to define what you measure and which actions trigger deductions, then add allowances to recurring prices to grant customers a fixed amount each billing period
  • •Report usage events to Paddle whenever customers use metered features, and Paddle automatically tracks their balance and sends a webhook when they run out
  • •Query customer usage balances via the API to check remaining allowance before allowing features, and handle the usage_balance.depleted webhook to restrict access or prompt upgrades when customers exhaust their allocation

Usage-based billing is in early access (beta)

Read this guide to see how it works, then apply to join the program. We'll reach out if you meet the program requirements.

Usage-based billing lets you include prepaid usage with subscription plans, then report usage to Paddle as customers use your app. Paddle grants usage when customers subscribe and renew, keeps a running balance for each customer, and tells you when a balance runs out.

It's a good fit for AI apps, APIs, and other products where plans come with an allowance, like 10,000 API calls, 1 million tokens, or 500 document exports.

What are we building?

In this tutorial, we'll set up a Pro plan for an API product. The plan includes 10,000 API calls each month. Every time a customer calls your API, your app reports it to Paddle, and Paddle draws down the customer's balance.

We'll learn how to:

  • Define what you measure using a usage balance unit and a meter.
  • Add an allowance to a price, so customers get usage when they subscribe.
  • Report usage to Paddle and read customer balances.
  • Restrict access or prompt an upgrade when a customer runs out.

How it works

Usage balance units, meters, and allowances

Usage-based billing uses three catalog entities:

  • Usage balance units describe what customers hold a balance of, like API calls, tokens, or credits. In the Paddle dashboard, they're called units.
  • Meters turn usage events into usage. Each meter has an action, like api_call, and draws down one usage balance unit. When you report usage for an action, every meter for that action draws down its unit.
  • Allowances on prices say how much of a usage balance unit a customer gets each billing period. A price can include allowances for more than one unit.

Each meter also has a rate: how much of its unit each unit of usage draws down. Rates let multiple features share one balance at different costs. For example, if customers hold a balance of credits, a chat_message meter could have a rate of 1 and a report_export meter a rate of 25, so each export draws down 25 credits. Rates can be decimals, like 0.001 to draw down one credit for every 1,000 tokens.

flowchart LR
    price["Price<br>allowances"] -- "grants each<br>billing period" --> balance["Usage balance<br>one per customer, per unit"]
    events["Usage events<br>action + quantity"] -- "matched by action" --> meter["Meter<br>action → unit, at a rate"]
    meter -- "draws down" --> balance
    unit["Usage balance unit<br>what customers hold"] -.->|granted by| price
    unit -.->|drawn down by| meter

Usage balances

When a customer subscribes to a price with an allowance, Paddle creates a usage balance for them automatically. There's one usage balance for each customer and usage balance unit. If a customer has more than one subscription that includes the same unit, their allowances are combined into one balance.

Each usage balance reports:

  • used: how much of the allowance the customer has used this billing period.
  • remaining: how much of the allowance is left. It counts down to 0 and never goes negative.
  • overage: usage recorded after remaining reached 0.

During early access (beta), Paddle never blocks usage or bills for overage. When a balance runs out, Paddle keeps recording usage as overage, and you decide whether to keep providing the feature.

Usage balances aren't the same as customer credit balances, which hold money from adjustments.

Billing periods

Allowances follow the subscription's billing period. When a subscription renews, unused usage from the previous period expires, and Paddle grants the full allowance for the new period and clears any overage. Unused usage doesn't roll over.

sequenceDiagram
    participant Customer
    participant App as Your app
    participant API as Paddle API
    participant WH as Paddle webhooks
    Note over Customer,WH: Customer subscribes
    Customer->>API: Completes checkout for the Pro plan
    API->>API: Creates a usage balance with 10,000 API calls
    Note over Customer,WH: Customer uses the app
    Customer->>App: Makes an API call (uses usage)
    App->>API: POST /usage-events
    API-->>App: 202 Accepted
    API->>API: Draws down the usage balance
    App->>API: GET /customers/{customer_id}/usage-balances
    API-->>App: used, remaining, overage
    Note over Customer,WH: Balance runs out
    WH->>App: usage_balance.depleted
    App->>Customer: Restricts access or prompts an upgrade
    Note over Customer,WH: Subscription renews
    API->>API: Expires unused API calls, grants 10,000 more, clears overage

Early access (beta) limitations

Usage-based billing is in early access (beta), so fields and behavior may change before general release. Some features aren't available yet:

Not available during early access (beta)What to know
TrialsYou can't add allowances to a price with a trial period.
One-time pricesAllowances are for recurring prices only.
Manually-collected subscriptionsPaddle rejects manually-collected transactions and subscriptions for prices with allowances.
Prorated plan changesUse full_immediately, full_next_billing_period, or do_not_bill when changing plans.
Top-upsCustomers get more usage when their subscription renews or when they change plan.
Billing for overagePaddle records usage beyond the allowance but doesn't bill for it. Overage clears when the subscription renews.
Batched usage eventsSend one usage event per request.
Other aggregation typesMeters add up the quantity of each usage event.
Other balance thresholdsPaddle sends a webhook when a balance runs out. There's no webhook for other thresholds, like 80% used.
Custom expiryUnused usage expires at the end of each billing period.
ReportingThere are no usage reports yet. Use the API to get usage balances.

If you need any of these, or more specialized usage billing, you can use a third-party usage billing provider with Paddle instead. The provider tracks and prices usage, and you bill for it through Paddle, for example with one-time charges.

Overview

Set up usage-based billing in six steps:

  1. Create a usage balance unit and meter
    Define what customers hold a balance of, and the action that draws it down.
  2. Add an allowance to a price
    Set how much usage a plan includes each billing period.
  3. Let customers subscribe
    Open a checkout as normal. Paddle creates a usage balance when the subscription activates.
  4. Report usage
    Send a usage event to Paddle each time a customer uses a metered feature.
  5. Check balances and restrict access
    Get usage balances and handle usage_balance.depleted to decide what customers can do.
  6. Handle renewals and plan changes
    Learn what happens to balances when subscriptions renew, change, pause, or cancel.

Before you begin

  • Join early access (beta)
    Usage-based billing is available to accounts in the early access (beta) program. Apply using the form on this page, then test in a sandbox account.
  • Create or update an API key
    Create an API key, or update an existing one, with these permissions: usage_balance_unit.write, meter.write, price.write, usage_event.write, and usage_balance.read.
  • Create a product
    Create a product for your plan. We'll add a price with an allowance to it.
  • Set up a notification destination
    Create or update a notification destination that's subscribed to usage_balance.depleted.
  • Set up checkout
    Customers subscribe using Paddle Checkout, like an overlay checkout.

Use an AI agent

Invoke the paddle-usage-based-billing skill included in our agent skills and plugins for Claude Code, Codex, and Cursor to build a usage-based billing integration.

Create a usage balance unit and meter

Start by defining what customers hold a balance of and what draws it down. For our API product, the usage balance unit is API calls, and the meter counts each call.

The Paddle dashboard creates a unit and a meter together.

  1. Go to Paddle > Catalog > Meters.
  2. Click New meter
  3. Under Unit, choose New, then enter a name for the unit, like call. To draw down a unit you already created, choose Existing instead.
  4. Under Meter, enter a display name, like API calls, and an action, like api_call. You send the action with usage events.
  5. Leave Aggregation set to Sum. It's the only option during early access (beta).
  6. Leave Meter weight set to 1. It's the meter's rate, so each call draws down one call from the balance.
  7. Click Save

Create a usage balance unit

Send a POST request to the /usage-balance-units endpoint. Include a name and a unit_name, which is the plural name of what customers hold a balance of.

If successful, Paddle responds with a copy of the new usage balance unit entity. Paddle creates an id starting with ubu_. Keep this for the next step to associate this unit with a meter.

POST/usage-balance-units
Request
{
"name": "API calls",
"unit_name": "calls"
}
Response (201 Created)
{
"data": {
"id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"name": "API calls",
"unit_name": "calls",
"status": "active",
"created_at": "2026-09-23T09:00:00.000Z",
"updated_at": "2026-09-23T09:00:00.000Z"
},
"meta": {
"request_id": "1681f87f-9c36-4557-a1da-bbb622afa0cc"
}
}

Create a meter

Send a POST request to the /meters endpoint. Include:

  • usage_balance_unit_id: Paddle ID of the usage balance unit this meter draws down.
  • name: a name for the meter, shown in the Paddle dashboard.
  • action: the name you send with usage events. Use lowercase letters, numbers, and underscores, starting with a letter.
  • unit_name: the singular name of what the meter measures.
  • rate: how much of the usage balance unit each unit of usage draws down. Set it to "1" so each call draws down one call from the balance.

aggregation defaults to sum, the only option during early access (beta).

If successful, Paddle responds with a copy of the new meter entity.

POST/meters
Request
{
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"name": "API calls",
"action": "api_call",
"description": "Calls to the public API",
"unit_name": "call",
"rate": "1"
}
Response (201 Created)
{
"data": {
"id": "mtr_01kvqjfc6eb9kzk7s2wvz2aamq",
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"name": "API calls",
"action": "api_call",
"description": "Calls to the public API",
"aggregation": "sum",
"unit_name": "call",
"rate": "1",
"custom_data": null,
"status": "active",
"created_at": "2026-09-23T09:01:00Z",
"updated_at": "2026-09-23T09:01:00Z"
},
"meta": {
"request_id": "cf40234b-e140-44d1-a83f-7bbdedd88589"
}
}

Keep in mind:

  • You can't change a meter's usage balance unit or aggregation. Create a new meter instead.
  • More than one meter can draw down the same unit. For example, meters with the actions api_call and bulk_api_call could both draw down calls.
  • Two meters can't have the same action and the same unit, or a single usage event would draw down the balance twice. Paddle returns meter_action_usage_balance_unit_duplicate if you try.
  • Archived meters still count usage. Archiving a meter hides it from lists, but usage events for its action still draw down balances.
  • Changes to rate apply to usage from the time you make them. Paddle doesn't recalculate usage that's already recorded.

Add an allowance to a price

Next, add an allowance to a recurring price. The allowance is how much of the usage balance unit a customer gets each billing period. For our Pro plan, that's 10,000 API calls a month.

  1. Go to Paddle > Catalog > Products, then click the product for your plan.
  2. Under the Prices section, click New price
  3. Enter details for your price, and set a billing period so it's recurring.
  4. Turn on Usage billing. This turns off the trial period, since prices with a trial can't include usage.
  5. Under Unit, choose Existing, then select the unit you created. To create a unit and meter here instead, choose New.
  6. Enter how many units the price includes each billing period, like 10000.
  7. Click Save

To include more than one unit, click Add unit before saving.

Send a POST request to the /prices endpoint to create a price, including a billing_cycle and an allowances array. Each allowance has:

  • usage_balance_unit_id: Paddle ID of the usage balance unit to grant.
  • amount: how much of the unit the price includes each billing period.

If successful, Paddle responds with a copy of the new price entity, including the allowances array.

POST/prices
Request
{
"description": "Pro plan (monthly)",
"name": "Pro",
"product_id": "pro_01htz88xpr0mm7b3ta2pjkr7w2",
"unit_price": {
"amount": "2000",
"currency_code": "USD"
},
"billing_cycle": {
"interval": "month",
"frequency": 1
},
"allowances": [
{
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"amount": "10000"
}
]
}
Response (201 Created)
{
"data": {
"id": "pri_01hv0vax6rv18t4tamj848ne4d",
"product_id": "pro_01htz88xpr0mm7b3ta2pjkr7w2",
"type": "standard",
"description": "Pro plan (monthly)",
"name": "Pro",
"billing_cycle": {
"interval": "month",
"frequency": 1
},
"trial_period": null,
"tax_mode": "account_setting",
"unit_price": {
"amount": "2000",
"currency_code": "USD"
},
"unit_price_overrides": [],
"allowances": [
{
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"amount": "10000"
}
],
"quantity": {
"minimum": 1,
"maximum": 100
},
"status": "active",
"custom_data": null,
"import_meta": null,
"created_at": "2026-09-23T09:05:00.000Z",
"updated_at": "2026-09-23T09:05:00.000Z"
},
"meta": {
"request_id": "9e7f51e8-838b-4b2c-b0fa-d52d0593354c"
}
}

To add allowances to an existing recurring price, send a PATCH request to the /prices/{price_id} endpoint with allowances. Paddle replaces the existing allowances with the array you send, so include every allowance you want to keep.

Keep in mind:

  • Allowances are for recurring prices without a trial period. Paddle returns price_allowance_not_allowed_for_trial_price if a price has a trial period, and price_allowance_not_allowed_for_one_off_price if it has no billing cycle.
  • A price can include up to 20 allowances, one for each usage balance unit.
  • Allowances multiply by quantity. If a customer buys three of a price that includes 10,000 API calls, they get 30,000 API calls.
  • An allowance can be 0. The customer gets a usage balance with nothing in it, so Paddle records all their usage as overage. Use this to track usage on a plan without including any.

Let customers subscribe

Customers subscribe to a plan with an allowance the same way as any other plan. Open a checkout for the price using Paddle.js, or create a transaction and pass it to a checkout.

When the subscription activates, Paddle automatically creates a usage balance for the customer and grants the allowance. Only automatically-collected subscriptions can include usage during early access (beta).

To check a customer's usage balance:

  1. Go to Paddle > Customers.
  2. Click the customer in the list.
  3. Scroll to the Usage balance section.

The Usage balance section shows how much of each usage balance unit the customer has been allocated, has used, and has left. It only appears once the customer has a usage balance.

Send a GET request to the /customers/{customer_id}/usage-balances endpoint. Paddle returns a usage balance with the full allowance remaining.

GET/customers/{customer_id}/usage-balances
Response (200 OK)
Response (200 OK)
{
"data": [
{
"id": "ubl_01h9zx4p8q2r5t7v9w1y3z5b7d",
"customer_id": "ctm_01gw9m680k848184fpttwr0b7z",
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"balance": {
"used": {
"total": "0",
"subscription": "0"
},
"remaining": {
"total": "10000",
"subscription": "10000"
},
"overage": {
"total": "0"
}
},
"created_at": "2026-09-23T10:00:00Z",
"updated_at": "2026-09-23T10:00:00Z"
}
],
"meta": {
"request_id": "bb093d50-ddb5-401a-a5ba-034b187b396e",
"pagination": {
"per_page": 50,
"next": "https://sandbox-api.paddle.com/customers/ctm_01gw9m680k848184fpttwr0b7z/usage-balances?after=ubl_01h9zx4p8q2r5t7v9w1y3z5b7d",
"has_more": false,
"estimated_total": 1
}
}
}

Customers can see their balance in the customer portal. The subscription page shows a usage balance card with how much they've used and how much is left.

Report usage

Each time a customer uses a metered feature, send a usage event to Paddle. Paddle finds meters that match the event's action and draws down the customer's usage balance.

Send a POST request to the /usage-events endpoint with an events array. Each event has:

  • event_key: a unique key for this usage from your system, like a job or request ID.
  • customer_id: Paddle ID of the customer that used the feature.
  • action: the action of the meter to draw down, like api_call.
  • quantity: how much the customer used, as a string. For example, "1" for one API call.
  • occurred_at: when the usage happened, as an RFC 3339 timestamp in UTC. Paddle rejects events more than 60 days in the past with usage_event_timestamp_too_old, and more than 24 hours in the future with usage_event_future_timestamp.

Send one event per request during early access (beta). Requests with more than one event return an error.

POST/usage-events
Request
{
"events": [
{
"event_key": "call_7f3a9c2e",
"customer_id": "ctm_01gw9m680k848184fpttwr0b7z",
"action": "api_call",
"quantity": "1",
"occurred_at": "2026-09-23T10:15:00Z"
}
]
}
Response (202 Accepted)
{
"data": {
"events": [
{
"event_key": "call_7f3a9c2e",
"status": "accepted"
}
]
},
"meta": {
"request_id": "cf40234b-e140-44d1-a83f-7bbdedd88589"
}
}

Paddle responds with 202 Accepted and a status for each event:

  • accepted: Paddle received the event. It draws down the usage balance shortly after, so a balance you get straight away might not include it yet.
  • rejected: Paddle didn't record the event. The error object says why. Fix the problem, then send the event again.

To avoid counting usage twice, Paddle uses event_key and occurred_at together to identify an event. If a request fails or times out, retry it with the same event_key and occurred_at, and Paddle counts it once. If you retry with a new occurred_at, Paddle counts it as new usage.

Send usage events when usage happens. If an event arrives shortly after a subscription renews, Paddle still counts it against the billing period when the usage occurred.

Check that action matches a meter. Paddle accepts events for actions that don't have a meter, but they don't draw down any usage balance.

Queue events Recommended

To make sure usage isn't lost or counted twice, save it in your app before you send it to Paddle. For example, use an outbox:

  1. When a customer uses a metered feature, save a record of the usage in the same database transaction as the work itself. Include the event_key and occurred_at you'll send.
  2. Send saved records to Paddle from a background job, so customers don't wait on the request.
  3. Mark records as sent when Paddle accepts them. Retry failed requests with the same event_key and occurred_at, and flag rejected events for review.

Run the job often, and alert if records stay unsent. Paddle rejects events more than 60 days old, including retries. If Paddle accepted an event before you retried it, the original still counts, so don't change occurred_at to get a retry accepted.

Check balances and restrict access

During early access (beta), Paddle doesn't block customers when they run out, so use usage balances to decide what customers can do in your app.

Before you build this, decide what should happen when a customer runs out: block the feature, keep providing it and prompt them to upgrade, or keep providing it without a prompt.

Get usage balances

Get a customer's usage balances to show how much they have left or to check before starting a metered action.

Send a GET request to the /customers/{customer_id}/usage-balances endpoint. Paddle returns a usage balance for each usage balance unit the customer has. In this example, the customer has used 3,500 of their 10,000 API calls this billing period.

GET/customers/{customer_id}/usage-balances
Response (200 OK)
Response (200 OK)
{
"data": [
{
"id": "ubl_01h9zx4p8q2r5t7v9w1y3z5b7d",
"customer_id": "ctm_01gw9m680k848184fpttwr0b7z",
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"balance": {
"used": {
"total": "3500",
"subscription": "3500"
},
"remaining": {
"total": "6500",
"subscription": "6500"
},
"overage": {
"total": "0"
}
},
"created_at": "2026-09-23T10:00:00Z",
"updated_at": "2026-09-25T14:08:31Z"
}
],
"meta": {
"request_id": "bb093d50-ddb5-401a-a5ba-034b187b396e",
"pagination": {
"per_page": 50,
"next": "https://sandbox-api.paddle.com/customers/ctm_01gw9m680k848184fpttwr0b7z/usage-balances?after=ubl_01h9zx4p8q2r5t7v9w1y3z5b7d",
"has_more": false,
"estimated_total": 1
}
}
}

To get a single usage balance, send a GET request to the /customers/{customer_id}/usage-balances/{usage_balance_id} endpoint. Paddle returns the usage balance on its own.

GET/customers/{customer_id}/usage-balances/{usage_balance_id}
Response (200 OK)
Response (200 OK)
{
"data": {
"id": "ubl_01h9zx4p8q2r5t7v9w1y3z5b7d",
"customer_id": "ctm_01gw9m680k848184fpttwr0b7z",
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"balance": {
"used": {
"total": "3500",
"subscription": "3500"
},
"remaining": {
"total": "6500",
"subscription": "6500"
},
"overage": {
"total": "0"
}
},
"created_at": "2026-09-23T10:00:00Z",
"updated_at": "2026-09-25T14:08:31Z"
},
"meta": {
"request_id": "bb093d50-ddb5-401a-a5ba-034b187b396e"
}
}

When balance.remaining.total is "0", the customer has used their allowance. Any more usage is recorded in balance.overage, and balance.overage.started_at shows when the balance first went into overage this billing period.

To avoid calling Paddle every time you check a balance, cache it in your app. Refresh it when usage_balance.depleted occurs, and when a subscription renews or changes.

Handle usage balance depleted

Paddle sends a usage_balance.depleted webhook when usage draws a customer's balance down to 0. Use it to restrict access, let the customer know, or prompt them to upgrade.

Top-ups aren't available during early access (beta). Prompt customers to upgrade to a plan with a bigger allowance instead.

usage_balance.depleted
{
"event_id": "evt_01js2n02s4fr6a8gvfm5enq0as",
"event_type": "usage_balance.depleted",
"occurred_at": "2026-09-28T16:42:10.283806Z",
"notification_id": "ntf_01js2n03f91aw3v7q6f7x55r3z",
"data": {
"id": "ubl_01h9zx4p8q2r5t7v9w1y3z5b7d",
"customer_id": "ctm_01gw9m680k848184fpttwr0b7z",
"usage_balance_unit_id": "ubu_01kw8ta2j8x5t7q4v9m1kd6phz",
"balance": {
"used": {
"total": "10000",
"subscription": "10000"
},
"remaining": {
"total": "0",
"subscription": "0"
},
"overage": {
"total": "0"
}
},
"created_at": "2026-09-23T10:00:00Z",
"updated_at": "2026-09-28T16:42:10Z"
}
}

The payload is the usage balance. It doesn't include a subscription ID, so use customer_id and usage_balance_unit_id to find the customer and feature in your app.

Keep in mind:

  • It occurs once when a balance runs out. Paddle doesn't send it again for more usage after that.
  • It can occur again after a customer gets more usage. For example, after a subscription renews or a customer upgrades, then runs out again.
  • It doesn't occur when usage expires. Unused usage expiring at the end of a billing period doesn't count as running out.

Handle renewals and plan changes

Paddle updates usage balances automatically as subscriptions change:

WhenWhat happens to the usage balance
Subscription renewsUnused usage from the previous billing period expires. Paddle grants the full allowance for the new period and clears overage.
Customer upgrades or downgradesPaddle expires the unused allowance from the old price and grants the new price's full allowance straight away, with no proration. Overage carries over until the subscription renews.
Quantity changesPaddle grants the allowance again for the new quantity.
Subscription is canceledWhen the cancellation takes effect, unused usage from that subscription expires. Paddle records any more usage as overage.
Subscription is pausedThe usage balance doesn't change, and Paddle still records usage.
Subscription resumesIf you resume with a new billing period, Paddle grants the full allowance. If you continue the existing billing period, the balance doesn't change.
Customer gets a refundThe usage balance doesn't change.

When you upgrade or downgrade a subscription that includes usage, set proration_billing_mode to full_immediately, full_next_billing_period, or do_not_bill. Paddle returns subscription_prorated_billing_not_allowed_for_allowance for prorated billing modes during early access (beta).

Because a plan change expires unused usage, customers who downgrade partway through a billing period lose what's left of their old allowance.

Next steps

That's it. Now you've built a plan that includes usage, reported usage to Paddle, and handled what happens when customers run out.

Events

usage_balance.depletedOccurs when usage draws a customer's usage balance down to 0.

Was this page helpful?