> This page is for version v2 (default).
> For other versions, use one of these documentation indexes:
> - v2 (default): https://docs.paid.ai/v-2/llms.txt
> - v1: https://docs.paid.ai/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.paid.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.paid.ai/_mcp/server.

# How credit balances work

> Learn how credits are granted, spent, rolled over, and topped up in Paid.

## Overview

Credits let you bill from a prepaid balance instead of charging only after usage happens. You can sell credits directly, include them in a plan, or grant them manually as a top-up or promotion.

In Paid, a customer's available credits are made up of one or more **credit allocations**. Each allocation has its own amount, timing, and optional expiry rules. Paid keeps the running balance for you and deducts credits automatically as usage is recorded.

This page explains how customers receive credits, how Paid decides which credits to spend first, and what happens when balances run low or go below zero.

## Credit allocations

A customer's balance is usually made up of several allocations rather than one single bucket. New allocations can be created when:

* A customer buys prepaid credits
* A recurring plan renews and includes a fresh allowance
* You manually grant bonus or promotional credits

Each allocation is tracked independently. That matters because different allocations can have different:

* Expiry dates
* Rollover windows
* Sources, such as purchased credits versus promotional credits

For example, a customer might have:

* 10,000 purchased API credits for their monthly plan
* 1,000 promotional API credits from a launch offer
* 500 rolled-over API credits from the previous period

Paid combines the usable portion of those allocations into the balance you see through the API and in the dashboard.

## How credits are granted

### Prepaid purchases

You can sell usage in advance by attaching credits to a product or plan. When the customer purchases that item, Paid creates a new credit allocation for them.

This is useful when you want customers to:

* Buy a bundle of usage before they consume it
* Start each billing cycle with a fresh allowance
* Top up when they run low

### Included credits on recurring plans

Recurring plans can include a credit allowance as part of the subscription. For example:

* `$99/month` includes `1,000 API Credits`
* `$499/month` includes `50,000 Messages`

On each renewal, Paid grants the next allocation for that billing period based on your plan configuration.

A benefit can allocate its credits **upfront** (the whole amount at the start of
the billing period) or **monthly** (one equal share per month of the period). A
monthly allocation across a billing period longer than one month must divide
exactly at six decimal places: `6` credits over 12 months is fine (`0.5` a
month), and so is `1.2` over 12 (`0.1` a month), but `0.5` over 12 recurs
(`0.041666…`) and is rejected with

> Credit benefit amount 0.5 does not divide evenly across 12 months at 6 decimal
> places. Use an amount divisible by 12, or switch allocation to upfront.

Paid refuses the configuration rather than rounding it, so the credits granted
over a period always sum exactly to the amount you configured. The two fixes are
the ones the message names: pick an amount that divides, or allocate upfront.

### Manual top-ups and promotions

You can also add credits outside the normal billing flow, for example:

* Goodwill credits after a support incident
* Promotional launch credits
* A manual top-up sold by your sales or support team

These create separate allocations, which means they can have their own expiry date and may be consumed before purchased credits depending on their configuration.

### When credits become available

Credits can become available at different points depending on how your pricing is configured:

* **On activation**: credits are usable as soon as the order or billing period starts
* **On payment**: credits stay pending until the related invoice is paid

This lets you decide whether customers can use credits immediately or only after payment is collected.

If you activate an order with a `startDate` in the past, Paid backfills credit grants and invoices for every elapsed period at activation. See [Backdated order activation](/documentation/billing/backdated-order-activation) for the full contract.

## How credits are consumed

When Paid receives a usage event tied to a credit-backed pricing model, it deducts credits automatically from the customer's available allocations.

Paid applies credits in a predictable order:

1. Promotional or manually granted credits are usually consumed before purchased credits
2. Allocations that expire sooner are consumed before those that expire later
3. If there is still a tie, older allocations are consumed first

This helps customers use the credits most at risk of expiring before longer-lived balances.

### Controlling how many credits a signal consumes

There are three ways to control the number of credits deducted by a signal:

**Fixed credit cost.** Set the credit cost on your product's pricing rule (e.g., credit cost = `1`). Every matching signal deducts exactly that amount. This is the simplest model and works well when every action has the same cost.

**Dynamic quantity from the signal.** Configure your pricing rule with a quantity mapping that reads from the signal's `data` object (e.g., map quantity to `$.quantity`). Then pass the quantity value in each signal. The formula becomes `quantity x creditCost`. For example, if the pricing rule has credit cost `1` and the signal sends `quantity: 5`, that signal deducts 5 credits.

