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

# OpenMeter

> Send AI-billing LLM usage events to OpenMeter as CloudEvents and sync customers so you can bill end users for AI consumption with subscriptions and metered pricing.

# OpenMeter billing platform integration

Use this guide after your framework-level integration is complete.

This page covers OpenMeter-specific setup:

* Create the `@ai-billing/openmeter` destination.
* Map usage events to OpenMeter customers via CloudEvents `subject`.
* Sync customer records when users sign up and assign subject keys.

For the server middleware setup, use [Node.js billing integration](https://www.narev.ai/docs/ai-billing/integrations/frameworks/nodejs.md).

## Metering strategy

OpenMeter integrations with Narev use **nanos metering** only: one meter sums `cost_nanos` from each CloudEvent. Narev resolves the dollar cost at request time, so you do **not** copy token rates into OpenMeter plans.

## Before you start

Create a meter in the [OpenMeter Dashboard](https://openmeter.cloud) with event type `llm_usage`. The `eventType` in your destination config must match that type.

## Install OpenMeter dependencies

```bash theme={null}
pnpm add @ai-billing/openmeter
```

## Configure environment variables

Set these on your server:

```bash theme={null}
OPENMETER_API_KEY=****
# Set to your OpenMeter API base URL (OpenMeter Cloud, self-hosted, or Kong)
OPENMETER_API_URL=https://openmeter.cloud
```

Use a sandbox or test organization until your metering flow is verified.

## Create OpenMeter billing destinations

Create `lib/ai/destinations.ts`:

```ts lib/ai/destinations.ts theme={null}
import { createOpenMeterDestination } from '@ai-billing/openmeter';

export function getBillingDestinations() {
  const openMeterApiKey = process.env.OPENMETER_API_KEY;

  if (!openMeterApiKey) return [];

  return [
    createOpenMeterDestination({
      apiKey: openMeterApiKey,
      apiUrl: process.env.OPENMETER_API_URL,
      eventType: 'llm_usage',
      customerIdKey: 'userId',
    }),
  ];
}
```

The key mapping is `customerIdKey: 'userId'`. Your billing tags must include `userId`, which becomes the CloudEvents `subject`.

## Sync OpenMeter customers when users sign up

Create `lib/openmeter-client.ts`:

```ts lib/openmeter-client.ts theme={null}
export async function createOpenMeterCustomer(
  name: string,
  userId: string,
) {
  const apiKey = process.env.OPENMETER_API_KEY;
  const apiUrl = process.env.OPENMETER_API_URL ?? 'https://openmeter.cloud';

  if (!apiKey) return;

  try {
    const response = await fetch(`${apiUrl}/api/v1/customers`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        name,
        key: userId,
        usageAttribution: { subjectKeys: [userId] },
      }),
    });

    if (!response.ok) {
      throw new Error(`OpenMeter API returned ${response.status}`);
    }
  } catch (error) {
    console.error('[ai-billing] Failed to create OpenMeter customer:', error);
  }
}
```

Call this when a user signs up:

```ts theme={null}
if (newUser) {
  await createOpenMeterCustomer(validatedData.email, newUser.id);
}
```

OpenMeter attributes usage to a customer when the CloudEvents `subject` matches a customer `key` or an assigned subject key.

## Required tag contract

In your generation routes, include:

```ts theme={null}
providerOptions: {
  'ai-billing-tags': {
    userId: session.user.id,
    modelId: chatModel,
    chatId: id,
  },
}
```

Contract requirements:

* `userId` in `ai-billing-tags` must match the CloudEvents `subject` and the customer subject key.
* Each user should have one OpenMeter customer record.
* If `userId` is missing, the destination skips the event to avoid ingesting anonymous usage.

> [!NOTE]
>
> The OpenMeter destination sends `cost_nanos` and `currency` in the CloudEvents `data` payload. If your provider does not return pricing natively, attach a price resolver (for example, Narev) in your framework middleware. See [@ai-billing/openmeter reference](https://www.narev.ai/docs/ai-billing/reference/openmeter/index.md).

## Verify OpenMeter metering

1. Register a new user and confirm an OpenMeter customer exists with `key = userId`.
2. Trigger a model call and confirm a CloudEvent with type `llm_usage` appears in OpenMeter.
3. Validate the `data` payload contains `cost_nanos`, `currency`, and your route context tags.
4. Confirm `OPENMETER_API_URL` points at the OpenMeter instance you are checking.

## Common issues

### Events appear but don't map to customers

* Confirm `userId` exists in `ai-billing-tags`.
* Confirm destination uses `customerIdKey: 'userId'`.
* Confirm customer creation assigns `subjectKeys: [userId]` in `usageAttribution`.

### No events arrive in OpenMeter

* Confirm `OPENMETER_API_KEY` is present at runtime.
* Confirm the meter event type matches your OpenMeter configuration.
* Confirm `OPENMETER_API_URL` matches your deployment (OpenMeter Cloud vs self-hosted).
* Confirm framework routes call the billing-wrapped model helper.
* Confirm each billing event includes a defined `cost` (attach a price resolver if needed).

### Events are skipped silently

* OpenMeter skips events when no customer identity tag is found. Confirm `userId` is set on every generation call.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.