curl --request GET \
--url https://api.duvo.ai/v2/organizations/{orgId}/runs \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.duvo.ai/v2/organizations/{orgId}/runs"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.duvo.ai/v2/organizations/{orgId}/runs', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.duvo.ai/v2/organizations/{orgId}/runs",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.duvo.ai/v2/organizations/{orgId}/runs"
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(string(body))
}HttpResponse<String> response = Unirest.get("https://api.duvo.ai/v2/organizations/{orgId}/runs")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.duvo.ai/v2/organizations/{orgId}/runs")
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{
"runs": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "<string>",
"source": "<string>",
"team_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"team_name": "<string>",
"agent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent_name": "<string>",
"build_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"automation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"automation_name": "<string>",
"user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "<string>",
"updated_at": "<string>",
"started_at": "<string>",
"completed_at": "<string>"
}
],
"total": 123,
"limit": 123,
"has_more": true,
"next_cursor": "<string>",
"created_after": "<string>",
"default_window_applied": true
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}List Org Runs
List runs across every team in an organization, filtered by status, agent, team, source, evaluation issues and time. Intended for external monitoring: one call covers the whole org instead of one per team. Requires an organization Admin, Executive, or Owner role, and an API key scoped to all teams you can access — a key pinned to a single team is rejected, because this endpoint spans every team in the organization.
curl --request GET \
--url https://api.duvo.ai/v2/organizations/{orgId}/runs \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.duvo.ai/v2/organizations/{orgId}/runs"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.duvo.ai/v2/organizations/{orgId}/runs', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.duvo.ai/v2/organizations/{orgId}/runs",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.duvo.ai/v2/organizations/{orgId}/runs"
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(string(body))
}HttpResponse<String> response = Unirest.get("https://api.duvo.ai/v2/organizations/{orgId}/runs")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.duvo.ai/v2/organizations/{orgId}/runs")
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{
"runs": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "<string>",
"source": "<string>",
"team_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"team_name": "<string>",
"agent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent_name": "<string>",
"build_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"automation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"automation_name": "<string>",
"user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "<string>",
"updated_at": "<string>",
"started_at": "<string>",
"completed_at": "<string>"
}
],
"total": 123,
"limit": 123,
"has_more": true,
"next_cursor": "<string>",
"created_after": "<string>",
"default_window_applied": true
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}Authorizations
API key authentication. Get your API key from the Duvo dashboard.
Path Parameters
The organization's unique identifier
Query Parameters
Number of runs per page (1-500, default 20). The cap is higher than the team runs endpoint's because this route serves bulk export: at 100 requests a minute per key, page size is what bounds how fast a month of runs can be pulled.
1 <= x <= 500Resume after the run a previous page ended on: pass the next_cursor that page returned, with the same filters and sort_order. Runs created or resolved in between cannot shift a boundary you have already passed, so a sweep sees every run exactly once, and a sweep that started under the default 7-day window keeps that window on every page. This list has no offset parameter: skipping rows costs the database every skipped row, and a run created between two requests shifts every later offset by one, so an offset sweep can repeat or miss a run. 400 when the value is not a cursor this endpoint issued.
1Sort direction on created_at (default desc)
asc, desc Filter to runs with this status. needs_attention is the monitoring status: runs that are waiting on a human or failed, plus runs whose latest evaluation flagged a critical issue — a run can finish as completed and still have accomplished nothing.
not_started, pending, starting, running, waiting, completed, failed, interrupted, stopped, needs_attention Filter to runs on this team
Filter to runs for this agent
Filter to runs created from this source (e.g. api, scheduling)
Filter on the run's latest successful evaluation: true returns only runs it flagged, false only runs it did not. Only the latest evaluation counts — an older flag does not match — and a run whose latest evaluation errored, or that has none, counts as unflagged. Omit to return both.
true, false Only runs whose latest successful evaluation has at least one failing rubric at this severity (critical | medium | low). Implies has_issues.
critical, medium, low Return runs created at or after this ISO-8601 timestamp. Every run has a creation time, so this is the window that returns all runs in a period whatever state they reached — unlike the started and completed windows below, which exclude runs that never started and runs still in flight respectively. When the request carries no lower time bound (created_after, started_after, completed_after or since), this defaults to 7 days ago and default_window_applied is true in the response: an organization's run history is unbounded, and a monitor wants what is recent. An upper bound alone keeps the default floor. Pass any lower bound to replace it.
Return runs created before this ISO-8601 timestamp (exclusive). Pair with created_after for a period. A closed creation window is also the stable one to paginate: results are ordered by creation time, so runs arriving mid-sweep cannot shift a closed window's pages.
Return runs that started at or after this ISO-8601 timestamp. Runs that never started are excluded. Pair with started_before to bound a stuck-run query to a window — without a lower bound, status=running also counts every run left running months ago.
Return runs that started before this ISO-8601 timestamp. Combine with status=running to find stuck runs — since/until filter on completion, so they never match a run that is still going.
Return runs completed at or after this ISO-8601 timestamp. Runs that have not completed are excluded, including every stuck one — reach for started_after/started_before to bound those. Alias of since; pass one or the other, not both.
Return runs completed before this ISO-8601 timestamp (exclusive). Runs that have not completed are excluded. Alias of until; pass one or the other, not both.
Alias of completed_after, kept because it is the name the public team runs endpoint ships. Prefer completed_after: this endpoint carries a creation and a start window too, and only the column-named pair says which one this is.
Alias of completed_before, kept because it is the name the public team runs endpoint ships. Prefer completed_before.
Skip row selection and enrichment. The normal list response shape is returned with an empty row array and the matching total.
true, false Return total, the count of every matching run ignoring pagination. Off by default: counting walks every match where the page stops at limit, so on a large organization it costs orders of magnitude more than the rows themselves. Ask for it when you are driving a pager, not when you are polling. Implied by count_only.
true, false Response
Default Response
Show child attributes
Show child attributes
Total runs matching the filters, ignoring pagination. Null unless include_total=true or count_only=true — null means not requested, distinct from a count of 0.
The limit that was applied
Whether another page exists past this one, determined by looking one row ahead rather than inferred from a full page. False on a count_only response.
Pass as cursor (same filters, same sort_order) to fetch the next page. Null when has_more is false. Exact continuation from the last run on this page, unaffected by runs created or resolved in the meantime.
The creation lower bound the query ran with, as ISO 8601: the caller's created_after, or 7 days ago when the request carried no time bound at all. Null when the caller bounded the query on another timestamp only.
True when the request carried no time bound and the 7-day creation window was applied for it. A caller that meant "everything" should pass an explicit created_after.
Was this page helpful?