Buyer Signals
Read aggregated engagement data from tracked emails your organization has sent — opens, clicks, replies, and their timing.
buyer-signals:read covers every endpoint on this page. Reply data (which recipient replied, when, and on which email) is surfaced inline — reply signals are one of the four tracked event types alongside sends, opens, and clicks.
What is a "buyer signal"?
A buyer signal is one instance of a tracked engagement event on a sent email. Cirrus recognizes four types:
| Signal | Meaning |
|---|---|
sends | Cirrus dispatched the message (baseline denominator). |
opens | Recipient rendered the tracking pixel. |
clicks | Recipient clicked a tracked link. |
replies | Recipient responded to the message. Attribution runs through Cirrus's reply-detection heuristics; auto-responders are filtered out. |
The endpoints below expose these signals at three grains: aggregate (/summary), daily timeseries (/activity), and per-sent-email (/sent-emails).
Endpoints on this page
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1alpha1/buyer-signals/summary | Unique-recipient stats across a period. Details ↓ |
GET | /api/v1alpha1/buyer-signals/activity | Daily timeseries of send / open / click / reply counts. Details ↓ |
GET | /api/v1alpha1/buyer-signals/sent-emails | Per-email table with engagement stats. Details ↓ |
GET | /api/v1alpha1/buyer-signals/sent-emails/{sentEmailId} | One sent email with full engagement detail. Details ↓ |
GET | /api/v1alpha1/buyer-signals/sent-emails/{sentEmailId}/signals | Per-recipient signal drill-down — the "who opened / replied?" view. Details ↓ |
Get summary stats
GET /api/v1alpha1/buyer-signals/summary
Aggregate unique-recipient stats across a period. One object, no pagination.
Query parameters
| Parameter | Type | Description |
|---|---|---|
periodDays | number | 7, 14, or 30. Default 7. |
Response
had*counts are unique-recipient — a recipient who opened three times contributes1tohadOpened, not3. For raw event counts use/activity.- Percentages are computed off
totalSentand are float-typed with one decimal.
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/summary?periodDays=30" \
-H "X-Cirrus-Api-Key: $TOKEN"import requests
response = requests.get(
"https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/summary",
headers={"X-Cirrus-Api-Key": token},
params={"periodDays": 30},
)
response.raise_for_status()
summary = response.json()using System.Net.Http;
using System.Web;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);
var query = HttpUtility.ParseQueryString(string.Empty);
query["periodDays"] = "30";
var uri = new UriBuilder("https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/summary")
{
Query = query.ToString()
}.Uri;
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var summary = await response.Content.ReadAsStringAsync();{
"periodDays": 30,
"totalSent": 1247,
"hadOpened": 812,
"hadClicked": 168,
"hadReplied": 94,
"openedPercentage": 65.1,
"clickedPercentage": 13.5,
"repliedPercentage": 7.5
}Get daily activity
GET /api/v1alpha1/buyer-signals/activity
Daily timeseries suitable for a chart. Returns one row per (date, action) combination for the requested period.
Query parameters
| Parameter | Type | Description |
|---|---|---|
periodDays | number | 7, 14, or 30. Default 7. |
action | string | (optional) sends, opens, clicks, replies. Repeatable. Omitted returns all four. |
Response
countis raw event count, not unique-recipient — a recipient who opens the same email three times contributes 3 opens to that day's total. Use/summaryfor the unique-recipient view.- Days with zero activity are omitted. A caller expecting a dense series should hydrate missing days as zero on their end.
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/activity?periodDays=30" \
-H "X-Cirrus-Api-Key: $TOKEN"import requests
response = requests.get(
"https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/activity",
headers={"X-Cirrus-Api-Key": token},
params={"periodDays": 30},
)
response.raise_for_status()
chart = response.json()using System.Net.Http;
using System.Web;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);
var query = HttpUtility.ParseQueryString(string.Empty);
query["periodDays"] = "30";
var uri = new UriBuilder("https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/activity")
{
Query = query.ToString()
}.Uri;
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var chart = await response.Content.ReadAsStringAsync();{
"periodDays": 30,
"items": [
{ "date": "2026-08-11", "action": "sends", "count": 42 },
{ "date": "2026-08-11", "action": "opens", "count": 28 },
{ "date": "2026-08-11", "action": "clicks", "count": 6 },
{ "date": "2026-08-11", "action": "replies", "count": 4 }
]
}List sent emails
GET /api/v1alpha1/buyer-signals/sent-emails
Per-email table with per-recipient engagement rolled up per row. Combines standard sends and blast sends in one list — use emailType to filter to one.
Query parameters
| Parameter | Type | Description |
|---|---|---|
cursor | string | Standard keyset cursor. |
limit | number | Clamped 1–100, default 25. |
sort | string | sentAt, lastReplyAt, lastOpenAt, lastClickAt, replies, opens, clicks. Prefix - for descending. Default -sentAt. |
periodDays | number | 7, 14, or 30. Default 7. Filter to emails sent within the window. |
search | string | (optional) Substring match on subject or recipient email. Case-insensitive. |
emailType | string | (optional) standard (one-off from Sidebar/Gmail), email-blast (bulk campaign), all. Default all. |
Response
See the SentEmailmodel for the full field reference.
recipientEmailsis the full to-list on the send. A single sent email can have multiple recipients when the sender used cc/bcc or when a blast batched a small group into one message; per-recipient signals are on the/signalsdrill-down.emailType=email-blastrows carry a populatedblastIdlinking back to theEmailBlastresource.lastOpenLocationis a coarse city-level geolocation of the IP that fired the most recent tracking-pixel open. Omitted (null) when the recipient's mail client suppressed the pixel or geolocation isn't confident.
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails?periodDays=30&limit=25" \
-H "X-Cirrus-Api-Key: $TOKEN"import requests
response = requests.get(
"https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails",
headers={"X-Cirrus-Api-Key": token},
params={"periodDays": 30, "limit": 25},
)
response.raise_for_status()
page = response.json()using System.Net.Http;
using System.Web;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);
var query = HttpUtility.ParseQueryString(string.Empty);
query["periodDays"] = "30";
query["limit"] = "25";
var uri = new UriBuilder("https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails")
{
Query = query.ToString()
}.Uri;
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var page = await response.Content.ReadAsStringAsync();{
"items": [
{
"id": "semail_...",
"subject": "Following up on Q3 pipeline forecasting",
"sender": {
"userId": "usr_...",
"displayName": "Alex Rivera"
},
"recipientEmails": ["guest@example.com"],
"sentAt": "2026-08-11T14:30:00Z",
"opens": 5,
"clicks": 1,
"replies": 1,
"lastOpenAt": "2026-08-12T09:22:03Z",
"lastClickAt": "2026-08-12T09:22:41Z",
"lastReplyAt": "2026-08-12T10:14:07Z",
"lastOpenLocation": "New York, NY",
"emailType": "standard",
"blastId": null
}
],
"nextCursor": null
}Get a sent email
GET /api/v1alpha1/buyer-signals/sent-emails/{sentEmailId}
Response
Same shape as the list row. For per-recipient breakdown of the same email, hit /signals.
Errors
404 sent-email-not-found— no sent email with that id in your org.
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails/semail_..." \
-H "X-Cirrus-Api-Key: $TOKEN"import requests
response = requests.get(
f"https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails/{sent_email_id}",
headers={"X-Cirrus-Api-Key": token},
)
response.raise_for_status()
sent_email = response.json()using System.Net.Http;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);
var response = await client.GetAsync(
$"https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails/{sentEmailId}");
response.EnsureSuccessStatusCode();
var sentEmail = await response.Content.ReadAsStringAsync();List recipient signals
GET /api/v1alpha1/buyer-signals/sent-emails/{sentEmailId}/signals
Per-recipient signal breakdown for one sent email — one row per recipient with their opens, clicks, replies, and last-event timestamps.
Query parameters
| Parameter | Type | Description |
|---|---|---|
cursor | string | Standard keyset cursor. |
limit | number | Clamped 1–100, default 25. |
sort | string | lastReplyAt, lastOpenAt, replies, opens. Prefix - for descending. Default -lastReplyAt. |
hasReplied | boolean | (optional) When true, restrict to recipients whose reply was tracked. |
Response
contactIdis populated when the recipient email matches a Cirrus contact.nullwhen the recipient isn't in the contact model (e.g., a fresh outbound to a new address).
Errors
404 sent-email-not-found— no sent email with that id.
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails/semail_.../signals" \
-H "X-Cirrus-Api-Key: $TOKEN"import requests
response = requests.get(
f"https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails/{sent_email_id}/signals",
headers={"X-Cirrus-Api-Key": token},
)
response.raise_for_status()
page = response.json()using System.Net.Http;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);
var response = await client.GetAsync(
$"https://altus.cirrusinsight.com/api/v1alpha1/buyer-signals/sent-emails/{sentEmailId}/signals");
response.EnsureSuccessStatusCode();
var page = await response.Content.ReadAsStringAsync();{
"items": [
{
"recipientEmail": "guest@example.com",
"contactId": "cont_...",
"opens": 5,
"clicks": 1,
"replies": 1,
"lastOpenAt": "2026-08-12T09:22:03Z",
"lastClickAt": "2026-08-12T09:22:41Z",
"lastReplyAt": "2026-08-12T10:14:07Z"
}
],
"nextCursor": null
}