> ## Documentation Index
> Fetch the complete documentation index at: https://docs.instaview.sk/llms.txt
> Use this file to discover all available pages before exploring further.

# Billing & Usage

> Monitor usage and track interview minutes or credits

## Overview

The Billing API provides read-only access to your usage statistics. InstaView supports two billing systems and the same endpoint serves both:

* **Minutes** *(legacy)* — companies are billed by interview minutes consumed. Subscription plans include a minutes allowance and an overage rate per minute.
* **Credits** *(new)* — companies are billed in credits, with a per-product price (`baseCost` plus `costPerMinute` beyond an `includedMinutes` window) determined by the agent focus.

<Info>
  **Required Scope**: `read:billing` is required to access billing and usage endpoints.
</Info>

## Usage Endpoint

### Get Usage Statistics

```javascript theme={null}
const response = await fetch(
  'https://api.instaview.sk/billing/usage?start=2024-01-01&end=2024-01-31',
  { headers: { 'Authorization': `Bearer ${apiKey}` } }
);

const { data } = await response.json();
```

### Query Parameters

* `start` (optional): Start date for the usage period (ISO 8601 format)
* `end` (optional): End date for the usage period (ISO 8601 format)
* If not provided, defaults to the last 30 days

### Response Structure (Minutes-Based Company)

```json theme={null}
{
  "success": true,
  "data": {
    "companies": [
      {
        "companyId": "550e8400-e29b-41d4-a716-446655440000",
        "companyName": "Acme Corp",
        "billingSystem": "minutes",
        "totalMinutesUsed": 245.5,
        "totalInterviews": 42,
        "breakdownByCostKey": [
          {
            "costKey": "interview_minutes",
            "minutesUsed": 245.5,
            "events": 42
          }
        ]
      }
    ],
    "totalMinutesUsed": 245.5,
    "totalInterviews": 42,
    "breakdownByCostKey": [
      {
        "costKey": "interview_minutes",
        "minutesUsed": 245.5,
        "events": 42
      }
    ]
  },
  "error": null,
  "timestamp": "2024-01-31T10:30:00Z"
}
```

### Response Structure (Credits-Based Company)

```json theme={null}
{
  "success": true,
  "data": {
    "companies": [
      {
        "companyId": "550e8400-e29b-41d4-a716-446655440000",
        "companyName": "Acme Corp",
        "billingSystem": "credits",
        "totalCreditsUsed": 612.5,
        "totalInterviews": 42,
        "breakdownByCostKey": [
          {
            "costKey": "interview_minutes",
            "creditsUsed": 612.5,
            "events": 42
          }
        ]
      }
    ],
    "totalCreditsUsed": 612.5,
    "totalInterviews": 42,
    "breakdownByCostKey": [
      {
        "costKey": "interview_minutes",
        "creditsUsed": 612.5,
        "events": 42
      }
    ]
  },
  "error": null,
  "timestamp": "2024-01-31T10:30:00Z"
}
```

### Field Descriptions

* **companies**: Array of company-level usage (for ATS keys managing multiple companies, this contains all companies)
* **billingSystem** *(per company)*: `"minutes"` or `"credits"`. Determines which usage fields are populated.
* **totalMinutesUsed**: Total interview minutes consumed in the period. Present for minutes-based companies (and for ATS keys, aggregated across the managed companies); omitted otherwise.
* **totalCreditsUsed**: Total credits consumed in the period. Present for credits-based companies; omitted otherwise.
* **totalInterviews**: Total number of interviews conducted.
* **breakdownByCostKey**: Usage breakdown by cost category. Each entry exposes `costKey`, `events`, and either `minutesUsed` (minutes-based) or `creditsUsed` (credits-based). Per-company breakdowns never mix the two units.

## Subscription Plans

Subscription plans are defined by:

* **maxInterviewMinutes**: Interview minutes included in the plan (minutes-based companies)
* **pricePerMonth**: Monthly subscription cost
* **pricePerYear**: Annual subscription cost (if applicable)
* **pricePerMinute**: Per-minute cost for usage beyond included minutes (minutes-based companies)
* **Feature flags**: Various boolean flags for features like custom voices, phone numbers, ATS integrations, etc.

