The @lavapayments/nodejs SDK provides a typed client for all Lava API operations including checkout, customers, usage tracking, and forward token generation.
Installation
npm install @lavapayments/nodejs
Requirements: Node.js 18.0.0 or higher
Initialize
import { Lava } from '@lavapayments/nodejs';
const lava = new Lava();
The client reads your secret key from the LAVA_SECRET_KEY environment variable automatically. You can also pass it explicitly: new Lava('aks_live_...'). Never commit API keys to version control.
Resources
| Resource | Purpose | Key Methods |
|---|
checkoutSessions | Create payment flows | create() |
customers | Manage customer links | list(), retrieve(), getSubscription(), delete() |
requests | Track API usage | list(), create(), retrieve() |
usage | Aggregate usage stats | retrieve() |
subscriptions | Manage billing plans | listPlans(), retrievePlan(), createPlan(), updatePlan(), deletePlan(), list(), update(), cancel() |
meters | Pricing configuration | list(), retrieve(), create(), update(), delete() |
creditBundles | Add-on credit packs | list(), retrieve() |
webhooks | Event notifications | list(), retrieve(), create(), update(), delete() |
secretKeys | API key management | list(), create(), delete() |
spendKeys | Wallet spend keys | list(), retrieve(), create(), update(), revoke(), rotate() |
walletKeys | Wallet API keys | list(), revoke(), rotate() |
models | Model discovery | list() |
Plus utility methods:
generateForwardToken() — Create authentication tokens for AI requests
Lava.login() — Browser-based CLI authentication (static)
Lava.exchangeAuthCode() — Exchange auth code for credentials (static)
providers.* — Pre-configured URLs for 26+ AI providers
Authentication
Generating Forward Tokens
Customer-based authentication — use this when billing a specific customer’s wallet with your pricing configuration:
const forwardToken = lava.generateForwardToken({
customer_id: 'conn_id_from_customer',
meter_slug: 'my-meter'
});
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!' }]
})
});
Unmanaged (bring your own key) authentication — use this when you want usage tracking without wallet billing:
const forwardToken = lava.generateForwardToken({
customer_id: null,
meter_slug: null,
provider_key: process.env.OPENAI_API_KEY!
});
Unmanaged mode (bring your own key) lets you use Lava’s proxy for usage tracking and analytics without setting up wallet billing. You supply your own provider API key; the AI provider charges your account directly. Lava may still charge a service fee for metering.
CLI Authentication
Use Lava.login() to authenticate from a CLI or script. It opens the browser, waits for the user to authorize, and returns credentials:
import { Lava } from '@lavapayments/nodejs';
const credentials = await Lava.login();
// credentials: { secret_key, wallet_key?: string | null, wallet_id, merchant_id, ... }
const merchant = new Lava(credentials.secret_key);
const wallet = credentials.wallet_key
? new Lava(credentials.wallet_key)
: null;
Lava.login() loads the active secret key, creating one if needed. It also returns a usable wallet key if one is already available or creates the first wallet key if none exists.
If you already have an authorization code (from a custom callback flow), exchange it directly:
const credentials = await Lava.exchangeAuthCode({
code: 'abc123...',
});
Lava.login() requires a Node.js environment. It starts a local HTTP server and opens the system browser. It is not intended for use in production web applications.
Key Management
Spend Keys
Spend keys give scoped access to your wallet for AI requests. Today these endpoints are still wallet-key authenticated, so use a wallet key if one is available:
const wallet = new Lava('lava_wk_...');
const spendKey = await wallet.spendKeys.create({
name: 'Agent Key',
allowed_providers: ['openai', 'anthropic'],
spend_limit: { amount: '50.00', cycle: 'monthly' },
rate_limit: { rpm: 60 },
});
// spendKey.key — the raw key, only shown once
// Rotate a key's secret (preserves settings)
const rotated = await wallet.spendKeys.rotate(spendKey.spend_key_id);
// rotated.key — new raw key
// Revoke a key
await wallet.spendKeys.revoke(spendKey.spend_key_id);
Secret keys are the long-term primary credential. Wallet-key usage here is transitional while spend-key management is moved off wallet-key auth.
Wallet Keys
Wallet keys authenticate API calls for wallet-scoped operations (spend keys, wallet keys, models):
const wallet = new Lava('lava_wk_...');
const { data: walletKeys } = await wallet.walletKeys.list();
// Rotate a wallet key's secret
const rotated = await wallet.walletKeys.rotate(walletKeys[0].wallet_key_id);
// rotated.key — new raw key, only shown once
// Revoke a wallet key
await wallet.walletKeys.revoke('wk_abc123');
Model Discovery
List available AI models in OpenAI-compatible format. When authenticated with a spend key, results are filtered by the key’s allowed models and providers:
const wallet = new Lava('lava_wk_...');
const { data: models } = await wallet.models.list();
// models[0]: { id: 'gpt-4o-mini', object: 'model', owned_by: 'openai', created: ... }
Key Operations
Create a Checkout Session
const session = await lava.checkoutSessions.create({
checkout_mode: 'subscription',
origin_url: 'https://yourapp.com',
plan_id: 'sc_plan_id'
});
// Pass session.checkout_session_token to the checkout SDK
Checkout modes: subscription (recurring plan), credit_bundle (add-on credits).
Retrieve a Customer
const customer = await lava.customers.retrieve('conn_abc123');
customer.customer_id; // unique customer ID
customer.contact; // { phone, email, first_name, last_name }
customer.subscription; // summary or null
Check Subscription Status
const { subscription } = await lava.customers.getSubscription('conn_abc123');
if (subscription) {
subscription.plan.name; // plan name
subscription.credits.total_remaining; // total available credits
subscription.credits.cycle_remaining; // from included credit + rollover
subscription.credits.bundle_remaining; // from bundle purchases + rollover
subscription.cycle_end_at; // current cycle end date
subscription.pending_change; // null, or { type: 'cancellation' | 'downgrade', effective_at }
}
Update a Subscription
// Set auto top-up bundle for a customer's subscription
await lava.subscriptions.update('as_abc123', {
auto_top_up_bundle_id: 'cb_pack_id'
});
// Disable auto top-up
await lava.subscriptions.update('as_abc123', {
auto_top_up_bundle_id: null
});
Report Usage (Post-Request Billing)
For advanced scenarios where you track usage outside of Lava’s proxy:
const request = await lava.requests.create({
request_id: 'req_custom_' + Date.now(),
customer_id: 'conn_abc123',
meter_slug: 'my-meter',
input_tokens: 100,
output_tokens: 50,
metadata: {
feature: 'code-generation',
user_id: 'user_789'
}
});
request.cost; // base AI provider cost
request.charge.amount; // merchant fee/markup charged
request.model_usage; // { input_tokens, output_tokens, total_cost, ... }
Get Usage Statistics
const usage = await lava.usage.retrieve({
start: '2025-01-01T00:00:00Z',
end: '2025-01-31T23:59:59Z',
// Optional filters:
// customer_id: 'conn_abc123',
// meter_id: 'meter_abc123',
// metadata_filters: { feature: 'chat' },
});
usage.totals.total_requests; // aggregate request count
usage.totals.total_usage_tokens; // aggregate token count
usage.totals.total_cost; // aggregate AI provider cost
usage.totals.total_charge; // aggregate merchant fees/markup
usage.items; // daily breakdown array
Common Patterns
All list methods support cursor-based pagination:
let cursor: string | undefined;
const allCustomers = [];
do {
const response = await lava.customers.list({ limit: 100, cursor });
allCustomers.push(...response.data);
cursor = response.next_cursor;
} while (cursor);
Error Handling
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!' }]
})
});
if (!response.ok) {
const error = await response.json();
// 402 — insufficient wallet balance
// 401 — invalid forward token
// Other — provider error (passed through)
}
const data = await response.json();
Complete Flow Example
A complete integration from checkout to AI request:
import { Lava } from '@lavapayments/nodejs';
const lava = new Lava();
// 1. Create a checkout session for a new customer
const session = await lava.checkoutSessions.create({
checkout_mode: 'subscription',
origin_url: 'https://yourapp.com',
plan_id: 'sc_plan_id'
});
// Pass session.checkout_session_token to the checkout SDK
// 2. After checkout completes, your frontend receives a customer_id
// Store it in your database, associated with your user
// 3. Generate a forward token for AI requests
const forwardToken = lava.generateForwardToken({
customer_id: 'conn_...', // from your database
meter_slug: process.env.LAVA_METER_SLUG!
});
// 4. Make an AI request through Lava's proxy
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: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Hello!' }
]
})
});
const data = await response.json();
// 5. Check remaining credit
const { subscription } = await lava.customers.getSubscription('conn_...');
// subscription?.credits.total_remaining
The SDK automatically detects test vs production mode based on your secret key prefix:
aks_test_* routes to sandbox (sandbox-api.lava.so)
- Other prefixes route to production (
api.lava.so)
Next Steps