> ## 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.

# Stripe

> Send AI-billing LLM usage events to Stripe Meters and map them to customers so you can bill end users for AI consumption with subscriptions and metered pricing.

# Stripe billing platform integration

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

This page covers Stripe-specific setup:

* Choose a metering strategy (nanos or itemized).
* Create the `@ai-billing/stripe` destination.
* Map usage events to Stripe customers.
* Sync customer records when users sign up and store the Stripe customer ID.

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

## Metering strategy

Stripe supports two ways to bill LLM usage with Narev:

| Strategy | What you bill | Price sync needed? |
| - | - | - |
| **Nanos (recommended)** | Resolved dollar cost per generation (`value` on the meter event) | 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 Stripe metered prices |

The rest of this guide covers **nanos metering**: one `llm_usage` meter, cost in `value`, customer in `stripe_customer_id`.

### Itemized metering (advanced)

Itemized billing creates one Stripe product per model with up to six meters (`input_tokens`, `output_tokens`, `reasoning_tokens`, `cache_read_tokens`, `cache_write_tokens`, `request_count`). Each meter gets a metered price whose `unit_amount_decimal` reflects Narev's per-token USD rate converted to cents:

```ts theme={null}
function pricePerTokenToUnitAmount(pricePerToken: number): string {
  return (pricePerToken * 100).toFixed(12).replace(/\.?0+$/, '') || '0';
}
```

When Narev updates a model price, deactivate the old metered price and create a new one on the same meter.

## Before you start

Create a Stripe Meter in the [Stripe Dashboard](https://dashboard.stripe.com/meters) with an event name such as `llm_usage`. The `meterName` in your destination config must match that event name.

## Install Stripe dependencies

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

## Configure environment variables

Set these on your server:

```bash theme={null}
STRIPE_SECRET_KEY=sk_test_****
```

Use a test key (`sk_test_...`) until your metering flow is verified.

## Create Stripe billing destinations

Create `lib/ai/destinations.ts`:

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

export function getBillingDestinations() {
  const stripeSecretKey = process.env.STRIPE_SECRET_KEY;

  if (!stripeSecretKey) return [];

  return [
    createStripeDestination({
      apiKey: stripeSecretKey,
      meterName: 'llm_usage',
    }),
  ];
}
```

The destination reads `stripe_customer_id` from `ai-billing-tags` on each generation call.

## Sync Stripe customers when users sign up

Create `lib/stripe-client.ts`:

```ts lib/stripe-client.ts theme={null}
import Stripe from 'stripe';

let _stripe: Stripe | null = null;

function getStripeClient(): Stripe | null {
  if (_stripe) return _stripe;

  const apiKey = process.env.STRIPE_SECRET_KEY;
  if (!apiKey) return null;

  _stripe = new Stripe(apiKey);
  return _stripe;
}

export async function createStripeCustomer(
  email: string,
): Promise<string | undefined> {
  const stripe = getStripeClient();
  if (!stripe) return;

  try {
    const customer = await stripe.customers.create({ email });
    return customer.id;
  } catch (error) {
    console.error('[ai-billing] Failed to create Stripe customer:', error);
  }
}
```

Call this when a user signs up and persist the returned ID on the user record:

```ts theme={null}
if (newUser) {
  const stripeCustomerId = await createStripeCustomer(validatedData.email);
  if (stripeCustomerId) {
    await saveStripeCustomerId(newUser.id, stripeCustomerId);
  }
}
```

## Required tag contract

In your generation routes, include `stripe_customer_id` in `ai-billing-tags`:

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

Contract requirements:

* `stripe_customer_id` in `ai-billing-tags` must match a Stripe Customer ID (`cus_...`).
* Each user should have one Stripe customer record.
* Stripe limits meter event payloads to 10 keys. The destination prioritizes `value` (cost) and `stripe_customer_id`, then core AI metrics and your custom tags.

> [!NOTE]
>
> The Stripe destination sends cost as the meter `value`. If your provider does not return pricing natively, attach a price resolver (for example, Narev) in your framework middleware. See [@ai-billing/stripe reference](https://www.narev.ai/docs/ai-billing/reference/stripe/index.md).

## Verify Stripe metering

1. Register a new user and confirm a Stripe customer exists with ID `cus_...`.
2. Trigger a model call and confirm a meter event named `llm_usage` appears in Stripe.
3. Validate the payload contains `stripe_customer_id`, `value`, and your route context tags.
4. Confirm your environment uses the expected Stripe mode (test or live key).

## Common issues

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

* Confirm `stripe_customer_id` exists in `ai-billing-tags`.
* Confirm the tag value is a valid Stripe Customer ID, not your internal `userId`.
* Confirm the customer was created in the same Stripe account as your secret key.

### No events arrive in Stripe

* Confirm `STRIPE_SECRET_KEY` is present at runtime.
* Confirm the meter event name matches your Stripe Meter configuration.
* Confirm framework routes call the billing-wrapped model helper.
* Confirm each billing event includes a defined `cost` (attach a price resolver if needed).

### Meter payload is truncated

* Stripe allows at most 10 payload keys. Keep custom tags minimal or use `mapMetadata` in `createStripeDestination` to control which fields are sent.


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