Skip to main content

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
NameTypeRequiredDescription
cursorstringNoPagination cursor for next page
limitnumberNoNumber of results per page (default: 10, max: 100)
connection_idstringNoFilter by connection (customer)
product_idstringNoFilter by product configuration
metadata_filtersRecord<string, string>NoFilter 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
NameTypeRequiredDescription
request_idstringYesUnique identifier for this request
connection_secretstringYesConnection secret for billing
product_secretstringYesProduct secret for pricing
metadataRecord<string, string>NoCustom metadata for filtering
input_tokensnumberNoNumber of input tokens
output_tokensnumberNoNumber of output tokens
input_charactersnumberNoNumber of input characters
output_charactersnumberNoNumber of output characters
input_secondsnumberNoSeconds of input audio/video
output_secondsnumberNoSeconds 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
NameTypeRequiredDescription
requestIdstringYesThe 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);

Metadata Best Practices

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.