For credits-based companies, per-interview pricing is governed by per-product **credit pricing rules** (a `baseCost`, `includedMinutes`, and `costPerMinute` per agent focus). Custom overrides may apply per company.

<Note>
  Plan details, credit pricing rules, and any custom overrides are managed through your company dashboard. Contact sales for custom pricing.
</Note>

## Monitoring Usage

### Check Period Usage

```javascript theme={null}
async function checkUsageStatus() {
  const usage = await getBillingUsage();

  for (const company of usage.companies) {
    if (company.billingSystem === "credits") {
      console.log(`${company.companyName}: ${company.totalCreditsUsed} credits used`);
    } else {
      console.log(`${company.companyName}: ${company.totalMinutesUsed.toFixed(1)} minutes used`);
    }
    console.log(`  Total interviews: ${company.totalInterviews}`);
  }

  return usage;
}
```

### Usage Alerts

Set up monitoring to track usage patterns:

```javascript theme={null}
async function monitorUsage() {
  const usage = await fetch(
    'https://api.instaview.sk/billing/usage',
    { headers: { 'Authorization': `Bearer ${apiKey}` } }
  ).then(r => r.json());
  
  const avgMinutesPerInterview = 
    usage.data.totalMinutesUsed / usage.data.totalInterviews;
  
  console.log(`Average interview length: ${avgMinutesPerInterview.toFixed(1)} minutes`);
  
  // Set up alerts based on your plan limits
  if (usage.data.totalMinutesUsed > 1000) {
    console.warn('High usage detected - consider reviewing subscription plan');
  }
}
```

## ATS Integration Keys

For ATS integration keys managing multiple companies, the usage endpoint returns aggregated data across all managed companies:

```json theme={null}
{
  "companies": [
    {
      "companyId": "company-a-uuid",
      "companyName": "Company A",
      "billingSystem": "minutes",
      "totalMinutesUsed": 120.0,
      "totalInterviews": 20
    },
    {
      "companyId": "company-b-uuid",
      "companyName": "Company B",
      "billingSystem": "minutes",
      "totalMinutesUsed": 125.5,
      "totalInterviews": 22
    }
  ],
  "totalMinutesUsed": 245.5,
  "totalInterviews": 42,
  "breakdownByCostKey": [...]
}
```

## Usage Reporting

### Monthly Usage Report

```javascript theme={null}
async function getMonthlyReport(year, month) {
  const start = new Date(year, month - 1, 1).toISOString();
  const end = new Date(year, month, 0, 23, 59, 59).toISOString();
  
  const response = await fetch(
    `https://api.instaview.sk/billing/usage?start=${start}&end=${end}`,
    { headers: { 'Authorization': `Bearer ${apiKey}` } }
  );
  
  const { data } = await response.json();
  
  return {
    period: `${year}-${String(month).padStart(2, '0')}`,
    minutes: data.totalMinutesUsed,
    interviews: data.totalInterviews,
    avgMinutesPerInterview: data.totalMinutesUsed / data.totalInterviews
  };
}

