The @lavapayments/nodejs SDK provides a typed client for all Lava API operations including checkout, connections, 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() |
connections | Manage customer links | list(), retrieve(), getSubscription(), delete() |
requests | Track API usage | list(), create(), retrieve() |
usage | Aggregate usage stats | retrieve() |
subscriptions | Manage billing plans | listConfigs(), retrieveConfig(), createConfig(), updateConfig(), deleteConfig(), list(), 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
Connection-based authentication — use this when billing a specific customer’s wallet with your pricing configuration:
const forwardToken = lava.generateForwardToken({
connection_id: 'conn_id_from_connection',
meter_slug: 'my-meter'
});
// Use the token in AI requests
const response = await fetch(lava.providers.openai + '/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${forwardToken}`
},
body: JSON.stringify({ /* request body */ })
});
BYOK (Bring Your Own Key) authentication — use this when you want usage tracking without wallet billing:
const forwardToken = lava.generateForwardToken({
connection_id: null,
meter_slug: null,
provider_key: process.env.OPENAI_API_KEY!
});
// Lava tracks usage but uses your provider key
const response = await fetch(lava.providers.openai + '/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${forwardToken}`
},
body: JSON.stringify({ /* request body */ })
});
BYOK mode allows you to use Lava’s proxy for usage tracking and analytics without setting up wallet billing. The AI provider charges your provider account directly.
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 contains:
// - wallet_key_id, wallet_key (lava_wk_*)
// - secret_key_id, secret_key (lava_sk_*)
// - wallet_id, merchant_id
// Use the returned keys to initialize clients
const wallet = new Lava(credentials.wallet_key);
const merchant = new Lava(credentials.secret_key);
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. You can set model restrictions, spend limits, rate limits, and expiration:
const wallet = new Lava('lava_wk_...');
// Create a spend key with restrictions
const spendKey = await wallet.spendKeys.create({
name: 'Agent Key',
allowed_providers: ['openai', 'anthropic'],
spend_limit: { amount: '50.00', cycle: 'monthly' },
rate_limit: { rpm: 60 },
});
console.log('Key:', spendKey.key); // Only shown once
// List spend keys
const { data: keys } = await wallet.spendKeys.list();
// Rotate a key's secret (preserves settings)
const rotated = await wallet.spendKeys.rotate(spendKey.spend_key_id);
console.log('New key:', rotated.key);
// Revoke a key
await wallet.spendKeys.revoke(spendKey.spend_key_id);
Wallet Keys
Wallet keys authenticate API calls for wallet-scoped operations (spend keys, wallet keys, models):
const wallet = new Lava('lava_wk_...');
// List wallet keys
const { data: walletKeys } = await wallet.walletKeys.list();
// Rotate a wallet key's secret
const rotated = await wallet.walletKeys.rotate(walletKeys[0].wallet_key_id);
console.log('New key:', rotated.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();
for (const model of models) {
console.log(`${model.id} (${model.owned_by})`);
}
Key Operations
Create a Checkout Session
const session = await lava.checkoutSessions.create({
checkout_mode: 'subscription',
origin_url: 'https://yourapp.com',
subscription_config_id: 'sub_plan_id'
});
// Pass to frontend
res.json({
checkoutToken: session.checkout_session_token
});
Checkout modes: onboarding (new wallet), topup (add funds), subscription (recurring plan), credit_bundle (add-on credits).
Retrieve a Connection
const connection = await lava.connections.retrieve('conn_abc123');
if (!connection.has_lava_credit_balance) {
console.log('No credit balance - prompt user to add funds');
} else {
console.log('User has credit balance');
}
Check Subscription Status
const result = await lava.connections.getSubscription('conn_abc123');
if (result.subscription) {
const { credits, plan } = result.subscription;
console.log('Credit Breakdown:');
console.log(` From plan: $${parseFloat(credits.cycle_remaining).toFixed(2)} (rollover: ${plan.rollover_type})`);
console.log(` From bundles: $${parseFloat(credits.bundle_remaining).toFixed(2)} (rollover: ${plan.bundle_rollover_type})`);
console.log(` Total: $${parseFloat(credits.total_remaining).toFixed(2)}`);
}
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(),
connection_id: 'conn_id_123',
meter_slug: 'my-meter',
input_tokens: 100,
output_tokens: 50,
metadata: {
feature: 'code-generation',
user_id: 'user_789'
}
});
console.log('Request cost:', request.total_request_cost);
Get Usage Statistics
const usage = await lava.usage.retrieve({
start: '2024-01-01T00:00:00Z',
end: '2024-01-31T23:59:59Z'
});
console.log('Total requests:', usage.totals.total_requests);
console.log('Total tokens:', usage.totals.total_usage_tokens);
console.log('Total revenue:', usage.totals.total_merchant_cost);
// Daily breakdown
for (const day of usage.items) {
console.log(`${day.date}: ${day.total_requests} requests, $${day.total_merchant_cost}`);
}
Common Patterns
All list methods support cursor-based pagination:
let cursor: string | undefined;
const allConnections: RestConnection[] = [];
do {
const response = await lava.connections.list({
limit: 100,
cursor
});
allConnections.push(...response.data);
cursor = response.next_cursor;
} while (cursor);
console.log(`Total connections: ${allConnections.length}`);
Error Handling
try {
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();
if (response.status === 402) {
console.error('Insufficient wallet balance');
} else if (response.status === 401) {
console.error('Invalid forward token');
} else {
console.error('Provider error:', error);
}
}
const data = await response.json();
} catch (error) {
console.error('Network error:', error);
}
Complete Flow Example
Here is a complete example showing the full integration workflow from checkout to AI request:
import { Lava } from '@lavapayments/nodejs';
const lava = new Lava();
// Step 1: Create a checkout session for a new customer
const session = await lava.checkoutSessions.create({
checkout_mode: 'onboarding',
origin_url: 'https://yourapp.com'
});
console.log('Checkout token:', session.checkout_session_token);
// Pass this token to your frontend to display the checkout UI
// Step 2: User completes payment on frontend
// (Use @lavapayments/checkout React library - not covered here)
// The frontend receives the connection_id after checkout completes
// Store this connection_id in your database, associated with your user
// Step 3: Retrieve the connection using the stored connection_id
const connectionId = 'conn_...'; // Retrieved from your database
const connection = await lava.connections.retrieve(connectionId);
// Step 4: Generate forward token for AI requests
const forwardToken = lava.generateForwardToken({
connection_id: connection.connection_id,
meter_slug: process.env.LAVA_METER_SLUG!
});
// Step 5: 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();
console.log('AI response:', data);
// Step 6: Check credit status
const updatedConnection = await lava.connections.retrieve(connection.connection_id);
console.log('Has credit balance:', updatedConnection.has_lava_credit_balance);
The SDK automatically detects test vs production mode based on your secret key prefix:
aks_test_* routes to sandbox (sandbox-api.lavapayments.com)
- Other prefixes route to production (
api.lavapayments.com)
Next Steps