List Time Series Metrics
curl --request GET \
--url https://api.whop.com/api/v1/stats/time_series \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.whop.com/api/v1/stats/time_series"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.whop.com/api/v1/stats/time_series', 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.whop.com/api/v1/stats/time_series",
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.whop.com/api/v1/stats/time_series"
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.whop.com/api/v1/stats/time_series")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.whop.com/api/v1/stats/time_series")
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{
"data": [
{
"description": "Ad platform delivery over time (spend, impressions, clicks) on the unified source language: source scopes by a whop:<campaign>:<group>:<ad> path, exact or with a trailing :* prefix (whop alone or no source = the whole account), and group_by=source groups one path segment deeper than the filter prefix. Only whop:* paths report delivery today; other roots return nothing. breakdown_by=metric returns each delivery measure per bucket plus whole-window data.totals. breakdown_by can instead split delivery by a dimension — age, gender, age_gender, placement, publisher_platform, country, region, device_platform, or impression_device — with the metric parameter picking the measure (spend, impressions, or clicks; defaults to spend). On the placement and publisher_platform dimensions the metric parameter also accepts results, roas, and cost_per_result: conversion-side measures attributed from your own tracked events rather than reported by the ad platform, with results counting conversions that match each ad group's conversion event. Dimension entries don't sum exactly to the totals (the ad platform withholds tiny cells) and are grouped by the ad account's calendar day — they can't re-bucket into time_zone. Spend converts to convert_to (defaults to usd). Whole-account attribution numbers live in the events and people metrics.",
"key": "ad_xxxxxxxxxxxxxx",
"name": "Ad delivery",
"properties": [
"source"
],
"unit": "currency",
"breakdowns": [
"<string>"
],
"windows": [
"7d"
]
}
]
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}Time Series
List Time Series Metrics
Lists the metrics you can chart over time, with the unit each reports and the properties you can filter or break it down by. Aggregates that are not bucketed over time are reports, listed at GET /stats/reports.
GET
/
stats
/
time_series
List Time Series Metrics
curl --request GET \
--url https://api.whop.com/api/v1/stats/time_series \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.whop.com/api/v1/stats/time_series"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.whop.com/api/v1/stats/time_series', 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.whop.com/api/v1/stats/time_series",
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.whop.com/api/v1/stats/time_series"
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.whop.com/api/v1/stats/time_series")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.whop.com/api/v1/stats/time_series")
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{
"data": [
{
"description": "Ad platform delivery over time (spend, impressions, clicks) on the unified source language: source scopes by a whop:<campaign>:<group>:<ad> path, exact or with a trailing :* prefix (whop alone or no source = the whole account), and group_by=source groups one path segment deeper than the filter prefix. Only whop:* paths report delivery today; other roots return nothing. breakdown_by=metric returns each delivery measure per bucket plus whole-window data.totals. breakdown_by can instead split delivery by a dimension — age, gender, age_gender, placement, publisher_platform, country, region, device_platform, or impression_device — with the metric parameter picking the measure (spend, impressions, or clicks; defaults to spend). On the placement and publisher_platform dimensions the metric parameter also accepts results, roas, and cost_per_result: conversion-side measures attributed from your own tracked events rather than reported by the ad platform, with results counting conversions that match each ad group's conversion event. Dimension entries don't sum exactly to the totals (the ad platform withholds tiny cells) and are grouped by the ad account's calendar day — they can't re-bucket into time_zone. Spend converts to convert_to (defaults to usd). Whole-account attribution numbers live in the events and people metrics.",
"key": "ad_xxxxxxxxxxxxxx",
"name": "Ad delivery",
"properties": [
"source"
],
"unit": "currency",
"breakdowns": [
"<string>"
],
"windows": [
"7d"
]
}
]
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}Authorizations
An Account API key, an App API key, an account access token, an account-scoped user token, or a user OAuth token. Prepend the key or token with Bearer, for example Bearer ***************************. See Auth & API keys for how to get each one.
Headers
Pins the request to a dated API version.
Example:
"2026-10-06-1"
Response
metric catalog
The available metrics.
Show child attributes
Show child attributes

