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

# Get Run Outputs

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

Fetch one logical output per sink node in a workflow run.

Every sink from the run's definition snapshot is returned in graph order,
including incomplete sinks with empty lines. Completed iterations are
unioned per sink with the latest completed value winning for duplicate
`line_id` values. Status reflects the latest attempt, so earlier completed
lines remain visible when a later attempt fails. Audio playback URLs are
short-lived and hydrated only on copied result lines.

Each sink's union is capped server-side; `truncated: true` on an output
signals that its `lines` are an incomplete prefix of the logical result.

Reference: https://onepin.ai/docs/reference/api-reference/workflows/get-run-outputs-api-v-1-workflows-workflow-id-runs-run-id-outputs-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)
- `run_id` (string, required)

### Headers

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

## Response

### 200

Successful Response

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

## Errors

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### WorkflowRunOutputsOut

- `run_id` (string, required)
- `run_status` (string, required)
- `credits` (integer, required, nullable) — Credits debited from the user's spendable balance for this run. Excludes separately invoiced overage; null until a final billed value is available.
- `outputs` (list of WorkflowRunSinkOutputOut, required)
- `credits_absorbed` (double, optional, default: 0) — Credits discounted by floor-rounding for this run. This is the positive sub-credit remainder above the charged floor and excludes any minimum charge adjustment; charged credits plus this value reconstructs true cost only for fully covered, uncapped runs that were not lifted by the minimum charge. Returns 0 for unsettled or legacy runs.

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

### WorkflowRunSinkOutputOut

- `node_id` (string, required)
- `node_type` (string, required)
- `display_name` (string, required)
- `status` (string, required)
- `lines` (list of WorkflowRunSinkOutputLine, required)
- `line_count` (integer, required)
- `truncated` (boolean, required)

### ValidationErrorLocItems

### ValidationErrorCtx

### WorkflowRunSinkOutputLine

- `audio_files` (list of map from string to any, optional)
- `recommended_audio_file_index` (integer, optional)
- `delivery` (WorkflowRunSinkOutputDelivery, optional)

### WorkflowRunSinkOutputDelivery

- `passed` (boolean, required)
- `failing_checks` (list of WorkflowRunSinkOutputDeliveryCheck, required)

### WorkflowRunSinkOutputDeliveryCheck

- `kind` (string, required)
- `label` (string, required)
- `score` (double, required, nullable)
- `threshold` (double, required, nullable)

## Examples

**Request**

```json
{}
```

**Response**

```json
{
  "data": {
    "run_id": "a3f8c2d1-7b4e-4f9a-8c6d-2e1f0b3a5c7d",
    "run_status": "completed",
    "credits": 42,
    "outputs": [
      {
        "node_id": "sink_node_01",
        "node_type": "audio_sink",
        "display_name": "Final Audio Output",
        "status": "completed",
        "lines": [
          {
            "audio_files": [
              {}
            ],
            "recommended_audio_file_index": 0,
            "delivery": {
              "passed": true,
              "failing_checks": [
                {
                  "kind": "quality_score",
                  "label": "Minimum Audio Quality",
                  "score": 0.87,
                  "threshold": 0.75
                }
              ]
            }
          }
        ],
        "line_count": 1,
        "truncated": false
      }
    ],
    "credits_absorbed": 0.37
  },
  "meta": {
    "request_id": "req_9f2e4b1c-3d7a-4e8f-b5c2-1a0d6e9f3b2c",
    "timestamp": "2024-03-15T10:45:22Z"
  }
}
```

**SDK Code**

```python
import requests

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

payload = {}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript
const url = 'https://api.onepin.ai/api/v1/workflows/workflow_id/runs/run_id/outputs';
const options = {
  method: 'GET',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{}'
};

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"
	"strings"
	"net/http"
	"io"
)

func main() {

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

	payload := strings.NewReader("{}")

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

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	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/run_id/outputs")

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

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"

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/run_id/outputs")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{}")
  .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/run_id/outputs', [
  'body' => '{}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://api.onepin.ai/api/v1/workflows/workflow_id/runs/run_id/outputs");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.onepin.ai/api/v1/workflows/workflow_id/runs/run_id/outputs")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

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()
```