> ## Documentation Index
> Fetch the complete documentation index at: https://docs.custral.com/llms.txt
> Use this file to discover all available pages before exploring further.

# The Usage module object

> Metered products: what you sell, who consumed it, and how much.

A usage module joins two objects: the one holding **what you sell** and the one
holding **who consumes it**. Your application records consumption against it;
Custral stores the events on the product and customer records.

<ResponseExample>
  ```json The Usage module object theme={null}
  {
    "id": "umod_3Ab9xK2mQ7",
    "name": "Compression",
    "productObjectId": "obj_3Ab9xK2mQ7",
    "customerObjectId": "obj_5Bc0xJ1kP4",
    "productIdentifierPropertyId": null,
    "customerIdentifierPropertyId": "prop_7Dd2xL3nR6",
    "createdAt": "2026-01-02T03:04:05.000Z"
  }
  ```
</ResponseExample>

## Attributes

<ResponseField name="id" type="string">
  Unique identifier, prefixed `umod_`.
</ResponseField>

<ResponseField name="name" type="string | null">
  What this metered product is called.
</ResponseField>

<ResponseField name="productObjectId" type="string | null">
  The [object](/dev/api-reference/objects) holding the things being sold.
</ResponseField>

<ResponseField name="customerObjectId" type="string | null">
  The object holding the people who consume them.
</ResponseField>

<ResponseField name="productIdentifierPropertyId" type="string | null">
  Optional property an external system identifies products by: a SKU, say.
</ResponseField>

<ResponseField name="customerIdentifierPropertyId" type="string | null">
  Optional property an external system identifies customers by.
</ResponseField>

<ResponseField name="createdAt" type="string | null">
  ISO 8601 timestamp.
</ResponseField>

## Two keys, on purpose

Recording usage and reading it back need different keys, and the split is
deliberate:

|                  | Endpoint                            | Key                            |
| ---------------- | ----------------------------------- | ------------------------------ |
| Record an event  | `POST /usage/track`                 | publishable (`pk_…`)           |
| Read events back | `GET /v1/usage-modules/{id}/events` | secret (`sk_…`) + `usage:read` |

`track` takes a publishable key so it can be called straight from a browser at
the moment of consumption. Reading events back is not publishable. A
client-side key must never be able to enumerate a workspace's usage.

## Recording usage

Use [`@custral/js`](https://www.npmjs.com/package/@custral/js) from your app:

```ts theme={null}
import {CustralUsage} from "@custral/js";

const usage = new CustralUsage({key: "pk_...", moduleId: "umod_..."});

await usage.track({
  productRecordId: "rec_...",
  customerRecordId: "rec_...",
  quantity: 5,
});
```

## Reading it back

With the server SDK, holding `usage:read`:

```ts theme={null}
const events = await custral.usageModules.listEvents("umod_...", {
  customerRecordId: "rec_...",
  from: "2026-01-01T00:00:00.000Z",
});
```

Events come back **newest first, 50 to a call**. That is the one list in the API
whose length is set by your own application rather than by anything a person
does in the workspace, so it always pages. A call without `limit` is a page, not
the history.

<ResponseField name="limit" type="integer">
  Page size, 1–200. Defaults to 50.
</ResponseField>

<ResponseField name="offset" type="integer">
  Rows to skip, for the next page.
</ResponseField>

To total a period, filter it rather than paging to the end:

```ts theme={null}
const january = await custral.usageModules.listEvents("umod_...", {
  customerRecordId: "rec_...",
  from: "2026-01-01T00:00:00.000Z",
  to: "2026-02-01T00:00:00.000Z",
  limit: 200,
});
```


## Related topics

- [Retrieve a usage module](/api-reference/usage-modules/retrieve-a-usage-module.md)
- [List usage modules](/api-reference/usage-modules/list-usage-modules.md)
- [Create a usage module](/api-reference/usage-modules/create-a-usage-module.md)
- [Usage](/data/properties/complex/usage.md)
- [Usage tracking](/bi/reporting/usage.md)
