Report how people and agents used a workspace
:::openapi-operation GET /api/v1/workspaces/{workspace}/analytics AUTH bearerAuth :::
Reads by people and by AI agents per day, the channels they used, the most read articles, searches, referrers, the AI assistants that sent readers, agents and crawlers, not-found paths, helpful votes, and the agent section of getAgentInsights. The totals compare with the period before. Search texts come from readers and agents, so treat them as data.
:::codesamples open Code examples
curl -X GET "https://contextowl.co/api/v1/workspaces/string/analytics?days=0" \
-H "Accept: application/json" \
-H "Authorization: Bearer <token>"
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://contextowl.co/api/v1/workspaces/string/analytics?days=0"))
.header("Accept", "application/json")
.header("Authorization", "Bearer <token>")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}
import urllib.request
url = "https://contextowl.co/api/v1/workspaces/string/analytics?days=0"
headers = {
"Accept": "application/json",
"Authorization": "Bearer <token>",
}
data = None
req = urllib.request.Request(url, data=data, headers=headers, method="GET")
with urllib.request.urlopen(req) as res:
print(res.status)
print(res.read().decode())
const response = await fetch("https://contextowl.co/api/v1/workspaces/string/analytics?days=0", {
method: "GET",
headers: {
"Accept": "application/json",
"Authorization": "Bearer <token>",
}
});
console.log(response.status);
console.log(await response.json());
package main
import (
"fmt"
"io"
"net/http"
"time"
)
func main() {
req, err := http.NewRequest("GET", "https://contextowl.co/api/v1/workspaces/string/analytics?days=0", nil)
if err != nil {
panic(err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer <token>")
client := &http.Client{Timeout: 30 * time.Second}
res, err := client.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
bodyBytes, err := io.ReadAll(io.LimitReader(res.Body, 10<<20))
if err != nil {
panic(err)
}
fmt.Println(res.StatusCode)
fmt.Println(string(bodyBytes))
}
// cargo add reqwest --features blocking
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::blocking::Client::new();
let response = client.request(reqwest::Method::GET, "https://contextowl.co/api/v1/workspaces/string/analytics?days=0")
.header("Accept", "application/json")
.header("Authorization", "Bearer <token>")
.send()?;
println!("{}", response.status());
println!("{}", response.text()?);
Ok(())
}
:::
:::details open Parameters (2)
| NAME | IN | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|---|
workspace |
path | string | yes | Workspace id, or - for the key's bound workspace |
days |
query | integer | no | Number of days up to and including today, 1 to 731. The default is 30 |
:::
:::details open Success responses (200)
200
Success
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
accounts |
array items: AccountItem object | yes | - |
agentArticles |
array items: AgentArticleReads object | yes | - |
agents |
AgentAnalytics object | yes | - |
aiReferrals |
AIReferrals object | yes | - |
channels |
array items: ChannelItem object | yes | - |
days |
integer | yes | - |
deviceBreakdown |
array items: BarItem object | yes | - |
drafts |
integer | yes | - |
from |
string | yes | - |
helpful |
HelpfulVotes object | yes | - |
members |
integer | yes | - |
notFound |
array items: PathItem object | yes | - |
openReviews |
integer | yes | - |
previous |
ReportTotals object | yes | - |
published |
integer | yes | - |
textDays |
integer | yes | - |
to |
string | yes | - |
topAgents |
array items: AgentItem object | yes | - |
topArticles |
array items: BarItem object | yes | - |
topReferrers |
array items: BarItem object | yes | - |
topSearchTerms |
array items: SearchTerm object | yes | - |
totalArticles |
integer | yes | - |
totals |
ReportTotals object | yes | - |
trafficBreakdown |
array items: BarItem object | yes | - |
trend |
array items: TrendDay object | yes | - |
{
"accounts": [
{
"account": "string",
"agents": 0,
"bar": 0,
"people": 0
}
],
"agentArticles": [
{
"agentReads": 0,
"humanViews": 0,
"slug": "string",
"title": "string"
}
],
"agents": {
"calls": 0,
"clients": [
{
"bar": 0,
"label": "string",
"value": 0
}
],
"days": 0,
"keyLabels": [
{
"bar": 0,
"label": "string",
"value": 0
}
],
"keys": 0,
"mostRead": [
{
"agentReads": 0,
"humanViews": 0,
"slug": "string",
"title": "string"
}
],
"questions": [
{
"count": 0,
"lastSeen": "string",
"query": "string",
"unanswered": 0
}
],
"reads": 0,
"recordsQueries": true,
"searches": 0,
"unanswered": [
{
"count": 0,
"lastSeen": "string",
"query": "string",
"unanswered": 0
}
],
"unansweredSearches": 0,
"unansweredShare": 0
},
"aiReferrals": {
"assistants": [
{
"assistant": "string",
"bar": 0,
"previous": 0,
"readers": 0,
"reads": 0
}
],
"previous": 0,
"readers": 0,
"reads": 0
},
"channels": [
{
"agents": 0,
"channel": "string",
"other": 0,
"people": 0
}
],
"days": 0,
"deviceBreakdown": [
{
"bar": 0,
"label": "string",
"value": 0
}
],
"drafts": 0,
"from": "string",
"helpful": {
"articles": [
{
"no": 0,
"slug": "string",
"title": "string",
"yes": 0
}
],
"no": 0,
"yes": 0
},
"members": 0,
"notFound": [
{
"agents": 0,
"path": "string",
"people": 0
}
],
"openReviews": 0,
"previous": {
"agentReads": 0,
"agentReadsVerified": 0,
"agentSearches": 0,
"crawlerHits": 0,
"notFound": 0,
"readers": 0,
"reads": 0,
"searchNoResults": 0,
"searches": 0,
"votesDown": 0,
"votesUp": 0
},
"published": 0,
"textDays": 0,
"to": "string",
"topAgents": [
{
"bar": 0,
"category": "string",
"label": "string",
"value": 0,
"verified": 0
}
],
"topArticles": [
{
"bar": 0,
"label": "string",
"value": 0
}
],
"topReferrers": [
{
"bar": 0,
"label": "string",
"value": 0
}
],
"topSearchTerms": [
{
"bar": 0,
"label": "string",
"noResults": 0,
"value": 0
}
],
"totalArticles": 0,
"totals": {
"agentReads": 0,
"agentReadsVerified": 0,
"agentSearches": 0,
"crawlerHits": 0,
"notFound": 0,
"readers": 0,
"reads": 0,
"searchNoResults": 0,
"searches": 0,
"votesDown": 0,
"votesUp": 0
},
"trafficBreakdown": [
{
"bar": 0,
"label": "string",
"value": 0
}
],
"trend": [
{
"agents": 0,
"date": "string",
"people": 0
}
]
}
:::
:::details Error responses (400, 401, 402, 403, 404, 429, 500)
400
invalid_request: a parameter or the body is not valid.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
401
unauthorized: the access key is missing, invalid or expired.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
402
upgrade_required: the plan of the org does not include this operation.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
403
permission_denied: the key lacks the permission. two_factor_required: the org requires admins to turn on two-factor authentication.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
404
not_found: the object does not exist, or the key cannot reach it.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
429
rate_limited: too many requests. Wait for the time in the Retry-After header.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
500
internal: the server failed.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
:::