curl --request GET \
--url https://app.reputably.net/api/entities/AiTrafficDaily/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.reputably.net/api/entities/AiTrafficDaily/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.reputably.net/api/entities/AiTrafficDaily/{id}', 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://app.reputably.net/api/entities/AiTrafficDaily/{id}",
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://app.reputably.net/api/entities/AiTrafficDaily/{id}"
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://app.reputably.net/api/entities/AiTrafficDaily/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.reputably.net/api/entities/AiTrafficDaily/{id}")
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{
"id": "<string>",
"site_id": "<string>",
"location_id": "<string>",
"date": "<string>",
"crawler_hits": 123,
"verified_hits": 123,
"spoofed_hits": 123,
"unique_agents": 123,
"by_agent": {},
"by_category": {},
"top_paths": "<array>",
"paths_by_category": {},
"referral_visits": 123,
"by_referrer": {},
"referral_paths": "<array>"
}Get one AI traffic daily rollup
Reads a single AI traffic daily rollup by id. Ids do not cross workspaces.
curl --request GET \
--url https://app.reputably.net/api/entities/AiTrafficDaily/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.reputably.net/api/entities/AiTrafficDaily/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.reputably.net/api/entities/AiTrafficDaily/{id}', 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://app.reputably.net/api/entities/AiTrafficDaily/{id}",
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://app.reputably.net/api/entities/AiTrafficDaily/{id}"
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://app.reputably.net/api/entities/AiTrafficDaily/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.reputably.net/api/entities/AiTrafficDaily/{id}")
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{
"id": "<string>",
"site_id": "<string>",
"location_id": "<string>",
"date": "<string>",
"crawler_hits": 123,
"verified_hits": 123,
"spoofed_hits": 123,
"unique_agents": 123,
"by_agent": {},
"by_category": {},
"top_paths": "<array>",
"paths_by_category": {},
"referral_visits": 123,
"by_referrer": {},
"referral_paths": "<array>"
}Authorizations
An agent key (rpk_...) created in Settings → API & MCP, sent as Authorization: Bearer rpk_.... Bearer only: a cookie session can never drive this API. An OAuth 2.1 access token obtained from the same host works identically and lands on the same ceiling.
Headers
Which workspace to read. Omit it and you get the account’s home workspace, which on an agency account is often not where the live businesses are. A workspace this credential cannot read is refused with 403 rather than quietly answered from the default.
Path Parameters
The AI traffic daily rollup id.
Response
The AI traffic daily rollup.
Unique id.
Denormalized from the site so the business-scope clamp (lib/businessScope.js) is a single-field query, same reason VisibilityRun carries it.
Hits whose source IP was inside the operator's published CIDR ranges (lib/aiCrawlerRanges.js). The IP itself is checked at ingest and discarded — it is never stored anywhere.
Hits where we HAD the operator's ranges and the source IP was not in them — i.e. something wearing the crawler's user-agent. Distinct from unchecked (no IP reported, or the operator publishes no ranges), which is crawler_hits - verified_hits - spoofed_hits.
{ 'GPTBot': { hits, verified, spoofed, category, operator }, ... } — only user-agents lib/aiCrawlers.js could identify. Unclassified traffic is dropped, never bucketed as 'other'.
{ ai_answers, search_index, training, other_ai } hit counts. ai_answers is the closest thing to an impression; training is high-volume and least actionable.
[{ path, hits }] capped at 25, descending. Capped because an unbounded path map on a large site is what would blow up the row size this schema exists to control.
{ ai_answers: [{ path, hits }], search_index: [...], ... } — each category independently capped at 12, so a low-volume category still shows its own pages instead of being crowded out. Per CATEGORY and not per agent on purpose: 11 bots x 25 paths would be ~275 extra entries a row, four buckets x 12 is ~48. Page data can therefore narrow to a category but never to a single crawler.
{ 'chatgpt.com': 8, ... } — humans who clicked through from an AI assistant. Only the browser beacon can see these.
[{ path, visits }] capped at 25, descending.