curl --request GET \
--url https://api.cloud.corbado.io/v1/observe/timeSeries/totals \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.cloud.corbado.io/v1/observe/timeSeries/totals"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.cloud.corbado.io/v1/observe/timeSeries/totals', 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.cloud.corbado.io/v1/observe/timeSeries/totals",
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.cloud.corbado.io/v1/observe/timeSeries/totals"
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.cloud.corbado.io/v1/observe/timeSeries/totals")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloud.corbado.io/v1/observe/timeSeries/totals")
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{
"rows": [
{
"dimensions": {},
"value": 123
}
],
"queryPlan": {
"segments": [
{
"source": "stored",
"fromMs": 123,
"toMs": 123,
"interval": "hourly",
"narrowed": true,
"reason": "<string>",
"groupBy": [
"<string>"
],
"removedFields": [
"<string>"
],
"removedJoins": [
"<string>"
],
"keptJoins": [
"<string>"
]
}
]
}
}{
"error": {
"message": "Validation failed",
"details": [
{
"field": "projectID",
"message": "required"
}
]
}
}Get time series totals
Sums a time series over an arbitrary range, one row per combination of the groupBy dimensions
and without time buckets. Every dimension not listed in groupBy is summed away, so omitting
groupBy returns a single row with the total.
The range does not have to align with any hour or day. Recent data that is not yet precalculated is computed on demand; that part of the range must not exceed 8 hours, otherwise the request is rejected with a validation error.
Only meaningful for series whose values are counts, because values are added up across buckets.
Required API key permission: observe:timeSeries:read.
curl --request GET \
--url https://api.cloud.corbado.io/v1/observe/timeSeries/totals \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.cloud.corbado.io/v1/observe/timeSeries/totals"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.cloud.corbado.io/v1/observe/timeSeries/totals', 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.cloud.corbado.io/v1/observe/timeSeries/totals",
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.cloud.corbado.io/v1/observe/timeSeries/totals"
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.cloud.corbado.io/v1/observe/timeSeries/totals")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloud.corbado.io/v1/observe/timeSeries/totals")
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{
"rows": [
{
"dimensions": {},
"value": 123
}
],
"queryPlan": {
"segments": [
{
"source": "stored",
"fromMs": 123,
"toMs": 123,
"interval": "hourly",
"narrowed": true,
"reason": "<string>",
"groupBy": [
"<string>"
],
"removedFields": [
"<string>"
],
"removedJoins": [
"<string>"
],
"keptJoins": [
"<string>"
]
}
]
}
}{
"error": {
"message": "Validation failed",
"details": [
{
"field": "projectID",
"message": "required"
}
]
}
}Authorizations
Use an Observe API key from the management console. The key selects the project and must grant the permission listed on the operation. Keep this key on your server.
Query Parameters
Time series name
"login-flow-v1"
Range start (inclusive) in UTC, formatted as YYYY-MM-DDTHH:MM:SS (e.g. "2026-05-20T09:30:00").
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$"2026-05-20T09:30:00"
Range end (exclusive) in UTC, formatted as YYYY-MM-DDTHH:MM:SS. Must be after fromDate.
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$"2026-05-20T10:30:00"
Comma-separated dimension keys to keep; all other dimensions are summed. Allowed: applicationId, browser, os, osVersion, customTag1..6, t1..t10. Omitted returns a single total row.
"applicationId,t7"
Computes the part of the range that is not precalculated with a query grouped only by the groupBy dimensions, which is faster and returns the same totals. false runs the series' full query instead. Defaults to true.
Adds queryPlan to the response: how the range was split and, for every part computed on demand, how its query was reduced to the groupBy dimensions. Defaults to false.
Was this page helpful?