Skip to main content
Meter events let you record what your customers consume — tokens, API calls, storage, compute — without triggering a payment or requiring a billing plan. Once ingested, this data powers metered entitlements, usage analytics, and internal rate limiting. Unlike usage events, meter events are fire-and-forget: the API always responds 202 Accepted and never rejects a well-formed event. There are no billing side-effects, no subscription requirements, and no timing constraints.

How it works

When you send an event to POST /v0/events, Paygentic:
  1. Validates that the type field matches a billable metric configured in your organization
  2. Returns 202 Accepted immediately
  3. Paygentic deduplicates and stores the event
The stored events are then available for aggregation — either to enforce metered entitlement quotas or for your own analytics.

Before you begin

  • At least one billable metric with an eventType configured
  • An API key with events:create permission

Setting up a billable metric for metering

A billable metric becomes a meter definition by configuring three fields:
FieldRequiredDescription
eventTypeYesThe type value your events will carry. Events with a non-matching type are rejected with 422.
valuePropertyNoJSONPath expression into the event data payload. Extracts the numeric value to aggregate (e.g., $.tokens). Required for aggregations other than count.
groupByNoA map of dimension names to JSONPath expressions. Allows slicing usage by properties like model or region.
aggregationYesHow to combine values: sum, count, avg, min, max, unique_count, or latest.
One billable metric = one measurement. To track multiple values from the same event (e.g., input tokens and output tokens separately), create multiple billable metrics pointing to the same eventType with different valueProperty paths.
Example: billable metric for AI inference tokens
{
  "name": "AI Tokens",
  "unit": "tokens",
  "eventType": "ai.inference",
  "valueProperty": "$.tokens",
  "aggregation": "SUM",
  "groupBy": {
    "model": "$.model"
  }
}

Sending events

Send a POST request to /v0/events for each unit of consumption:
curl -X POST "https://api.paygentic.io/v0/events" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "ai.inference",
    "source": "https://api.myapp.com",
    "subject": "cus_abc123",
    "data": {
      "tokens": 1500,
      "model": "gpt-4o",
      "region": "us-east-1"
    },
    "idempotencyKey": "req_xyz789"
  }'

Event fields

FieldRequiredDescription
typeYesMust match an eventType on one of your billable metrics.
sourceYesURI identifying the system sending the event (e.g., https://api.myapp.com).
subjectYesThe customer or entity the event relates to — typically a customerId.
dataYesArbitrary JSON object containing the metering payload.
idempotencyKeyNoYour own deduplication key. If omitted, a unique key is generated.
namespaceNoOrganization ID. Defaults to your authenticated organization.
timestampNoISO 8601 event timestamp. Defaults to server receipt time.

Response

{
  "id": "evt_abc123",
  "object": "event",
  "type": "ai.inference",
  "source": "https://api.myapp.com",
  "subject": "cus_abc123",
  "namespace": "org_xyz",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "idempotencyKey": "req_xyz789"
}

Multi-dimensional metering

The data payload can carry as many fields as you need. Use groupBy on your billable metric to slice usage by dimension. Example: track tokens per model Billable metric configuration:
{
  "eventType": "ai.inference",
  "valueProperty": "$.tokens",
  "aggregation": "sum",
  "groupBy": {
    "model": "$.model",
    "region": "$.region"
  }
}
Every event with type: "ai.inference" contributes to the aggregate, and usage can be broken down by model or region when checking entitlement balances or querying analytics.
The groupBy paths use JSONPath notation. $.model extracts the top-level model field from the event data object. Nested fields use dot notation: $.request.metadata.tier.

Multiple metrics from one event stream

Multiple billable metrics can read from the same eventType. This lets you track different aspects of the same operation without sending separate events. Example: track input and output tokens separately from one AI inference event Event payload:
{
  "type": "ai.inference",
  "subject": "cus_abc123",
  "source": "https://api.myapp.com",
  "data": {
    "inputTokens": 800,
    "outputTokens": 700,
    "model": "gpt-4o"
  }
}
Billable metric 1 — Input Tokens:
{
  "name": "Input Tokens",
  "eventType": "ai.inference",
  "valueProperty": "$.inputTokens",
  "aggregation": "sum"
}
Billable metric 2 — Output Tokens:
{
  "name": "Output Tokens",
  "eventType": "ai.inference",
  "valueProperty": "$.outputTokens",
  "aggregation": "sum"
}
One event ingested, two metrics updated. Both can have independent pricing, quotas, and entitlement limits.

Standalone metering (no plan required)

Meter events do not require a billing plan, a subscription, or even a customer account. The only requirement is a billable metric with a matching eventType. This makes meter events suitable for:
  • Internal analytics — Track usage across your infrastructure before you’ve set up billing
  • Rate limiting — Enforce per-customer limits without any billing integration
  • Capacity planning — Instrument your system to understand consumption patterns
  • Usage dashboards — Give customers visibility into their own usage
You can add billing later by creating a plan with a price linked to your billable metric — the same events you’re already ingesting will feed into billing automatically.

Using meters with metered entitlements

Meter events are the data source for metered entitlements. When a customer has a metered entitlement, the grant engine reads their aggregated meter data to determine how much quota they have remaining. To check whether a customer has remaining quota, use GET /v1/entitlements/{entitlementId}. For metered entitlements, this endpoint returns balance, usage, and period data inline. The entitlementId comes from the list entitlements response. See Features and Entitlements — Metered Features for code examples, the full balance response schema, and hard vs soft limit configuration.

Idempotency

Use idempotencyKey to prevent duplicate events when retrying failed requests:
  • If you send two events with the same idempotencyKey, only the first is recorded
  • The deduplication window is 24 hours
  • If you omit idempotencyKey, the API generates a unique key for you (retries will create duplicate events)
Best practice: Generate idempotency keys deterministically from your internal identifiers:
const idempotencyKey = `${requestId}-${customerId}-${eventType}`;

Error handling

StatusCondition
202 AcceptedEvent accepted and queued for processing
400 Bad RequestMalformed request (e.g., invalid timestamp format)
422 Unprocessable EntityThe type field does not match any billable metric in your organization
401 UnauthorizedMissing or invalid API key
403 ForbiddenAPI key lacks events:create permission for the target namespace
A 422 response means you need to create a billable metric with the matching eventType before sending events of that type. Events with an unrecognized type are not queued.

Next Steps