Credit costs are decimal, so this arithmetic can produce a fractional balance. With credit cost `0.5` and the same `quantity: 5`, that signal deducts `2.5` credits and a balance of `10` becomes `7.5`. Credit values are exact to at most six decimal places, and a seventh is rejected rather than rounded. See [Credit precision](/documentation/credits/credits#credit-precision). The `quantity` a signal carries is a count of your own units and stays a whole number; the per-unit credit cost is where sub-unit pricing lives.

#### Node.js

```typescript
await paid.signals.createSignals({
  signals: [
    {
      eventName: "workflow_run",
      customer: { externalCustomerId: "cus_acme" },
      attribution: { externalProductId: "automation" },
      data: { quantity: 5 },
    },
  ],
});
```

#### Go

```go
_, err := paidClient.Signals.CreateSignals(ctx, &paid.BulkSignalsRequest{
    Signals: []*paid.Signal{
        {
            EventName: "workflow_run",
            Customer: &paid.CustomerAttribution{
                CustomerByExternalID: &paid.CustomerByExternalID{
                    ExternalCustomerID: "cus_acme",
                },
            },
            Attribution: &paid.Attribution{
                ProductByExternalID: &paid.ProductByExternalID{
                    ExternalProductID: "automation",
                },
            },
            Data: map[string]interface{}{"quantity": 5},
        },
    },
})
if err != nil {
    return err
}
```

> **Note**
>
> The pricing rule must have a quantity property configured to read from signal
> data. Without this mapping, every signal consumes the fixed credit cost
> regardless of the `quantity` value sent.

**Bracketed prepaid credits.** For non-linear credit costs, use the bracketed prepaid credits pricing model. This lets you define quantity ranges that each map to a flat credit amount. For example, processing 1 to 10 pages might cost `0.5` credits, while 11 to 50 pages costs 5 credits. A bracket's credit amount may be fractional; the range bounds themselves are quantity bounds and stay whole numbers. The bracket is selected based on the signal's quantity value. To select brackets from a different signal data field, set `pricingInput.path` to a key in the signal's `data` payload. For a signal sent with `data: {"rooms": 3}`, use `rooms`. Dots address nested fields (for example `dimensions.pages` for `data: {"dimensions": {"pages": 12}}`). When unset, the top-level `quantity` field is used. The field is fixed on an order once it is created.

### Tracking credit consumption by user

Credit balances are managed at the customer (organization) level, but you can attribute consumption to individual users within a customer account. Include `external_user_id` in the signal's `data` field, matching the external ID of a user created via the [user management API](/documentation/customers-users/user-management):

#### Node.js

```typescript
await paid.signals.createSignals({
  signals: [
    {
      eventName: "chat_message",
      customer: { externalCustomerId: "cus_acme" },
      attribution: { externalProductId: "chatbot" },
      data: { quantity: 1, external_user_id: "usr_jane_doe" },
    },
  ],
});
```

#### Go

```go
_, err := paidClient.Signals.CreateSignals(ctx, &paid.BulkSignalsRequest{
    Signals: []*paid.Signal{
        {
            EventName: "chat_message",
            Customer: &paid.CustomerAttribution{
                CustomerByExternalID: &paid.CustomerByExternalID{
                    ExternalCustomerID: "cus_acme",
                },
            },
            Attribution: &paid.Attribution{
                ProductByExternalID: &paid.ProductByExternalID{
                    ExternalProductID: "chatbot",
                },
            },
            Data: map[string]interface{}{
                "quantity":         1,
                "external_user_id": "usr_jane_doe",
            },
        },
    },
})
if err != nil {
    return err
}
```

When Paid processes a signal with `external_user_id`, it resolves the user and their seat assignment. If the user occupies a seat with seat-scoped credit balances, the credit spend is deducted from that seat's balance rather than the organization pool. If no seat is found, credits are deducted from the organization balance as usual.

All fields in the `data` object are also stored with the signal and queryable through the [analytics API](/documentation/analytics-api/overview), so you can break down usage by user, team, or any other dimension you include.

Seat-based plans can grant credits either to the organization (shared pool) or to individual seats (per-user balance), depending on how the credit benefit is configured. See [Examples of plans with included credits](/documentation/credits/examples-of-plans-with-included-credits) for both patterns.

## What happens when credits run out

If usage exceeds the customer's available balance, Paid can continue recording usage and treat the difference as overage, depending on your pricing setup.

From the customer's perspective:

* Their available balance reaches zero
* New usage can still be accepted
* The excess can later be billed as overage

Because credit costs can be fractional, a balance can also overshoot into a negative remainder: a `0.5`-credit call against a `0.25`-credit balance leaves `-0.25`. The overage is the amount below zero.

> **Note**
>
> On an invoice, a **fractional** credit overage bills as a single line with
> quantity `1` and the exact total for the credits consumed. The real terms live
> in the line description, which reads
> `Credits overage - api_credits: 2.5 credits @ USD 0.40`. Invoice-line
> quantities are whole numbers, so quantity `1` is what keeps `total ÷ quantity`
> from publishing a per-credit price that was never charged. Whole-credit
> overages keep their real credit count as the quantity. If you aggregate
> overage line quantities, read them as line counts rather than as credits
> consumed.

This is useful if you do not want product usage to stop the moment a balance is exhausted.

## Top-ups after exhaustion

When a customer has already exhausted their credits, the effect of a top-up depends on how you apply it.

### New top-up allocation

If you add a new top-up as a fresh credit grant, the customer gets a new usable balance immediately.

Example:

* Customer had `100` credits
* Customer used `200`
* You add a new top-up of `50`

Result:

* The earlier deficit still exists historically
* The new `50` credits are available to spend right away

This is the right model for a true top-up purchase or goodwill grant.

### Adjusting an earlier allocation

If instead you increase an earlier allocation retroactively, the added credits first reduce the existing deficit. In that case, the customer may see little or no newly available balance immediately.

This is the right model when you are correcting or resizing a prior grant rather than giving the customer a fresh top-up.

### Rule of thumb

Use:

* A **new credit grant** when you want the customer to receive new spendable credits now
* An **adjustment to an existing grant** when you want to correct the historical allocation itself

## Rollover

Credits can optionally roll forward after a billing period ends.

With rollover enabled:

* Unused credits can remain available after the original period closes
* You can cap how much rolls over
* You can define how long rolled-over credits stay valid

Example:

* A monthly plan includes `1,000` credits
* Up to `200` unused credits roll over
* Rolled-over credits expire after `30 days`

This gives customers flexibility without letting unused balances accumulate forever.

## Querying balances

Use the API to retrieve a customer's current balance by credit currency.

This is useful for:

* Showing remaining credits in your product
* Preventing an action when the balance is too low
* Triggering low-balance alerts or top-up prompts

The balance response is grouped by credit currency and includes a `recipient` field. `recipient` tells you whether the balance applies to:

* `organization`: one shared balance for the whole customer account
* `seat`: a balance that is scoped to an individual seat-based allocation

#### Node.js

```typescript
import { PaidClient } from '@paid-ai/paid-node';

const client = new PaidClient({ token: 'YOUR_API_KEY' });

const balances = await client.customers.getCreditBalances('cus_abc123');

for (const balance of balances.data) {
  console.log(`${balance.currencyName}: ${balance.available} available`);
}
```

#### Python

```python
from paid import Paid

client = Paid(token="YOUR_API_KEY")

balances = client.customers.get_credit_balances("cus_abc123")

for balance in balances.data:
    print(f"{balance.currency_name}: {balance.available} available")
```

#### Go

```go
import (
    "fmt"

    paid "github.com/paid-ai/paid-go"
    paidclient "github.com/paid-ai/paid-go/client"
    "github.com/paid-ai/paid-go/option"
)

client := paidclient.NewClient(option.WithToken("YOUR_API_KEY"))

balances, err := client.Customers.GetCustomerCreditBalances(
    ctx,
    &paid.GetCustomerCreditBalancesRequest{ID: "cus_abc123"},
)
if err != nil {
    return err
}

for _, balance := range balances.Data {
    // %g keeps the significant digits: a 7.5 balance prints as 7.5, not 8.
    fmt.Printf("%s: %g available\n", balance.CurrencyName, balance.Available)
}
```

#### cURL

```bash
curl -X GET https://api.agentpaid.io/api/v2/customers/cus_abc123/credits/balances \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Example response:

```json
{
  "data": [
    {
      "creditsCurrencyId": "cc_abc123",
      "currencyName": "API Credits",
      "currencyKey": "api_credits",
      "available": 7499.5,
      "used": 2500.5,
      "total": 10000,
      "periodStart": "2026-03-01T00:00:00.000Z",
      "periodEnd": "2026-03-31T23:59:59.999Z",
      "rolloverEndDate": null,
      "recipient": "organization"
    }
  ]
}
```

In most prepaid setups, `organization` is the right model because the whole customer account draws from the same pool. Use `seat` when each licensed seat should receive and consume its own allowance independently.