// Usage
const report = await getMonthlyReport(2024, 1);
console.log(`January 2024: ${report.minutes} minutes, ${report.interviews} interviews`);
```

### Date Range Analysis

```javascript theme={null}
async function analyzeUsageTrend(startDate, endDate, intervalDays = 7) {
  const reports = [];
  const current = new Date(startDate);
  const end = new Date(endDate);
  
  while (current <= end) {
    const intervalEnd = new Date(current);
    intervalEnd.setDate(intervalEnd.getDate() + intervalDays);
    
    const response = await fetch(
      `https://api.instaview.sk/billing/usage?start=${current.toISOString()}&end=${intervalEnd.toISOString()}`,
      { headers: { 'Authorization': `Bearer ${apiKey}` } }
    );
    
    const { data } = await response.json();
    
    reports.push({
      start: current.toISOString(),
      end: intervalEnd.toISOString(),
      minutes: data.totalMinutesUsed,
      interviews: data.totalInterviews
    });
    
    current.setDate(current.getDate() + intervalDays);
  }
  
  return reports;
}
```

## Cost Breakdown

The `breakdownByCostKey` field provides granular usage tracking. Each bucket carries `minutesUsed` for minutes-based companies and `creditsUsed` for credits-based companies.

```javascript theme={null}
async function getCostBreakdown() {
  const usage = await getBillingUsage();

  for (const breakdown of usage.breakdownByCostKey) {
    console.log(`${breakdown.costKey}:`);
    if (typeof breakdown.creditsUsed === "number") {
      console.log(`  - Credits: ${breakdown.creditsUsed}`);
      console.log(`  - Avg per event: ${(breakdown.creditsUsed / breakdown.events).toFixed(2)} credits`);
    }
    if (typeof breakdown.minutesUsed === "number") {
      console.log(`  - Minutes: ${breakdown.minutesUsed}`);
      console.log(`  - Avg per event: ${(breakdown.minutesUsed / breakdown.events).toFixed(2)} min`);
    }
    console.log(`  - Events: ${breakdown.events}`);
  }
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Cache Usage Data" icon="database">
    Cache usage statistics to reduce API calls:

    ```javascript theme={null}
    class UsageCache {
      constructor(ttl = 300000) { // 5 minutes
        this.cache = null;
        this.lastFetch = 0;
        this.ttl = ttl;
      }
      
      async get() {
        if (this.cache && Date.now() - this.lastFetch < this.ttl) {
          return this.cache;
        }
        
        this.cache = await fetchUsageData();
        this.lastFetch = Date.now();
        return this.cache;
      }
    }
    ```
  </Accordion>

  <Accordion title="Set Usage Alerts" icon="bell">
    Monitor usage and set up alerts:

    ```javascript theme={null}
    async function checkUsageAlerts(thresholds) {
      const usage = await getBillingUsage();
      
      if (usage.totalMinutesUsed > thresholds.warning) {
        sendAlert('warning', `Usage at ${usage.totalMinutesUsed} minutes`);
      }
      
      if (usage.totalMinutesUsed > thresholds.critical) {
        sendAlert('critical', `Usage exceeded ${thresholds.critical} minutes`);
      }
    }
    ```
  </Accordion>

  <Accordion title="Track Per-Company Usage" icon="building">
    For ATS integrations, monitor usage per company:

    ```javascript theme={null}
    async function trackCompanyUsage() {
      const usage = await getBillingUsage();
      
      const sortedCompanies = usage.companies.sort(
        (a, b) => b.totalMinutesUsed - a.totalMinutesUsed
      );
      
      console.log('Top companies by usage:');
      sortedCompanies.slice(0, 10).forEach(company => {
        console.log(`${company.companyName}: ${company.totalMinutesUsed} min`);
      });
    }
    ```
  </Accordion>
</AccordionGroup>

## Managing Subscriptions

<Warning>
  **Subscription changes must be made through the dashboard.** The API provides read-only access to usage data. Contact your account manager or visit the billing section of your dashboard to modify your subscription plan.
</Warning>

For subscription changes:

1. Log in to [app.instaview.sk](https://app.instaview.sk)
2. Navigate to **Settings** → **Billing**
3. View available plans and make changes
4. Or contact sales: [sales@instaview.sk](mailto:sales@instaview.sk)

## Next Steps

<CardGroup cols={2}>
  <Card title="Interview API" icon="microphone" href="/guides/resources/interviews">
    Schedule and manage interviews
  </Card>

  <Card title="Best Practices" icon="star" href="/guides/best-practices">
    Optimize your API usage
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Handle billing errors gracefully
  </Card>

  <Card title="Scopes & Permissions" icon="shield" href="/guides/scopes-and-permissions">
    Understand API key scopes
  </Card>
</CardGroup>
