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

# Polar

> Send Narev Cloud LLM usage events to Polar and sync customers so you can bill end users for AI consumption with subscriptions and metered pricing.

# Polar billing platform integration

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

This page covers Polar-specific setup:

* Choose a metering strategy (nanos or itemized).
* Create the `@ai-billing/polar` destination.
* Map usage events to Polar customers.
* Sync user identity with `externalId`.

For the server middleware setup, use [Node.js billing integration](/docs/platform/billing/integrations/frameworks/nodejs).

## Metering strategy

Polar supports two ways to bill LLM usage with Narev:

| Strategy                | What you bill                                                         | Price sync needed?                                         |
| ----------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------- |
| **Nanos (recommended)** | Resolved dollar cost per generation                                   | No. Narev resolves cost at request time via `@ai-billing`  |
| **Itemized**            | Raw token counts per model (input, output, reasoning, cache, request) | Yes. Push per-token rates into Polar `metered_unit` prices |

The rest of this guide covers **nanos metering**: one `llm_usage` event, customer matched via `userId` → `externalId`.

<Note>
  Narev Cloud no longer hosts a Connect dashboard for Polar. Credentials, meters, and destinations live in your application. The removed Connect flow also provisioned top-up credit products and itemized per-model products with a daily price sync cron. Replicate any of that in your own infrastructure using the [Narev Prices API](/docs/platform/api-reference/v1/prices/search) and the Polar Products API.
</Note>

### Itemized metering (advanced)

Itemized billing creates one Polar product per model with meters for each token dimension. Update prices by calling `polar.products.update` with `metered_unit` entries whose `unitAmount` uses the same cents-per-token conversion as Stripe (`pricePerToken * 100`). The removed Connect sync ran this daily for itemized connections only.

## Install polar dependencies

```bash theme={null}
pnpm add @ai-billing/polar @polar-sh/sdk
```

## Configure environment variables

Set these on your server:

```bash theme={null}
POLAR_ACCESS_TOKEN=****
POLAR_SERVER=sandbox # or production
```

Use `sandbox` until your metering flow is verified.

## Create Polar billing destinations

Create `lib/ai/destinations.ts`:

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

export function getBillingDestinations() {
  const polarAccessToken = process.env.POLAR_ACCESS_TOKEN;
  const polarServer = process.env.POLAR_SERVER as
    | 'sandbox'
    | 'production'
    | undefined;

  if (!polarAccessToken) return [];

  return [
    createPolarDestination({
      accessToken: polarAccessToken,
      server: polarServer ?? 'sandbox',
      eventName: 'llm_usage',
      externalCustomerIdKey: 'userId',
    }),
  ];
}
```

The key mapping is `externalCustomerIdKey: 'userId'`. Your billing tags must include `userId`.

## Sync Polar customers on signup

Create `lib/polar-client.ts`:

```ts lib/polar-client.ts theme={null}
import { Polar } from '@polar-sh/sdk';

let _polar: Polar | null = null;

function getPolarClient(): Polar | null {
  if (_polar) return _polar;

  const accessToken = process.env.POLAR_ACCESS_TOKEN;
  if (!accessToken) return null;

  const server = (process.env.POLAR_SERVER ?? 'sandbox') as
    | 'sandbox'
    | 'production';

  _polar = new Polar({ accessToken, server });
  return _polar;
}

export async function createPolarCustomer(email: string, userId: string) {
  const polar = getPolarClient();
  if (!polar) return;

  try {
    await polar.customers.create({ email, externalId: userId });
  } catch (error) {
    console.error('[ai-billing] Failed to create Polar customer:', error);
  }
}
```

Call this when a user signs up:

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

## 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 Polar `externalId`.
* Each user should have one Polar customer record.

## Verify polar metering

1. Register a new user and confirm a Polar customer exists with `externalId = userId`.
2. Trigger a model call and confirm an event named `llm_usage` appears.
3. Validate metadata contains `userId`, `modelId`, and route context.
4. Confirm your environment uses the expected Polar server (`sandbox` or `production`).

## Common issues

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

* Confirm `userId` exists in `ai-billing-tags`.
* Confirm destination uses `externalCustomerIdKey: 'userId'`.
* Confirm customer creation uses `externalId = userId`.

### No events arrive in Polar

* Confirm `POLAR_ACCESS_TOKEN` is present at runtime.
* Confirm `POLAR_SERVER` matches the Polar workspace you are checking.
* Confirm framework routes call the billing-wrapped model helper.
