Skip to main content
This guide shows how to create a complete billing flow programmatically: define pricing, create a plan, embed checkout, and route billable traffic per customer.
Prerequisites: Start with Authenticate an Agent, then follow Route Traffic for the gateway path you chose.

MCP flow

If your agent is already using the Lava MCP server, the end-to-end billing flow is:
  1. lava_login
  2. lava_create_meter
  3. lava_create_plan
  4. lava_create_checkout_session
  5. lava_generate_forward_token
  6. lava_chat_completions or lava_forward
Use the SDK code below only if you are implementing the same flow directly in your application code.

SDK flow

Overview

The billing flow has four parts:
  1. Meter - Defines how usage is priced (e.g., $3 per million tokens)
  2. Plan - A subscription that includes an optional monthly fee, credit allowance, and linked meters
  3. Checkout - An embedded flow where your customer subscribes and pays
  4. Forward tokens - Per-customer auth tokens that route traffic through the gateway with billing

Step 1: Create a Meter

A meter defines the pricing rules for a type of usage. For example, charging per token for AI model calls:
import { Lava } from '@lavapayments/nodejs';

const lava = new Lava(); // reads LAVA_SECRET_KEY from env

const meter = await lava.meters.create({
  name: 'AI Chat Tokens',
  rate_type: 'fixed',
  tier_type: 'tokens_1m',
  tiers: [
    { start: '0', rate: '3.00' }  // $3.00 per million tokens
  ]
});

console.log('Meter ID:', meter.meter_id);
console.log('Meter slug:', meter.meter_slug);

Meter options

ParameterOptionsDescription
rate_typefixed, percentageFixed price per unit, or percentage markup on base cost
tier_typetokens_1m, characters_1m, minutes, requestsWhat unit is being measured
You can also add volume-based tiers for graduated pricing:
const meter = await lava.meters.create({
  name: 'API Requests',
  rate_type: 'fixed',
  tier_type: 'requests',
  tiers: [
    { start: '0', rate: '0.01' },       // $0.01/request for first 10k
    { start: '10000', rate: '0.005' }    // $0.005/request after 10k
  ]
});

Step 2: Create a Plan

A plan ties together an optional recurring price, included credits, and one or more meters (product features included in your plan):
const plan = await lava.subscriptions.createPlan({
  name: 'Pro Plan',
  period_amount: '49.00',
  billing_interval: 'month',
  included_credit: '25.00',
  meter_ids: [meter.meter_id]  // Link meters to this plan
});

console.log('Plan ID:', plan.plan_id);
The meter_ids field links meters to the plan. You can link multiple meters to a single plan.

Plan options

ParameterOptionsDescription
billing_intervalday, week, month, yearHow often the subscription renews
rollover_typefull, noneWhether unused included credit carries over
included_creditAny decimal stringCredit included with each billing cycle
credit_bundlesArray of bundlesOptional add-on credit packs customers can purchase
Example with credit bundles:
const plan = await lava.subscriptions.createPlan({
  name: 'Pro Plan',
  period_amount: '99.00',
  billing_interval: 'month',
  included_credit: '50.00',
  rollover_type: 'full',
  meter_ids: [meterA.meter_id, meterB.meter_id],
  credit_bundles: [
    { name: '$25 Top-up', cost: '25.00', credit_amount: '25.00' },
    { name: '$100 Top-up', cost: '100.00', credit_amount: '100.00' }
  ]
});

Step 3: Embed Checkout

Checkout is a two-step flow: your backend creates a session, your frontend opens it with the @lavapayments/checkout SDK.
npm install @lavapayments/checkout

Backend: Create a session

const session = await lava.checkoutSessions.create({
  checkout_mode: 'subscription',
  origin_url: 'https://yourapp.com',
  plan_id: plan.plan_id
});

// Return session.checkout_session_token to your frontend

Frontend: Open checkout

import { useLavaCheckout } from '@lavapayments/checkout';

const { open } = useLavaCheckout({
  onSuccess: ({ customerId }) => {
    // Save customerId — this is the billing relationship with your customer
  }
});

// Call with the token from your backend
open(checkoutSessionToken);
The checkout overlay handles phone verification, payment method collection, and subscription creation. When complete, onSuccess fires with the customerId.
Checkout sessions expire after 60 minutes. Create a new session for each checkout attempt.
The checkout_session_token is an opaque token — do not try to construct URLs from it. Always use the SDK to open checkout.

Step 4: Route Billable Traffic

Once a customer has completed checkout, generate forward tokens scoped to their customer ID and meter. Every request made with this token is tracked and billed against their subscription:
// Get the customer (from your database, or list them)
const { data: customers } = await lava.customers.list();
const customer = customers[0];

// Generate a forward token for this customer
const forwardToken = lava.generateForwardToken({
  customer_id: customer.customer_id,
  meter_slug: meter.meter_slug,
});

// Use it exactly like in the Route Traffic guide
const response = await fetch(lava.providers.openai + '/chat/completions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${forwardToken}`
  },
  body: JSON.stringify({
    model: 'gpt-4o-mini',
    messages: [{ role: 'user', content: 'Hello!' }]
  })
});

Step 5: Monitor Customer Usage

Track usage and costs per customer:
// Get usage for a specific customer
const usage = await lava.usage.retrieve({
  start: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
  customer_id: customer.customer_id,
});

console.log('Customer requests:', usage.totals.total_requests);
console.log('Customer cost:', usage.totals.total_cost);

// Check their subscription status
const sub = await lava.customers.getSubscription(customer.customer_id);
if (sub.subscription) {
  console.log('Plan:', sub.subscription.plan.name);
  console.log('Credits remaining:', sub.subscription.credits.total_remaining);
}

What’s Next?