Zuplo
Metrics, Billing & Quotas

OpenMeter Metering Policy

Send usage metrics to OpenMeter for metering and billing. This policy allows you to track API usage by sending events to OpenMeter's API in CloudEvents format.

With this policy, you'll benefit from:

  • Usage-Based Billing: Implement precise metering for pay-as-you-go pricing models
  • Real-Time Analytics: Track API usage patterns and customer behavior as they happen
  • Customizable Event Tracking: Capture specific metrics that matter to your business
  • Customer Segmentation: Identify usage patterns across different customer segments
  • Flexible Integration: Works seamlessly with OpenMeter's CloudEvents-based API
  • Batch Processing: Efficiently sends events in batches to minimize performance impact

Configuration

The configuration shows how to configure the policy in the 'policies.json' document.

jsonCode
{ "name": "my-openmeter-inbound-policy", "policyType": "openmeter-inbound", "handler": { "export": "OpenMeterInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "apiUrl": "https://openmeter.cloud", "eventSource": "api-gateway", "requiredEntitlements": ["gpt_4_tokens", "api_calls", "saml_sso"], "subjectPath": ".data.accountId" } } }

Policy Configuration

  • name <string> - The name of your policy instance. This is used as a reference in your routes.
  • policyType <string> - The identifier of the policy. This is used by the Zuplo UI. Value should be openmeter-inbound.
  • handler.export <string> - The name of the exported type. Value should be OpenMeterInboundPolicy.
  • handler.module <string> - The module containing the policy. Value should be $import(@zuplo/runtime).
  • handler.options <object> - The options for this policy. See Policy Options below.

Policy Options

The options for this policy are specified below. All properties are optional unless specifically marked as required.

  • apiUrl <string> - The URL of the OpenMeter API endpoint. Defaults to "https://openmeter.cloud".
  • apiKey (required) <string> - The API key to use when sending metering calls to OpenMeter.
  • meter <undefined> - A single meter configuration or an array of meter configurations for OpenMeter.
  • meterOnStatusCodes <undefined> - A list of successful status codes and ranges "200-299, 304" that should trigger a metering event. Defaults to "200-299".
  • eventSource <string> - The event's source (e.g. the service name). Defaults to "api-gateway".
  • requiredEntitlements <string[]> - A list of entitlements (feature keys) required in order for the call to be allowed.
  • subjectPath <string> - The path to the property on request.user that contains the subject used for meters and entitlements. For example .data.accountId would read the request.user.data.accountId property. Defaults to ".sub".

Using the Policy

How it works

The policy sends usage events to OpenMeter's API in CloudEvents format whenever a request matches the configured status codes. The events include customer identification, event type, and custom data that can be used for metering and billing.

Additionally, the policy can check entitlements before allowing access to your API. When entitlement checking is enabled, the policy will:

  1. Check if the subject has access to the required features
  2. Block the request if the subject doesn't have access to any required feature
  3. Log detailed information about failed entitlements

Programmatic Meters

You can dynamically set meters for each request using the OpenMeterInboundPolicy.setMeters method:

typescriptCode
import { OpenMeterInboundPolicy } from "@zuplo/runtime"; export default async function (request, context) { // Set a single meter OpenMeterInboundPolicy.setMeters(context, { type: "api-call", data: { endpoint: request.url, method: request.method, tokens: 150, }, }); // Or set multiple meters OpenMeterInboundPolicy.setMeters(context, [ { type: "api-call", data: { endpoint: request.url, method: request.method, }, }, { type: "llm-usage", data: { model: "gpt-4", prompt_tokens: 100, completion_tokens: 50, }, }, ]); return request; }

Examples

Basic Metering

jsonCode
{ "type": "openmeter-inbound", "handler": "$import(@zuplo/runtime).OpenMeterInboundPolicy", "options": { "apiKey": "your-api-key", "meter": { "type": "api-call", "data": { "service": "payment-api", "tier": "premium" } } } }

Multiple Meters

jsonCode
{ "type": "openmeter-inbound", "handler": "$import(@zuplo/runtime).OpenMeterInboundPolicy", "options": { "apiKey": "your-api-key", "meter": [ { "type": "api-call", "data": { "service": "payment-api" } }, { "type": "data-transfer", "data": { "bytes": 1024 } } ] } }

Metering with Entitlement Checking

jsonCode
{ "type": "openmeter-inbound", "handler": "$import(@zuplo/runtime).OpenMeterInboundPolicy", "options": { "apiKey": "your-api-key", "meter": { "type": "api-call", "data": { "service": "payment-api" } }, "requiredEntitlements": ["payment-api-access", "premium-tier"] } }

Custom Status Codes

jsonCode
{ "type": "openmeter-inbound", "handler": "$import(@zuplo/runtime).OpenMeterInboundPolicy", "options": { "apiKey": "your-api-key", "meterOnStatusCodes": "200-299,304", "meter": { "type": "api-call" } } }

CloudEvents Format

The policy sends events to OpenMeter in CloudEvents format. Each event includes:

  • specversion: Always "1.0"
  • id: Unique identifier (combines request ID and meter type)
  • time: ISO 8601 timestamp
  • source: The configured event source
  • subject: The user/customer identifier
  • type: The meter type
  • data: Custom data from the meter configuration

You can override CloudEvents fields when setting meters dynamically:

typescriptCode
OpenMeterInboundPolicy.setMeters(context, { type: "llm-usage", id: "custom-event-id-123", subject: "user-456", data: { model: "gpt-4", tokens: 1500, }, });

Read more about how policies work

Last modified on