Per-campaign analytics
Returns detailed analytics for a single campaign, including:
- Campaign info and
stats— campaign-level totals across the combined main sequence + all subsequences (sent/opened/clicked/bounced/replied). stepStats— per-step breakdown for the main sequence only. Subseq step indices live in their own namespace, so combining them here would collide step 0/1/... For per-subseq breakdown, seesubsequences[].stepStats.subsequences[]— one entry per subsequence with its ownstats,stepStats,addedCount, andcurrentlyEnrolledcount.bySequence— sent/opened/clicked/bounced split by main vs subseq.- Lead status breakdown (active, paused, completed, bounced, etc.)
- Total replied count and positive replied count (based on workspace AI tag settings)
Without from/to, returns all-time data. Supply one or both to filter by date range.
Date filters apply to email sends (and to per-subsequence stats); reply
attribution to subsequences uses the lead's subsequence.repliedAt timestamp
which the reply-worker sets when a reply is matched to a subsequence email.
curl -X GET "https://api.sendkit.ai/v1/analytics/campaigns/example_string?from=2024-05-01&to=2024-05-31" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY"
import requests
import json
url = "https://api.sendkit.ai/v1/analytics/campaigns/example_string?from=2024-05-01&to=2024-05-31"
headers = {
"Content-Type": "application/json",
"X-Api-Key": "YOUR_API_KEY"
}
response = requests.get(url, headers=headers)
print(response.json())
const response = await fetch("https://api.sendkit.ai/v1/analytics/campaigns/example_string?from=2024-05-01&to=2024-05-31", {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Api-Key": "YOUR_API_KEY"
}
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://api.sendkit.ai/v1/analytics/campaigns/example_string?from=2024-05-01&to=2024-05-31", nil)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Api-Key", "YOUR_API_KEY")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://api.sendkit.ai/v1/analytics/campaigns/example_string?from=2024-05-01&to=2024-05-31')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['Content-Type'] = 'application/json'
request['X-Api-Key'] = 'YOUR_API_KEY'
response = http.request(request)
puts response.body
{
"success": true,
"data": {
"campaign": {
"id": "664a1b2c3d4e5f6a7b8c9d02",
"name": "Webinar Attendee Nurture",
"status": "paused"
},
"stats": {
"sent": 195,
"delivered": 195,
"opened": 51,
"clicked": 16,
"replied": 18,
"bounced": 18,
"unsubscribed": 8
},
"bySequence": {
"main": {
"sent": 175,
"opened": 45,
"clicked": 13,
"bounced": 17
},
"subsequence": {
"sent": 20,
"opened": 6,
"clicked": 3,
"bounced": 1
}
},
"stepStats": [
{
"_id": 0,
"sent": 100,
"opened": 30,
"clicked": 8,
"bounced": 9
},
{
"_id": 1,
"sent": 50,
"opened": 10,
"clicked": 3,
"bounced": 8
},
{
"_id": 2,
"sent": 25,
"opened": 5,
"clicked": 2,
"bounced": 0
}
],
"subsequences": [
{
"id": "664c1b2c3d4e5f6a7b8c9d10",
"name": "Interested follow-up",
"trigger": {
"type": "ai_tag",
"value": "interested"
},
"enabled": true,
"archived": false,
"addedCount": 22,
"currentlyEnrolled": 14,
"stats": {
"sent": 20,
"opened": 6,
"clicked": 3,
"bounced": 1,
"replied": 4
},
"stepStats": [
{
"_id": 0,
"sent": 14,
"opened": 5,
"clicked": 2,
"bounced": 1
},
{
"_id": 1,
"sent": 6,
"opened": 1,
"clicked": 1,
"bounced": 0
}
]
}
],
"statusBreakdown": {
"failed": 6,
"bounced": 18,
"active": 30,
"completed": 23,
"unsubscribed": 8,
"replied": 18,
"pending": 22
},
"totalReplied": 18,
"totalPositiveReplied": 8
}
}
{
"error": "Not Found",
"message": "The requested resource was not found",
"code": 404
}
/v1/analytics/campaigns/{campaignId}Target server for requests. Edit to use your own host.
Platform API key (sk_user_...) or Workspace API key (sk_...)
Campaign ID
Start date (ISO 8601 or date string). Omit for no lower bound.
End date (ISO 8601 or date string). Omit for no upper bound.
Request Preview
Response
Response will appear here after sending the request
Authentication
API Key for authentication. Platform API key (sk_user_...) or Workspace API key (sk_...)
Path Parameters
Campaign ID
Query Parameters
Responses
Campaign aggregate email stats
Send/open/click/bounce totals split by main vs subsequence emails (within the date filter, if any).
Aggregate email stats for a single sequence bucket (main or subsequence) within the requested date range.
Aggregate email stats for a single sequence bucket (main or subsequence) within the requested date range.
Per-step breakdown for the main sequence only. Sorted by step number. Top-level stats remains the combined main + subseq total. Per-subsequence step breakdown is in subsequences[].stepStats.
Zero-based sequence step index
One entry per subsequence configured on the campaign. Empty entries (no sends in the date window) are still returned with zero-valued stats so the UI can render every defined subseq.
Subsequence ID (the _id of the subdocument)
What causes a lead to enter this subsequence. With type='ai_tag', the
subsequence fires when the lead's AI tag (set by reply classification or
manual tagging) matches value (case-insensitive); manual tag changes via
the campaign-lead PATCH endpoint and the MCP tag_conversation tool also
enroll into matching subsequences. With type='reply', the subsequence
fires the first time the lead replies and value is ignored.
ai_tagreplyRequired when type is ai_tag. The AI tag value to match.
Total leads that have ever entered this subsequence
Number of leads currently in this subsequence with subsequence.status === "active". Always reflects current state, ignoring the date filter.
Aggregate email stats for this subsequence within the date filter (replied counts use subsequence.repliedAt).
Per-step breakdown within this subsequence. Step indices are local to the subsequence — step 0 is the subsequence's first email.
Zero-based sequence step index
Lead count by status (keys are status strings, values are counts)
Total leads that replied
Total leads that replied with a positive AI tag