> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://onepin.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://onepin.ai/docs/_mcp/server.

# Usage Summary

GET https://api.onepin.ai/api/v1/usage/summary

Return aggregated usage totals and activity chart data for the workspace.

Combines credit consumption, character and line counts, and workflow run
statistics for the requested rolling window (`range`) with a chart-ready
activity series (`activity`) bucketed by `activity_view`.

The `credits.used` field reflects the authenticated user's own billing-period
consumption; all other aggregate fields (characters, lines, runs, daily
buckets, activity buckets) are workspace-scoped across all members.

Date boundaries are computed in the supplied `timezone` (IANA, e.g.
`America/New_York`) so "today" and "this week" align with the caller's local
calendar. Defaults to UTC.

Use `GET /usage/by-language` for a language-level breakdown, or
`GET /usage/activity` for the event-by-event feed.

Dual-auth: Bearer JWT or API key (scope `workspace:read`).

Reference: https://onepin.ai/docs/reference/api-reference/usage/summary-api-v-1-usage-summary-get

## Authentication

- `Authorization` header (bearer token, required) — Clerk JWT token
- `Authorization` header (bearer token, required) — Onepin live API key (`op_live_...`). Test and public keys are reserved in Phase 1.

## Servers

- `https://api.onepin.ai` (prod, default)
- `https://dev-api.onepin.ai` (dev)

## Request

### Query parameters

- `range` (enum, optional, default: 30d) — Rolling local calendar-day range.
  - Allowed values: `30d`, `60d`, `90d`
- `activity_view` (enum, optional, default: daily) — Activity chart view: daily=7 local days, weekly=12 Monday-start weeks, monthly=12 months.
  - Allowed values: `daily`, `weekly`, `monthly`
- `timezone` (string, optional, default: UTC) — IANA timezone for local day bucketing.

### Headers

- `X-Workspace-Id` (string, optional, nullable)

## Response

### 200

Successful Response

- `data` (UsageSummaryOut, required)
- `meta` (Meta, required)

## Errors

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### UsageSummaryOut

- `range` (enum, required) — Rolling window applied to aggregate totals: `30d`, `60d`, or `90d`.
  - Allowed values: `30d`, `60d`, `90d`
- `activity_view` (enum, required) — Chart bucketing period applied to the `activity` series.
  - Allowed values: `daily`, `weekly`, `monthly`
- `timezone` (string, required) — IANA timezone used for local day/week/month boundary computation.
- `period` (UsagePeriodOut, required) — Absolute UTC start and end of the rolling window.
- `credits` (UsageCreditsOut, required) — Credit consumption and quota for the authenticated user's billing period.
- `characters` (UsageCharactersOut, required) — Total characters processed across the workspace in the rolling window.
- `lines` (UsageLinesOut, required) — Total script lines generated across the workspace in the rolling window.
- `audio` (UsageAudioOut, required) — Delivered audio length across the workspace in the rolling window, retries excluded. A different population from `characters` — see `UsageAudioOut`.
- `runs` (UsageRunsOut, required) — Workflow run counts by status across the workspace in the rolling window.
- `activity` (UsageActivitySummaryOut, required) — Bucketed activity chart data for the selected `activity_view`.
- `corrected` (UsageCorrectedOut, optional) — Words respliced by the Pronunciation Corrector across the workspace in the rolling window. Counted in WORDS, not characters, and never summed with `characters`.
- `daily` (list of UsageDailyOut, optional) — Per-calendar-day breakdown for the rolling window, ordered oldest first.

### Meta

- `request_id` (string, required)
- `timestamp` (datetime, required)

### ValidationError

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `input` (any, optional)
- `ctx` (ValidationErrorCtx, optional)

### UsagePeriodOut

- `start` (datetime, required) — Start of the reporting period (inclusive), in UTC.
- `end` (datetime, required) — End of the reporting period (exclusive), in UTC.

### UsageCreditsOut

- `used` (integer, required) — Credits used for the authenticated user's current billing period; daily and activity buckets remain workspace-scoped.
- `quota` (integer, optional, nullable) — Customer display quota reconciled with settled billing-period usage and the current spendable balance, without dropping below the applicable plan or lifetime-grant allowance. Null only when no authenticated user is available for this aggregate.
- `percent` (double, optional, nullable) — Credits used as a percentage of quota, clamped to 0–100; null when quota is zero or unavailable.

### UsageCharactersOut

- `total` (integer, required) — Total characters processed across all workflow runs in the period.

### UsageLinesOut

- `total` (integer, required) — Total script lines generated in the period.
- `avg_chars_per_line` (double, optional, nullable) — Average character count per generated line, or `null` when no lines exist.

### UsageAudioOut

Delivered audio length — the delivered take per independent generator, retries excluded. A different population from `characters`, which counts billed generator characters and so includes every regenerated take. The two are reported side by side on the Usage page but must not be reasoned about as one basis. NOT one take per line. A line fed by two independent generators — the A/B voice-comparison shape — delivers both branches and both count (POD-593), so such a run contributes roughly twice the audio a per-line reading would predict. A run contributes 0 until it reaches a terminal status, because the delivered total is stamped only then. A window covering a still-running or parked run (parked runs survive up to `PAUSED_RUN_MAX_DAYS`) therefore under-reports it, and the SAME window's total grows once that run terminates. Separately, runs that terminated before the stamp shipped to production (`v0.41.105`, 2026-08-07) carry no value at all, so longer `range` windows under-report until that date falls out of the window.

