> 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.

# Runs Summary

GET https://api.onepin.ai/api/v1/workflows/{workflow_id}/runs/summary

Aggregate run statistics for a workflow over an optional date window.

Returns per-status counts (`completed`, `failed`, `cancelled`, `pending`,
`running`, `paused`) plus three derived metrics:

- `pass_rate`: `completed / (completed + failed)`. Cancelled runs are
  user-aborted, not quality failures, so they are excluded. `null` when
  there are no non-cancelled terminal runs in the window.
- `delivered_audio_ms`: total delivered-take audio in milliseconds, summed
  over completed runs.
- `average_duration_seconds`: mean *active* duration — `completed_at -
  started_at` minus paused time — over successfully completed runs only.
  `null` when no runs have completed.

**Date range:** `from` / `to` filter by `created_at`. Both must be ISO 8601
with a UTC offset; a naive datetime returns 422. An inverted range
(`from > to`) also returns 422. Omit both to aggregate over all runs.

Use `GET /runs` with `?status=` filters for individual run details; this
endpoint is best for dashboard-style health metrics.

Reference: https://onepin.ai/docs/reference/api-reference/workflows/runs-summary-api-v-1-workflows-workflow-id-runs-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

### Path parameters

- `workflow_id` (string, required)

### Query parameters

- `from` (datetime, optional, nullable) — Filter runs by created_at >= this ISO datetime (ISO 8601 with UTC offset required).
- `to` (datetime, optional, nullable) — Filter runs by created\_at \<= this ISO datetime (ISO 8601 with UTC offset required).

### Headers

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

## Response

### 200

Successful Response

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

## Errors

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### RunsSummaryOut

- `total_runs` (integer, required) — Total runs in the queried window.
- `completed` (integer, required) — Runs that finished successfully.
- `failed` (integer, required) — Runs that ended in a failure state.
- `cancelled` (integer, required) — Runs explicitly cancelled by a user.
- `pending` (integer, required) — Runs queued but not yet started.
- `running` (integer, required) — Runs currently executing.
- `paused` (integer, required) — Runs paused at a wave boundary.
- `pass_rate` (double, required, nullable) — Fraction of non-cancelled terminal runs that completed successfully: `completed / (completed + failed)`. Cancelled runs are user-aborted, not quality failures, so they are excluded. Null when there are no non-cancelled terminal runs.
- `delivered_audio_ms` (integer, required) — Delivered-take audio in milliseconds, summed over completed runs only, within the queried window. Intentionally narrower than the workspace usage 'Audio' total (which counts all terminal runs, including cancelled), so the two are not expected to reconcile. Runs that completed before this figure was stamped (v0.41.105, 2026-08-07) have no stored value and count as 0.
- `average_duration_seconds` (double, required, nullable) — Mean active duration in seconds over completed runs only (`completed_at - started_at` minus paused time). Null when no runs have completed.

### 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)

### ValidationErrorLocItems

### ValidationErrorCtx

## Examples

**Response**

```json
{
  "data": {
    "total_runs": 1,
    "completed": 1,
    "failed": 1,
    "cancelled": 1,
    "pending": 1,
    "running": 1,
    "paused": 1,
    "pass_rate": 1.1,
    "delivered_audio_ms": 1,
    "average_duration_seconds": 1.1
  },
  "meta": {
    "request_id": "string",
    "timestamp": "2024-01-15T09:30:00Z"
  }
}
```

**SDK Code**

```python
import requests

url = "https://api.onepin.ai/api/v1/workflows/workflow_id/runs/summary"

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

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

print(response.json())
```

```javascript
const url = 'https://api.onepin.ai/api/v1/workflows/workflow_id/runs/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/workflows/workflow_id/runs/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/workflows/workflow_id/runs/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/workflows/workflow_id/runs/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/workflows/workflow_id/runs/summary', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://api.onepin.ai/api/v1/workflows/workflow_id/runs/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/workflows/workflow_id/runs/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()
```