curl --request POST \
--url https://api.apsio.io/v1/projects/{projectId}/explore/metrics \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"metric": "apsio.metrickit.time_to_first_draw",
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z",
"app_id": "<string>",
"filters": [],
"group_by": "<string>"
}
'import requests
url = "https://api.apsio.io/v1/projects/{projectId}/explore/metrics"
payload = {
"metric": "apsio.metrickit.time_to_first_draw",
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z",
"app_id": "<string>",
"filters": [],
"group_by": "<string>"
}
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({
metric: 'apsio.metrickit.time_to_first_draw',
from: '2023-11-07T05:31:56Z',
to: '2023-11-07T05:31:56Z',
app_id: '<string>',
filters: [],
group_by: '<string>'
})
};
fetch('https://api.apsio.io/v1/projects/{projectId}/explore/metrics', 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}/explore/metrics",
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([
'metric' => 'apsio.metrickit.time_to_first_draw',
'from' => '2023-11-07T05:31:56Z',
'to' => '2023-11-07T05:31:56Z',
'app_id' => '<string>',
'filters' => [
],
'group_by' => '<string>'
]),
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}/explore/metrics"
payload := strings.NewReader("{\n \"metric\": \"apsio.metrickit.time_to_first_draw\",\n \"from\": \"2023-11-07T05:31:56Z\",\n \"to\": \"2023-11-07T05:31:56Z\",\n \"app_id\": \"<string>\",\n \"filters\": [],\n \"group_by\": \"<string>\"\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}/explore/metrics")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"metric\": \"apsio.metrickit.time_to_first_draw\",\n \"from\": \"2023-11-07T05:31:56Z\",\n \"to\": \"2023-11-07T05:31:56Z\",\n \"app_id\": \"<string>\",\n \"filters\": [],\n \"group_by\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apsio.io/v1/projects/{projectId}/explore/metrics")
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 \"metric\": \"apsio.metrickit.time_to_first_draw\",\n \"from\": \"2023-11-07T05:31:56Z\",\n \"to\": \"2023-11-07T05:31:56Z\",\n \"app_id\": \"<string>\",\n \"filters\": [],\n \"group_by\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"from": "2026-10-04T10:15:00.431000000Z",
"to": "2026-10-04T10:15:00.431000000Z",
"bucket_seconds": 123,
"retention_days": 123,
"metric": "<string>",
"kind": "sum",
"aggregation": "count",
"unit": "<string>",
"group_by": "<string>",
"series": [
{
"group": "<string>",
"other": true,
"points": [
{
"t": "2026-10-04T10:15:00.431000000Z",
"value": 123
}
]
}
],
"sql": "<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>"
}
}Aggregate a metric over time
One metric of the project per bucket (at most 120), aggregated, optionally split by one field into its 10 largest groups and the rest. Sums are read as delta points (cumulative sums are left out), as are histograms, whose percentiles come from their merged buckets. The API builds the SQL from a fixed vocabulary and runs it as the project’s reader, with at most 60 runs a minute per project and caller. sql shows it with its values, for reading only.
curl --request POST \
--url https://api.apsio.io/v1/projects/{projectId}/explore/metrics \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"metric": "apsio.metrickit.time_to_first_draw",
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z",
"app_id": "<string>",
"filters": [],
"group_by": "<string>"
}
'import requests
url = "https://api.apsio.io/v1/projects/{projectId}/explore/metrics"
payload = {
"metric": "apsio.metrickit.time_to_first_draw",
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z",
"app_id": "<string>",
"filters": [],
"group_by": "<string>"
}
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({
metric: 'apsio.metrickit.time_to_first_draw',
from: '2023-11-07T05:31:56Z',
to: '2023-11-07T05:31:56Z',
app_id: '<string>',
filters: [],
group_by: '<string>'
})
};
fetch('https://api.apsio.io/v1/projects/{projectId}/explore/metrics', 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}/explore/metrics",
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([
'metric' => 'apsio.metrickit.time_to_first_draw',
'from' => '2023-11-07T05:31:56Z',
'to' => '2023-11-07T05:31:56Z',
'app_id' => '<string>',
'filters' => [
],
'group_by' => '<string>'
]),
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}/explore/metrics"
payload := strings.NewReader("{\n \"metric\": \"apsio.metrickit.time_to_first_draw\",\n \"from\": \"2023-11-07T05:31:56Z\",\n \"to\": \"2023-11-07T05:31:56Z\",\n \"app_id\": \"<string>\",\n \"filters\": [],\n \"group_by\": \"<string>\"\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}/explore/metrics")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"metric\": \"apsio.metrickit.time_to_first_draw\",\n \"from\": \"2023-11-07T05:31:56Z\",\n \"to\": \"2023-11-07T05:31:56Z\",\n \"app_id\": \"<string>\",\n \"filters\": [],\n \"group_by\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apsio.io/v1/projects/{projectId}/explore/metrics")
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 \"metric\": \"apsio.metrickit.time_to_first_draw\",\n \"from\": \"2023-11-07T05:31:56Z\",\n \"to\": \"2023-11-07T05:31:56Z\",\n \"app_id\": \"<string>\",\n \"filters\": [],\n \"group_by\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"from": "2026-10-04T10:15:00.431000000Z",
"to": "2026-10-04T10:15:00.431000000Z",
"bucket_seconds": 123,
"retention_days": 123,
"metric": "<string>",
"kind": "sum",
"aggregation": "count",
"unit": "<string>",
"group_by": "<string>",
"series": [
{
"group": "<string>",
"other": true,
"points": [
{
"t": "2026-10-04T10:15:00.431000000Z",
"value": 123
}
]
}
],
"sql": "<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"
Body
The metric's name, as the catalog lists it.
^[A-Za-z0-9_.:/-]{1,255}$"apsio.metrickit.time_to_first_draw"
sum and gauge points are in metric_values, histograms in metric_histograms.
sum, gauge, histogram Per bucket: count (points, or a histogram's observations), rate (a sum's total or a histogram's observations per minute), sum, avg, min, max, or a percentile. A gauge takes count, avg, min, max and percentiles.
count, rate, sum, avg, min, max, p50, p90, p95, p99 Start, inclusive (RFC 3339). Defaults to 24 hours before to.
End, exclusive (RFC 3339). Defaults to now.
Only this app of the project.
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$20Show child attributes
Show child attributes
One field (service.version, os.name, os.version, device.model.identifier, country, ...), any point attribute by its key, or a resource attribute as resource.: the 10 groups with the most points, and the rest as one series.
^[A-Za-z0-9_.:/-]{1,128}$Response
The series.
RFC 3339 time in UTC with up to nanosecond precision.
"2026-10-04T10:15:00.431000000Z"
RFC 3339 time in UTC with up to nanosecond precision.
"2026-10-04T10:15:00.431000000Z"
Days of detail the project's plan keeps (D94); nothing older is read.
sum, gauge, histogram count, rate, sum, avg, min, max, p50, p90, p95, p99 The metric's unit (UCUM, as the app reports it). Written by the app: untrusted data.
Every bucket of the range in each series, the largest group first.
Show child attributes
Show child attributes
The query with its values, for reading. Not run as written.