- `total_ms` (integer, required) — Total delivered audio length in milliseconds across the workspace in the period, counting the delivered take per independent generator on each line (retries excluded). Zero when no audio was delivered.

### UsageRunsOut

- `total` (integer, required) — Total workflow runs initiated in the period.
- `completed` (integer, required) — Runs that finished successfully.
- `failed` (integer, required) — Runs that terminated with an error.
- `cancelled` (integer, required) — Runs that were cancelled by the user or system.
- `running` (integer, required) — Runs currently in progress.
- `pending` (integer, required) — Runs queued but not yet started.
- `paused` (integer, optional, default: 0) — Runs currently paused awaiting manual review.

### UsageActivitySummaryOut

- `view` (enum, required) — The activity view period applied: `daily`, `weekly`, or `monthly`.
  - Allowed values: `daily`, `weekly`, `monthly`
- `bucket_unit` (enum, required) — Time unit for each bucket: `day`, `week`, or `month`.
  - Allowed values: `day`, `week`, `month`
- `range_label` (string, required) — Human-readable label for the chart range (e.g. `Last 7 days`, `Last 12 weeks`).
- `total` (integer, required) — Total credits consumed across all activity buckets — workspace-wide over the activity view window. Distinct from `UsageSummaryOut.credits.used`, which is the caller's own consumption scoped to the billing period.
- `avg` (double, required) — Average credits consumed per activity bucket, rounded to 1 decimal.
- `buckets` (list of UsageActivityBucketOut, optional) — Ordered list of time buckets covering the activity view period, newest last.
- `peak` (UsageActivityPeakOut, optional, nullable) — The bucket with the highest credit consumption, or `null` when no credits were consumed.

### UsageCorrectedOut

Words the Pronunciation Corrector respliced — a SEPARATE unit from `characters`. Reported apart rather than folded in because the two count different things: `characters` is text the generator synthesized, this is words a remediation node fixed inside already generated audio. Adding them would produce a number that is neither.

- `total` (integer, required) — Total words respliced by the Pronunciation Corrector in the period.

### UsageDailyOut

- `date` (string, required) — Local calendar date for this bucket in `YYYY-MM-DD` format, computed in the requested timezone.
- `credits` (integer, required) — Credits consumed on this date.
- `characters` (integer, required) — Characters processed on this date.
- `lines` (integer, required) — Script lines generated on this date.
- `runs` (integer, required) — Workflow runs started on this date.

### ValidationErrorLocItems

### ValidationErrorCtx

### UsageActivityBucketOut

- `label` (string, required) — Human-readable label for the bucket period (e.g. `Mon`, `Jan`, `Week 1`).
- `start` (datetime, required) — Start of the bucket period (inclusive), in UTC.
- `end` (datetime, required) — End of the bucket period (exclusive), in UTC.
- `credits` (integer, required) — Credits consumed in this bucket.
- `characters` (integer, required) — Characters processed in this bucket.
- `lines` (integer, required) — Script lines generated in this bucket.
- `runs` (integer, required) — Workflow runs in this bucket.

### UsageActivityPeakOut

- `value` (integer, required) — Peak bucket credit consumption.
- `label` (string, required)
- `start` (datetime, required)
- `end` (datetime, required)

## Examples

**Response**

```json
{
  "data": {
    "range": "30d",
    "activity_view": "daily",
    "timezone": "string",
    "period": {
      "start": "2024-01-15T09:30:00Z",
      "end": "2024-01-15T09:30:00Z"
    },
    "credits": {
      "used": 1,
      "quota": 1,
      "percent": 1.1
    },
    "characters": {
      "total": 1
    },
    "lines": {
      "total": 1,
      "avg_chars_per_line": 1.1
    },
    "audio": {
      "total_ms": 1
    },
    "runs": {
      "total": 1,
      "completed": 1,
      "failed": 1,
      "cancelled": 1,
      "running": 1,
      "pending": 1,
      "paused": 0
    },
    "activity": {
      "view": "daily",
      "bucket_unit": "day",
      "range_label": "string",
      "total": 1,
      "avg": 1.1,
      "buckets": [
        {
          "label": "string",
          "start": "2024-01-15T09:30:00Z",
          "end": "2024-01-15T09:30:00Z",
          "credits": 1,
          "characters": 1,
          "lines": 1,
          "runs": 1
        }
      ],
      "peak": {
        "value": 1,
        "label": "string",
        "start": "2024-01-15T09:30:00Z",
        "end": "2024-01-15T09:30:00Z"
      }
    },
    "corrected": {
      "total": 1
    },
    "daily": [
      {
        "date": "string",
        "credits": 1,
        "characters": 1,
        "lines": 1,
        "runs": 1
      }
    ]
  },
  "meta": {
    "request_id": "string",
    "timestamp": "2024-01-15T09:30:00Z"
  }
}
```

**SDK Code**

```python
import requests

url = "https://api.onepin.ai/api/v1/usage/summary"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.onepin.ai/api/v1/usage/summary';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.onepin.ai/api/v1/usage/summary"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.onepin.ai/api/v1/usage/summary")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.onepin.ai/api/v1/usage/summary")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.onepin.ai/api/v1/usage/summary', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.onepin.ai/api/v1/usage/summary");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.onepin.ai/api/v1/usage/summary")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```