curl --request POST \
--url https://production-api.joinrings.com/v1/persons/activity-stats/batch \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"uuids": [
"<string>"
],
"group_by": "<string>",
"periods": "<string>",
"sort_by": "<string>"
}
'import requests
url = "https://production-api.joinrings.com/v1/persons/activity-stats/batch"
payload = {
"uuids": ["<string>"],
"group_by": "<string>",
"periods": "<string>",
"sort_by": "<string>"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
uuids: ['<string>'],
group_by: '<string>',
periods: '<string>',
sort_by: '<string>'
})
};
fetch('https://production-api.joinrings.com/v1/persons/activity-stats/batch', 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://production-api.joinrings.com/v1/persons/activity-stats/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'uuids' => [
'<string>'
],
'group_by' => '<string>',
'periods' => '<string>',
'sort_by' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://production-api.joinrings.com/v1/persons/activity-stats/batch"
payload := strings.NewReader("{\n \"uuids\": [\n \"<string>\"\n ],\n \"group_by\": \"<string>\",\n \"periods\": \"<string>\",\n \"sort_by\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://production-api.joinrings.com/v1/persons/activity-stats/batch")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"uuids\": [\n \"<string>\"\n ],\n \"group_by\": \"<string>\",\n \"periods\": \"<string>\",\n \"sort_by\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://production-api.joinrings.com/v1/persons/activity-stats/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"uuids\": [\n \"<string>\"\n ],\n \"group_by\": \"<string>\",\n \"periods\": \"<string>\",\n \"sort_by\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"entity_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"by_user": [
{
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"name": "<string>"
}
],
"top_email_user": {
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"name": "<string>"
},
"top_meeting_user": {
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"name": "<string>"
}
}
]
}Bulk person activity stats
Body: uuids (person UUIDs, max 100), plus the same optional periods
group_by, and sort_by controls as the single-entity endpoint.
results holds one entry per input UUID, in order. UUIDs with no data —
or that the identified user is not authorized to read — come back with
empty periods rather than failing the whole batch.
curl --request POST \
--url https://production-api.joinrings.com/v1/persons/activity-stats/batch \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"uuids": [
"<string>"
],
"group_by": "<string>",
"periods": "<string>",
"sort_by": "<string>"
}
'import requests
url = "https://production-api.joinrings.com/v1/persons/activity-stats/batch"
payload = {
"uuids": ["<string>"],
"group_by": "<string>",
"periods": "<string>",
"sort_by": "<string>"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
uuids: ['<string>'],
group_by: '<string>',
periods: '<string>',
sort_by: '<string>'
})
};
fetch('https://production-api.joinrings.com/v1/persons/activity-stats/batch', 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://production-api.joinrings.com/v1/persons/activity-stats/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'uuids' => [
'<string>'
],
'group_by' => '<string>',
'periods' => '<string>',
'sort_by' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://production-api.joinrings.com/v1/persons/activity-stats/batch"
payload := strings.NewReader("{\n \"uuids\": [\n \"<string>\"\n ],\n \"group_by\": \"<string>\",\n \"periods\": \"<string>\",\n \"sort_by\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://production-api.joinrings.com/v1/persons/activity-stats/batch")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"uuids\": [\n \"<string>\"\n ],\n \"group_by\": \"<string>\",\n \"periods\": \"<string>\",\n \"sort_by\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://production-api.joinrings.com/v1/persons/activity-stats/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"uuids\": [\n \"<string>\"\n ],\n \"group_by\": \"<string>\",\n \"periods\": \"<string>\",\n \"sort_by\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"entity_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"by_user": [
{
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"name": "<string>"
}
],
"top_email_user": {
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"name": "<string>"
},
"top_meeting_user": {
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"periods": [
{
"activity_counts": {
"emails": 0,
"meetings": 0,
"total": 0
},
"period": "<string>",
"last_activity_date": "<string>"
}
],
"name": "<string>"
}
}
]
}Authorizations
Body
Entity UUIDs to fetch stats for (max 100).
Optional grouping. internal_user returns a per-user breakdown under by_user in addition to the aggregate periods.
"internal_user"Comma-separated list of periods to retrieve stats for. Valid values: '30_days', '90_days', '180_days', '365_days', 'all_time'. If not specified, returns all available periods.
Optional. top_user populates top_email_user and top_meeting_user (each user's name + 90-day counts) without requiring group_by=internal_user's full by_user array. Combine with group_by=internal_user to get both.
"top_user"Response
Bulk activity-stats response.
results holds one ActivityStatsResponse per input UUID, in the same
order as the request. Entities the caller is not authorized to read (or
that have no data) are returned with empty periods rather than failing
the whole batch.
Show child attributes
Show child attributes