curl --request GET \
--url https://api.apsio.io/v1/projects/{projectId}/vitals \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.apsio.io/v1/projects/{projectId}/vitals"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.apsio.io/v1/projects/{projectId}/vitals', 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}/vitals",
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.apsio.io/v1/projects/{projectId}/vitals"
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.apsio.io/v1/projects/{projectId}/vitals")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apsio.io/v1/projects/{projectId}/vitals")
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{
"from": "2026-10-04T10:15:00.431000000Z",
"to": "2026-10-04T10:15:00.431000000Z",
"releases": [
{
"app_id": "<string>",
"release": "<string>",
"app_start": {
"cold": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
},
"warm": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
},
"hot": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
}
},
"screens": [
{
"screen": "<string>",
"ttid": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
},
"ttfd": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
}
}
],
"hangs": {
"sessions": 123,
"sessions_with_hang": 123,
"hang_rate": 123,
"sessions_with_anr": 123,
"anr_rate": 123
}
}
]
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}{
"error": {
"code": "invalid_request",
"message": "<string>"
}
}Vitals per release
App start (cold, warm, hot) and screen load (TTID, TTFD) percentiles, and hang and ANR session rates, per app and release, for the time range (default: the last 7 days, at most 30). The 20 releases with the most sessions.
curl --request GET \
--url https://api.apsio.io/v1/projects/{projectId}/vitals \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.apsio.io/v1/projects/{projectId}/vitals"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.apsio.io/v1/projects/{projectId}/vitals', 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}/vitals",
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.apsio.io/v1/projects/{projectId}/vitals"
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.apsio.io/v1/projects/{projectId}/vitals")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apsio.io/v1/projects/{projectId}/vitals")
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{
"from": "2026-10-04T10:15:00.431000000Z",
"to": "2026-10-04T10:15:00.431000000Z",
"releases": [
{
"app_id": "<string>",
"release": "<string>",
"app_start": {
"cold": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
},
"warm": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
},
"hot": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
}
},
"screens": [
{
"screen": "<string>",
"ttid": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
},
"ttfd": {
"count": 123,
"p50_ms": 123,
"p90_ms": 123,
"p95_ms": 123
}
}
],
"hangs": {
"sessions": 123,
"sessions_with_hang": 123,
"hang_rate": 123,
"sessions_with_anr": 123,
"anr_rate": 123
}
}
]
}{
"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"
Query Parameters
Start of the time range, inclusive (RFC 3339). Defaults to the range end minus the default length.
"2026-10-01T00:00:00Z"
End of the time range, exclusive (RFC 3339). Defaults to now.
"2026-10-08T00:00:00Z"
Only this app.
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$Only this release.
128Screens per release, the most loaded first; 0 to 50.
0 <= x <= 50Response
Vitals per app and release, the most sessions first.