Overview
The Requests resource provides access to detailed logs of individual AI API calls made through Lava’s proxy. Each request contains:
- Token usage and costs
- Provider and model information
- Fee breakdown
- Metadata for filtering
Most developers use this resource to display request history to end users or for detailed analytics.
For aggregated statistics (total tokens, total cost, etc.), use the Usage resource instead.
Methods
list()
List AI requests with optional filtering.
Signature
list(params?: RequestsListParams): Promise<ListResponse<RestRequest>>
Parameters
| Name | Type | Required | Description |
cursor | string | No | Pagination cursor for next page |
limit | number | No | Number of results per page (default: 10, max: 100) |
connection_id | string | No | Filter by connection (customer) |
product_id | string | No | Filter by product configuration |
metadata_filters | Record<string, string> | No | Filter by custom metadata key-value pairs |
Returns
{
data: RestRequest[];
has_more: boolean;
next_cursor?: string;
}
Example: List Recent Requests
const requests = await lava.requests.list({
limit: 20
});
for (const req of requests.data) {
console.log(`${req.created_at}: ${req.model} - ${req.model_usage.total_tokens} tokens - $${req.total_request_cost}`);
}
Example: Filter by Connection
Get all requests for a specific customer:
const customerRequests = await lava.requests.list({
connection_id: 'conn_abc123',
limit: 50
});
const totalCost = customerRequests.data.reduce(
(sum, req) => sum + parseFloat(req.total_request_cost),
0
);
console.log(`Customer total cost: $${totalCost.toFixed(2)}`);
Example: Filter by Metadata
Track requests by feature or user action:
const featureRequests = await lava.requests.list({
metadata_filters: {
feature: 'chat',
version: 'v2'
},
limit: 100
});
console.log(`Found ${featureRequests.data.length} chat v2 requests`);
create()
Manually create a request record for usage tracking (advanced use case).
Signature
create(params: CreateRequestParams): Promise<RestRequest>
Parameters
| Name | Type | Required | Description |
request_id | string | Yes | Unique identifier for this request |
connection_secret | string | Yes | Connection secret for billing |
product_secret | string | Yes | Product secret for pricing |
metadata | Record<string, string> | No | Custom metadata for filtering |
input_tokens | number | No | Number of input tokens |
output_tokens | number | No | Number of output tokens |
input_characters | number | No | Number of input characters |
output_characters | number | No | Number of output characters |
input_seconds | number | No | Seconds of input audio/video |
output_seconds | number | No | Seconds of output audio/video |
Returns
Single RestRequest object with calculated costs.
Example: Manual Request Tracking
const request = await lava.requests.create({
request_id: 'req_custom_' + Date.now(),
connection_secret: 'conn_secret_123',
product_secret: 'prod_secret_456',
input_tokens: 100,
output_tokens: 50,
metadata: {
feature: 'code-generation',
user_id: 'user_789'
}
});
console.log('Request cost:', request.total_request_cost);
When to use create(): Most developers never need this method. It’s only for advanced scenarios where you’re tracking usage outside of Lava’s proxy (e.g., custom provider integrations, offline processing).
retrieve()
Get detailed information for a specific request.
Signature
retrieve(requestId: string): Promise<RestRequest>
Parameters
| Name | Type | Required | Description |
requestId | string | Yes | The request ID |
Returns
{
request_id: string;
status: 'pending' | 'completed' | 'error';
connection_id?: string;
product_id?: string;
provider: string; // 'openai', 'anthropic', etc.
provider_key_type: 'managed' | 'unmanaged';
model?: string;
endpoint: string;
response_id?: string; // Provider's response ID
model_usage: {
input_tokens: number;
output_tokens: number;
total_tokens: number;
input_characters: number;
output_characters: number;
total_characters: number;
input_seconds: number;
output_seconds: number;
total_seconds: number;
input_cost: string; // USD as decimal string
output_cost: string;
total_cost: string;
payer: 'wallet' | 'merchant';
};
fee: {
amount: string;
rate_type: 'fixed' | 'percentage';
token_basis: 'input+output' | 'output';
breakdown: Array<{
tier: {
start: number;
rate: string;
type: 'tokens_1m' | 'characters_1m' | 'minutes' | 'requests';
};
tokens: number;
characters: number;
seconds: number;
cost: string;
}>;
};
service_charge: {
amount: string;
payer: 'wallet' | 'merchant';
};
total_request_cost: string;
total_wallet_cost: string;
total_merchant_cost: string;
metadata: Record<string, string>;
timestamp?: string;
created_at: string;
}
Example
const request = await lava.requests.retrieve('req_abc123');
console.log('Provider:', request.provider);
console.log('Model:', request.model);
console.log('Status:', request.status);
console.log('Total tokens:', request.model_usage.total_tokens);
console.log('Total cost:', request.total_request_cost);
console.log('Metadata:', request.metadata);
Understanding Request Costs
Each request includes multiple cost breakdowns:
const request = await lava.requests.retrieve('req_abc123');
// What the AI provider charged
console.log('Base cost:', request.model_usage.total_cost);
// Your merchant fee
console.log('Merchant fee:', request.fee.amount);
// Lava's service charge (1.9%)
console.log('Service charge:', request.service_charge.amount);
// Total charged to customer's wallet
console.log('Wallet cost:', request.total_wallet_cost);
// Your merchant earnings
console.log('Merchant earnings:', request.total_merchant_cost);
Common Use Cases
Request History for End Users
Display request logs in your application:
async function getUserRequestHistory(connectionId: string) {
const requests = await lava.requests.list({
connection_id: connectionId,
limit: 50
});
return requests.data.map(req => ({
id: req.request_id,
date: new Date(req.created_at),
provider: req.provider,
model: req.model,
tokens: req.model_usage.total_tokens,
cost: parseFloat(req.total_wallet_cost),
status: req.status
}));
}
// Usage in API route
app.get('/api/request-history', async (req, res) => {
const history = await getUserRequestHistory(req.user.connectionId);
res.json(history);
});
Feature Usage Analytics
Track which features are most expensive:
async function analyzeFeatureUsage() {
const requests = await lava.requests.list({
limit: 1000
});
const byFeature = new Map<string, { count: number; cost: number }>();
for (const req of requests.data) {
const feature = req.metadata.feature || 'unknown';
const current = byFeature.get(feature) || { count: 0, cost: 0 };
byFeature.set(feature, {
count: current.count + 1,
cost: current.cost + parseFloat(req.total_request_cost)
});
}
return Array.from(byFeature.entries()).map(([feature, stats]) => ({
feature,
requests: stats.count,
totalCost: stats.cost,
avgCost: stats.cost / stats.count
}));
}
Cost Per User Analysis
Find highest-cost customers:
async function getTopSpenders(limit: number = 10) {
const requests = await lava.requests.list({
limit: 1000
});
const byConnection = new Map<string, number>();
for (const req of requests.data) {
if (!req.connection_id) continue;
const current = byConnection.get(req.connection_id) || 0;
byConnection.set(
req.connection_id,
current + parseFloat(req.total_wallet_cost)
);
}
return Array.from(byConnection.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, limit)
.map(([connectionId, totalCost]) => ({
connectionId,
totalCost
}));
}
Error Rate Monitoring
Track failed requests:
async function getErrorRate(hours: number = 24) {
const requests = await lava.requests.list({
limit: 1000
});
const cutoff = new Date(Date.now() - hours * 60 * 60 * 1000);
const recent = requests.data.filter(
req => new Date(req.created_at) > cutoff
);
const errors = recent.filter(req => req.status === 'error');
return {
total: recent.length,
errors: errors.length,
errorRate: errors.length / recent.length,
errorsByProvider: errors.reduce((acc, req) => {
acc[req.provider] = (acc[req.provider] || 0) + 1;
return acc;
}, {} as Record<string, number>)
};
}
Export to CSV
Generate CSV reports for accounting:
async function exportRequestsToCSV(startDate: string, endDate: string) {
let allRequests: RestRequest[] = [];
let cursor: string | undefined;
do {
const response = await lava.requests.list({
limit: 100,
cursor
});
allRequests.push(...response.data);
cursor = response.next_cursor;
} while (cursor);
// Filter by date range
const filtered = allRequests.filter(req => {
const date = new Date(req.created_at);
return date >= new Date(startDate) && date <= new Date(endDate);
});
// Generate CSV
const csvLines = [
'Date,Provider,Model,Tokens,Cost',
...filtered.map(req =>
[
req.created_at,
req.provider,
req.model,
req.model_usage.total_tokens,
req.total_request_cost
].join(',')
)
];
return csvLines.join('\n');
}
// Usage
const csv = await exportRequestsToCSV('2024-01-01', '2024-01-31');
fs.writeFileSync('january-requests.csv', csv);
Use metadata to track contextual information:
// When making AI requests, include metadata in headers
const response = await fetch(lava.providers.openai + '/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${forwardToken}`,
'X-Lava-Metadata-Feature': 'chat',
'X-Lava-Metadata-User-ID': userId,
'X-Lava-Metadata-Session-ID': sessionId,
'X-Lava-Metadata-Version': 'v2'
},
body: JSON.stringify({ /* ... */ })
});
// Later, filter by metadata
const chatRequests = await lava.requests.list({
metadata_filters: {
feature: 'chat',
version: 'v2'
}
});
Use consistent metadata keys across your application for easier filtering and analytics.