Usage events tools
MCP tools for Usage events: usage_events_create, usage_events_list.
usage_events_create: Record usage eventsusage_events_list: List usage events
usage_events_create
Record usage events. Operation usage_events.create · Brand level · permission usage:write · risk tier write · since M5
Records a batch of 1 to 1,000 usage events for metered prices, billed in arrears on the customer's next
invoice. Each event names the customerId, the meter (a meter of one of the brand's metered prices), the
quantity (an integer string; negative usage, such as refunded volume, reduces the period), when it
happened (occurredAt), optional attributes, and its own idempotencyKey, unique in the brand and mode.
Every event gets a result, in request order (results[i]), and the batch is recorded even when some events
fail:
created: recorded now;duplicate: an event with this key and the same content was recorded earlier (or earlier in the batch); it is counted once, so resending a batch after a timeout is safe;failed: not recorded, with anerror(usage_idempotency_key_reused,resource_not_foundorcustomer_deletedfor the customer,usage_meter_unknown,usage_occurred_at_out_of_range,resource_not_foundorsubscription_item_meter_mismatchfor asubscriptionItemId).
A malformed request (a missing field, a quantity that isn't an integer, more than 1,000 events) is refused as a
whole with validation_failed, and nothing is recorded.
Usage is aggregated per customer, meter, day (in the entity's time zone) and attribute set. Usage that
happened in a period that was already invoiced is recorded as late and billed on the next invoice as a
separate late usage line. Each request counts once against the API key's rate limit, whatever its size.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
events | array of object | yes | 1 to 1000 usage events. (1–1000 items) |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back. - Plan feature: needs
usage_billing.enabled.
Errors
entitlement_required: The organization's plan doesn't include usage billing (usage_billing.enabled).validation_failed: The request is malformed: no events or more than 1,000, a missing field, a bad quantity or key (details.issues). Nothing is recorded.usage_idempotency_key_reused: Per event: the key was already used for an event with other content.resource_not_found: Per event: no customer with this ID in the brand and mode.customer_deleted: Per event: the customer was deleted.usage_meter_unknown: Per event: no metered price of the brand uses the meter.usage_occurred_at_out_of_range: Per event:occurredAtis more than 5 minutes ahead or more than three years back.subscription_item_meter_mismatch: Per event: thesubscriptionItemIdisn't the customer's live metered item for this meter.permission_denied: The credentials can't record this brand's usage (usage:write).
Examples
Two events, one sent again
The second event was already recorded by an earlier request: it is reported, not counted again.
Arguments:
{
"events": [
{
"idempotencyKey": "req_7f3a9c",
"customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0a1",
"meter": "api.calls",
"quantity": "120",
"occurredAt": "2026-10-13T09:15:00Z",
"attributes": {
"model": "large"
}
},
{
"idempotencyKey": "req_7f3a9b",
"customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0a1",
"meter": "api.calls",
"quantity": "80",
"occurredAt": "2026-10-13T09:14:00Z"
}
],
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"object": "usage_event_batch",
"created": 1,
"duplicates": 1,
"failed": 0,
"results": [
{
"index": 0,
"idempotencyKey": "req_7f3a9c",
"status": "created",
"id": "uev_01m4v0d9k2j7r5t3w8x6y4z2a0",
"late": false,
"error": null
},
{
"index": 1,
"idempotencyKey": "req_7f3a9b",
"status": "duplicate",
"id": "uev_01m4v0d9k2j7r5t3w8x6y4z2a1",
"late": false,
"error": null
}
]
}
Refunded volume, and a misspelled meter
Arguments:
{
"events": [
{
"idempotencyKey": "refund_re_8812",
"customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0a1",
"meter": "payments.volume",
"quantity": "-25000000",
"occurredAt": "2026-10-13T10:00:00Z"
},
{
"idempotencyKey": "call_99102",
"customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0a1",
"meter": "api.cals",
"quantity": 1,
"occurredAt": "2026-10-13T10:00:05Z"
}
],
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"object": "usage_event_batch",
"created": 1,
"duplicates": 0,
"failed": 1,
"results": [
{
"index": 0,
"idempotencyKey": "refund_re_8812",
"status": "created",
"id": "uev_01m4v0d9k2j7r5t3w8x6y4z2a0",
"late": false,
"error": null
},
{
"index": 1,
"idempotencyKey": "call_99102",
"status": "failed",
"id": null,
"late": null,
"error": {
"code": "usage_meter_unknown",
"message": "No metered price of this brand uses this meter.",
"param": "events.1.meter",
"details": {
"meter": "api.cals"
}
}
}
]
}
usage_events_list
List usage events. Operation usage_events.list · Brand level · permission usage:read · risk tier read · since M5
Lists the brand's usage events in the mode of the request, newest recorded first.
customerId,meter: one customer's or one meter's events;occurredFrom(inclusive) andoccurredTo(exclusive): when the usage happened (ISO 8601 instants);late=true: only late usage (it happened in a period that was already invoiced),late=false: the others.
Paginate with limit (1–100, default 10) and starting_after (the next_cursor of the previous page).
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
limit | integer | no | (1–100) |
starting_after | ID (uev_…) | no | – |
customerId | ID (cus_…) | no | Only this customer's events. |
meter | string | no | Only this meter's events. (at most 100 characters) |
occurredFrom | date-time (ISO 8601) | no | Events that happened at or after this instant. |
occurredTo | date-time (ISO 8601) | no | Events that happened before this instant. |
late | string | no | true: only late events (they happened in a period that was already invoiced); false: only the others. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A filter or the page size is malformed.permission_denied: You can't read this brand's usage (usage:read).
Example
A customer's API calls on one day
Arguments:
{
"customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0a1",
"meter": "api.calls",
"occurredFrom": "2026-10-13T00:00:00+02:00",
"occurredTo": "2026-10-14T00:00:00+02:00",
"limit": 2,
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "list",
"data": [
{
"id": "uev_01m4v0d9k2j7r5t3w8x6y4z2a0",
"object": "usage_event",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"livemode": false,
"customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0a1",
"subscriptionItemId": null,
"meter": "api.calls",
"quantity": "120",
"occurredAt": "2026-10-13T09:15:00.000Z",
"attributes": {
"model": "large"
},
"idempotencyKey": "req_7f3a9c",
"late": false,
"walletId": null,
"reservationId": null,
"amount": null,
"createdAt": "2026-10-13T09:15:02.000Z"
},
{
"id": "uev_01m4v0d9k2j7r5t3w8x6y4z2a1",
"object": "usage_event",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"livemode": false,
"customerId": "cus_01m4ty3c2b5qx7mhd9k8w6s0a1",
"subscriptionItemId": null,
"meter": "api.calls",
"quantity": "80",
"occurredAt": "2026-10-13T09:14:00.000Z",
"attributes": {},
"idempotencyKey": "req_7f3a9b",
"late": false,
"walletId": null,
"reservationId": null,
"amount": null,
"createdAt": "2026-10-13T09:14:01.000Z"
}
],
"has_more": true,
"next_cursor": "uev_01m4v0d9k2j7r5t3w8x6y4z2a1"
}