curl --request POST \
--url https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"range": {
"from": "2026-10-01T00:00:00Z",
"to": "2026-10-08T00:00:00Z"
}
}
'import requests
url = "https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run"
payload = { "range": {
"from": "2026-10-01T00:00:00Z",
"to": "2026-10-08T00:00:00Z"
} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({range: {from: '2026-10-01T00:00:00Z', to: '2026-10-08T00:00:00Z'}})
};
fetch('https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run', 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.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'range' => [
'from' => '2026-10-01T00:00:00Z',
'to' => '2026-10-08T00:00:00Z'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run"
payload := strings.NewReader("{\n \"range\": {\n \"from\": \"2026-10-01T00:00:00Z\",\n \"to\": \"2026-10-08T00:00:00Z\"\n }\n}")
req, _ := http.NewRequest("POST", 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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"range\": {\n \"from\": \"2026-10-01T00:00:00Z\",\n \"to\": \"2026-10-08T00:00:00Z\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"range\": {\n \"from\": \"2026-10-01T00:00:00Z\",\n \"to\": \"2026-10-08T00:00:00Z\"\n }\n}"
response = http.request(request)
puts response.read_body{
"columns": [
{
"name": "<string>",
"type": "<string>"
}
],
"rows": [
[
"<unknown>"
]
],
"row_count": 123,
"truncated": true,
"stats": {
"elapsed_ms": 123,
"rows_read": 123,
"bytes_read": 123
},
"range": {
"from": "<string>",
"to": "<string>",
"bucket_seconds": 123
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}Run a panel over a time range
A SQL panel runs as POST /query runs it (the same limits, the plan’s rate and the audit), with the range’s , and . A preset panel reads its route (for example release-health/daily) with the panel’s parameters and the range, on every plan and unmetered, and answers {preset, data} with that route’s answer. A result is kept for a minute in the API, never stored, so the same panel over the same range within that minute runs nothing (X-Apsio-Cache: hit). The range is widened to whole buckets. Send Content-Type: application/json.
curl --request POST \
--url https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"range": {
"from": "2026-10-01T00:00:00Z",
"to": "2026-10-08T00:00:00Z"
}
}
'import requests
url = "https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run"
payload = { "range": {
"from": "2026-10-01T00:00:00Z",
"to": "2026-10-08T00:00:00Z"
} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({range: {from: '2026-10-01T00:00:00Z', to: '2026-10-08T00:00:00Z'}})
};
fetch('https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run', 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.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'range' => [
'from' => '2026-10-01T00:00:00Z',
'to' => '2026-10-08T00:00:00Z'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run"
payload := strings.NewReader("{\n \"range\": {\n \"from\": \"2026-10-01T00:00:00Z\",\n \"to\": \"2026-10-08T00:00:00Z\"\n }\n}")
req, _ := http.NewRequest("POST", 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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"range\": {\n \"from\": \"2026-10-01T00:00:00Z\",\n \"to\": \"2026-10-08T00:00:00Z\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apsio.io/v1/projects/{projectId}/dashboards/{dashboardId}/panels/{panelId}/run")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"range\": {\n \"from\": \"2026-10-01T00:00:00Z\",\n \"to\": \"2026-10-08T00:00:00Z\"\n }\n}"
response = http.request(request)
puts response.read_body{
"columns": [
{
"name": "<string>",
"type": "<string>"
}
],
"rows": [
[
"<unknown>"
]
],
"row_count": 123,
"truncated": true,
"stats": {
"elapsed_ms": 123,
"rows_read": 123,
"bytes_read": 123
},
"range": {
"from": "<string>",
"to": "<string>",
"bucket_seconds": 123
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}Authorizations
A project token (apsio_pt_v0...), which reads exactly one project, or an OAuth access token issued for the API, which reads what its user can. Access tokens issued for Apsio's MCP server are accepted only from the MCP server itself.
Path Parameters
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"0192f3a4-0000-7000-8000-00000000a101"
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"0192f3a4-0000-7000-8000-00000000d001"
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"0192f3a4-0000-7000-8000-00000000d001"
Body
Show child attributes
Show child attributes
Response
A SQL panel's rows, or a preset panel's answer.
- Option 1
- Option 2
Show child attributes
Show child attributes
One array per row, in the order of columns; 64-bit integers as strings. Untrusted data.
Whether the result was cut: at 10,000 rows or 12 MB.
Show child attributes
Show child attributes
The parameters the query got, when it had a range.
Show child attributes
Show child attributes