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

# POST /usage-events

**Record usage events**

> **Early access (beta): usage-based billing**

Records usage events for usage-based billing. During beta, include one event in each request.

Paddle responds once it has accepted an event, then draws down the customer's usage balances
in the background. Each event draws down the customer's usage balance for every meter with a
matching `action`, including archived meters. Paddle accepts events for actions that don't match a meter, but they
don't draw down any usage balance.

Paddle counts each event once for a customer and action, using its `event_key` and `occurred_at`.
If a request fails or you're not sure it went through, send the event again with the same
`event_key` and `occurred_at`. If you change `occurred_at` when you retry, Paddle records it as
new usage.

`occurred_at` must be no more than 60 days in the past and no more than 24 hours in the future,
measured from when Paddle receives the request. Paddle rejects events outside this window with
`usage_event_timestamp_too_old` or `usage_event_future_timestamp`, and doesn't count them. If you
retry an event that Paddle already accepted after it's more than 60 days old, Paddle rejects the
retry but still counts the original event.

If successful, your response includes the status of each event, in the order you sent them.
Events that Paddle didn't record have a `status` of `rejected` and include an `error` that
explains why.

**Required permissions:** `usage_event.write`

## Request body

- `events`: array (required) — Usage events to record. During beta, include one event in each request. (Items: 1–1)
  - `event_key`: string (required) — Unique key for this usage from your system, like a request or job ID. Paddle uses `event_key` and `occurred_at` together to count each event once for a customer and action, so send both unchanged when you retry. (Length: 1–255)
  - `customer_id`: string (required) — Paddle ID of the customer who used the metered feature. (pattern: `^ctm_[a-z\d]{26}$`)
  - `action`: string (required) — Action of the meters to draw down, matching a meter's `action`. Paddle accepts events for actions that don't match a meter, but they don't draw down any usage balance. (Length: 2–64; pattern: `^[a-z][a-z0-9_]*$`)
  - `quantity`: string (required) — How much usage to record, in the unit that the meter measures, like calls or tokens. A positive decimal string with up to 9 decimal places, for example `"12"` or `"2.5"`. Paddle rejects values with more decimal places rather than rounding them. (Max length: 45; pattern: `^([1-9][0-9]{0,34}(\.[0-9]{1,9})?|0\.(?:[1-9][0-9]{0,8}|0[1-9][0-9]{0,7}|00[1-9][0-9]{0,6}|000[1-9][0-9]{0,5}|0000[1-9][0-9]{0,4}|00000[1-9][0-9]{0,3}|000000[1-9][0-9]{0,2}|0000000[1-9][0-9]?|00000000[1-9]))$`)
  - `occurred_at`: string (date-time) (required) — When the usage happened, as an RFC 3339 datetime string in UTC. Paddle uses it with `event_key` to identify the event, so send the same value when you retry. Can't be more than 24 hours in the future or more than 60 days in the past, measured in 24-hour periods from when Paddle receives the request.

### Request example

```json
{
  "events": [
    {
      "event_key": "call_7f3a9c2e",
      "customer_id": "ctm_01gw9m680k848184fpttwr0b7z",
      "action": "api_call",
      "quantity": "1",
      "occurred_at": "2026-09-15T10:15:00Z"
    }
  ]
}
```

## Response (202)

- `data`: object (required) — Represents the result of recording usage events.
  - `events`: array (required) — Status of each usage event, in the order you sent them.
    - `event_key`: string (required) — `event_key` of the usage event, as you sent it.
    - `status`: string (required) — Whether Paddle accepted or rejected this usage event.
      - `accepted` — Paddle accepted the event and draws down usage balances for meters with a matching `action`. Paddle accepts events for actions that don't match a meter, but they don't draw down any usage balance.
      - `rejected` — Paddle didn't record the event. See `error` for why.
    - `error`: object — Why Paddle rejected this usage event. Only returned when `status` is `rejected`.
      - `type`: string (required) — Type of error encountered.
        - `request_error` — Typically means there's a problem with the request that you made.
        - `api_error` — Typically means there's a problem with the Paddle API.
      - `code`: string (required) — Short snake case string that describes this error. Use to search the error reference.
      - `detail`: string (required) — Some information about what went wrong as a human-readable string.
      - `documentation_url`: string (uri) (required) — Link to a page in the error reference for this specific error.
      - `errors`: array — List of validation errors. Only returned when there's a validation error.
        - `field`: string (required) — Field where validation error occurred.
        - `message`: string (required) — Information about how the field failed validation.
- `meta`: object (required) — Information about this response.
  - `request_id`: string (required) — Unique ID for the request relating to this response. Provide this when contacting Paddle support about a specific request.

### Response example

```json
{
  "data": {
    "events": [
      {
        "event_key": "call_7f3a9c2e",
        "status": "accepted"
      }
    ]
  },
  "meta": {
    "request_id": "cf40234b-e140-44d1-a83f-7bbdedd88589"
  }
}
```
