Your AI Connector Docs

Analytics & Reports API

These read-only endpoints let you pull your account’s activity into your own dashboards and reports: message-event counts, credit consumption, AI spend, and the same charts and insights the in-app dashboard shows. This guide covers:

  • Summary — message-volume counters (sent, delivered, read, replied, booked, contacts created, credits).
  • Credits — a detailed, paginated ledger of credit usage with totals and breakdowns.
  • AI cost — a per-day rollup of AI spend.
  • Metric series — a chart-ready time series for one or more metrics, grouped by campaign, channel, AI Agent, or number.
  • Conversation outcomes — conversations over time, grouped by the contact tags they carry (the closing tags your agent applies).
  • Conversation costs: the average credit cost of a conversation the AI handled alone versus one your team stepped into.
  • Dashboard insights and Dashboard AI insights — the full data behind the in-app dashboard, including AI-written summaries.
  • Entity activity — a single contact’s, deal’s, or task’s timeline.
  • Aggregated event counts — a legacy, camelCase form of Summary kept for existing integrations.

Every endpoint on this page needs an exact scope, not both: pass at most one of campaign_id (legacy) or agent_id where the endpoint accepts it. Sending both returns 400, and an id that is not on your account returns 404 rather than 403, so other accounts’ ids stay unguessable.

Only two endpoints filter by contact tag. tag_ids (with tag_match) is honoured by Dashboard insights and Aggregated event counts — those are the two the in-app dashboard’s All tags filter uses. Summary, Metric series and Conversation outcomes validate the parameter (a malformed id list still returns 400) but do not apply it: you get account-wide numbers back, with no error to tell you so. Don’t read an unfiltered total as a tag-filtered one.

All paths below are relative to the API base URL:

https://api.youraiconnector.com/v1

Every request must be authenticated. See Authentication for the four accepted methods. The examples here use the X-API-Key header (and one query-parameter form for cURL).


Date range

All three endpoints accept the same optional date filters:

Parameter Description
from Start of the range, YYYY-MM-DD, inclusive. Defaults to 30 days ago.
to End of the range, YYYY-MM-DD, inclusive. Defaults to today.

Dates are interpreted in UTC. The range defaults to the last 30 days and is capped at 366 days — a wider range returns 400. from must not be after to.

The truncated flag

The Summary and Credits endpoints cap how many records a single request scans. If your range is busy enough to hit that cap, the response includes "truncated": true. When you see it, the numbers are based on a partial scan — narrow your date range (or page through with a smaller window) to get complete figures.

Note: Cost and token figures are only included for AI calls billed to your own provider API keys. When cost figures are hidden for your account, the response sets "costs_redacted": true and the cost fields are returned as zero.


Message volume summary

Returns aggregated message-event counters for your account, both as range totals and as a per-day series. Every day in the range appears in by_date — quiet days are zero-filled. Optionally filter to a single campaign with campaign_id.

GET /analytics/summary

Parameter Required Description
from No Range start, YYYY-MM-DD.
to No Range end, YYYY-MM-DD.
campaign_id No Only count events belonging to this campaign.

cURL

curl "https://api.youraiconnector.com/v1/analytics/summary?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/summary?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/summary",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()

Response

{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "total": 1240,
    "sent": 800,
    "delivered": 760,
    "read": 540,
    "replied": 210,
    "booked": 35,
    "contact_created": 120,
    "credits_spent": 412.5,
    "credits_recharged": 500
  },
  "by_date": [
    {
      "date": "2026-05-01",
      "total": 40,
      "sent": 25,
      "delivered": 24,
      "read": 18,
      "replied": 7,
      "booked": 1,
      "contact_created": 4,
      "credits_spent": 13.5,
      "credits_recharged": 0
    }
  ],
  "truncated": false
}

Each entry in by_date has the same counter fields as totals, plus a date.

If you pass a campaign_id that does not belong to your account, the response is 404 with { "success": false, "error": "Campaign not found" }.


Credit usage

Returns credit usage over the range: a paginated list of individual records, plus range totals and breakdowns by reason and by campaign.

GET /analytics/credits

Parameter Required Description
from No Range start, YYYY-MM-DD.
to No Range end, YYYY-MM-DD.
campaign_id No Only include usage attributed to this campaign.
limit No Page size for records, 1–100. Defaults to 50.
cursor No Pass the previous page’s next_cursor to fetch the next page.

Adjustments vs. consumption: Balance changes such as bonuses, plan renewals, and corrections are excluded from totals and the breakdowns — they are not real consumption. They still appear in the records list, flagged with "is_adjustment": true.

Totals and breakdowns appear only on the first page (when no cursor is supplied). On later pages, totals, by_reason, by_reason_cost, and by_campaign are returned as null — only the records array continues. This avoids re-scanning the whole range for every page.

cURL

curl "https://api.youraiconnector.com/v1/analytics/credits?from=2026-05-01&to=2026-05-31&limit=50&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({
  from: "2026-05-01",
  to: "2026-05-31",
  limit: "50",
});
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/credits?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

// To page: pass data.next_cursor as ?cursor on the next request, until it is null.

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/credits",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31", "limit": 50},
)
data = res.json()

# To page: pass data["next_cursor"] as cursor on the next request, until it is None.

Response (first page)

{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "credits_used": 412.5,
    "cost_usd": 1.284512,
    "records": 318
  },
  "by_reason": {
    "AI Message": 380.0,
    "Campaign Message": 32.5
  },
  "by_reason_cost": {
    "AI Message": 1.284512,
    "Campaign Message": 0
  },
  "by_campaign": {
    "Spring Promo": 250.0,
    "Reactivation": 162.5
  },
  "records": [
    {
      "id": "rec_abc123",
      "amount": 1,
      "timestamp": "2026-05-31T14:02:11.000Z",
      "reason": "AI Message",
      "is_adjustment": false,
      "campaign_id": "campaign123",
      "campaign_name": "Spring Promo",
      "contact_id": "contact456",
      "contact_name": "Jane Smith",
      "credit_type": "ai",
      "custom_keys_used": false,
      "description": null,
      "cost_usd": 0,
      "input_tokens": 0,
      "output_tokens": 0,
      "cache_read_tokens": 0,
      "cache_creation_tokens": 0,
      "ai_model": null,
      "request_id": null,
      "is_test": false
    }
  ],
  "next_cursor": "rec_abc123",
  "costs_redacted": false,
  "truncated": false
}

Field notes:

  • amount — credits charged for the record. Zero for records billed to your own provider API key.
  • is_adjustment — true for balance changes (excluded from totals/breakdowns).
  • cost_usd, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, ai_model, request_id — populated only on records billed to your own provider API key; zero or null otherwise.
  • is_test — true for playground/test runs, which are never billed.
  • next_cursor — the cursor for the next page, or null when there are no more records.

Credit balance

GET /users/me/credits — your account’s current credit position in one call: what is left to spend, the monthly allowance, and the auto-recharge and low-credit settings. Credit usage above is a history; this is the balance right now. Team members calling it need billing access; the account owner’s key always has it.

curl "https://api.youraiconnector.com/v1/users/me/credits?apiKey=YOUR_API_KEY"
const res = await fetch("https://api.youraiconnector.com/v1/users/me/credits", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const { balance } = await res.json();

Response (200)

{
  "success": true,
  "balance": 1837.5,
  "monthly_credits": 2000,
  "used_this_month": null,
  "auto_recharge_enabled": true,
  "low_credit_threshold": null
}
Field Meaning
balance Credits left to spend — the same number the Credits card shows.
monthly_credits The plan’s monthly allowance, or null when the account has none.
used_this_month Credits spent this month for an allocation (agency sub-) account; null for a regular account — use Credit usage for that.
auto_recharge_enabled Whether auto-recharge is switched on.
low_credit_threshold The balance at which the low-credit webhook fires, or null when the default applies.

Agencies can pass sub_account_id to read a client account’s balance. Inside an automation, the Check credits step returns the same fields.


AI cost rollup

Returns the per-day AI spend rollup for your account. This reads pre-aggregated daily totals, so it is fast even over long ranges. Every day in the range appears in days — quiet days are zero-filled.

GET /analytics/ai-cost

Parameter Required Description
from No Range start, YYYY-MM-DD.
to No Range end, YYYY-MM-DD.

cURL

curl "https://api.youraiconnector.com/v1/analytics/ai-cost?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/ai-cost?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/ai-cost",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()

Response

{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "total_usd": 12.4821,
    "byok_usd": 12.4821,
    "platform_usd": 0,
    "calls": 4210
  },
  "days": [
    {
      "date": "2026-05-01",
      "total_usd": 0.4012,
      "byok_usd": 0.4012,
      "platform_usd": 0,
      "input_usd": 0.18,
      "output_usd": 0.19,
      "cache_creation_usd": 0.02,
      "cache_read_usd": 0.0112,
      "calls": 140,
      "by_provider": { "anthropic": 0.4012 }
    }
  ],
  "costs_redacted": false
}

Field notes:

  • byok_usd — spend billed to your own provider API keys.
  • platform_usd — the portion of spend that ran on the platform rather than your own key.
  • input_usd, output_usd, cache_creation_usd, cache_read_usd — the cost components that make up total_usd.
  • by_provider — USD spend keyed by AI provider name.
  • USD figures are only returned to accounts that use their own provider key. For credit-paying accounts every USD field is zero and costs_redacted is true (call counts stay visible).

Metric series

Returns one or more metric time series in one call, optionally grouped by up to two dimensions — the endpoint to bind a chart to. A single request can answer “sent and replied per day, per channel, for this campaign” without one call per campaign.

GET /analytics/series

Every response carries a labels array (the time axis, zero-filled across the whole range) and one entry in series per group, each holding one array per requested metric aligned to labels. Series past limit are not dropped — they collapse into other_bucket, computed as the range total minus the returned series, so a rendered chart always adds up to your real numbers; truncated is true whenever that happens.

Where the numbers come from: sent, delivered, read, and replied come from message records, which carry the channel and sending number. booked, contact_created, and credits_spent come from the event stream, which carries no sending number, so those metrics land in the null-number bucket when you group by number.

conversations counts the conversations (chat sessions) that started in each bucket, and conversation_credits what those conversations cost, counted exactly like Conversation costs. Divide one by the other per bucket for the average cost per conversation over time. When you group or filter by campaign, agent, channel or number, a conversation counts toward the one its first message belongs to.

Parameter Required Description
from No Range start, YYYY-MM-DD. Defaults to 30 days ago.
to No Range end, YYYY-MM-DD. Defaults to today.
metrics No Comma-separated list from sent, ai_sent, human_sent, automated_sent, delivered, read, replied, booked, contact_created, credits_spent, conversations, conversation_credits. Defaults to sent,replied. An unknown metric returns 400.
group_by No Comma-separated list of up to two dimensions from date, campaign, channel, agent, number. date is accepted but has no effect — every response already carries the time axis. Omit for a single account-wide series.
granularity No day (default), week, or month. Week buckets start on Monday, month buckets on the 1st.
limit No How many series to return before the rest collapse into other_bucket, 1–50. Defaults to 12.
campaign_id No Only count activity belonging to this campaign. Legacy; prefer agent_id.
agent_id No Only count activity belonging to this AI Agent.
channel No Only count activity on this channel, for example whatsapp.

This endpoint’s date range is capped at 92 days (tighter than the 366-day cap used elsewhere on this page).

cURL

curl "https://api.youraiconnector.com/v1/analytics/series?from=2026-05-01&to=2026-05-31&metrics=sent,replied,booked&group_by=campaign,channel&limit=10&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({
  from: "2026-05-01",
  to: "2026-05-31",
  metrics: "sent,replied,booked",
  group_by: "campaign,channel",
  limit: "10",
});
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/series?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/series",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={
        "from": "2026-05-01",
        "to": "2026-05-31",
        "metrics": "sent,replied,booked",
        "group_by": "campaign,channel",
        "limit": 10,
    },
)
data = res.json()

Response

{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "granularity": "day",
  "labels": ["2026-05-01", "2026-05-02"],
  "group_by": ["campaign", "channel"],
  "metrics": ["sent", "replied", "booked"],
  "series": [
    {
      "key": {
        "campaign_id": "campaign123",
        "campaign_name": "Spring Promo",
        "channel": "whatsapp"
      },
      "total": 812,
      "metrics": {
        "sent": [40, 35],
        "replied": [12, 9],
        "booked": [2, 1]
      }
    }
  ],
  "other_bucket": {
    "series_count": 6,
    "total": 340,
    "metrics": {
      "sent": [18, 20],
      "replied": [5, 6],
      "booked": [0, 1]
    }
  },
  "truncated": true
}

Field notes:

  • key — the identity of one series. Only the keys for the requested group_by dimensions are present; a dimension whose value is unknown for a row (a message with no campaign, an event with no channel) comes back as null rather than being dropped, so series still add up to the totals.
  • other_bucket — null when nothing was collapsed.
  • This endpoint returns 503 with "error_code": "analytics_unavailable" when the reporting database cannot answer for your account, rather than a 200 full of zeros — a zeroed chart would read as fact.

Conversation outcomes

Returns conversation outcomes over a date range: a per-day count of conversations under each contact tag, plus range totals for replies, bookings, handovers to a human, and conversations whose contact carries no tag.

The tag is a contact tag: the tags your AI Agent applies with its tag tool, auto-tag rules, the API or your team. It is not a per-conversation label. A conversation is counted under the tags its contact carries at the time of the request, so a contact with several tags counts once under each, and a tag removed later drops out of past days too. Give your agent one closing tag per outcome (for example resolved_ai, handoff_asked_for_human) and this endpoint returns containment and handoff reasons over time.

GET /analytics/outcomes

Pass group_by=tag to collapse the time axis and get range totals per tag only — in that mode labels is empty and each tag’s counts array is empty, while total is still populated.

Parameter Required Description
from No Range start, YYYY-MM-DD. Defaults to 30 days ago.
to No Range end, YYYY-MM-DD. Defaults to today.
campaign_id No Only count conversations with contacts currently on this campaign. Legacy; prefer agent_id.
agent_id No Only count outcomes belonging to this AI Agent.
group_by No date (default) keeps the per-day counts; tag collapses to range totals.

This endpoint’s date range is capped at 92 days.

cURL

curl "https://api.youraiconnector.com/v1/analytics/outcomes?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/outcomes?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/outcomes",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()

Response

{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "group_by": "date",
  "labels": ["2026-05-01", "2026-05-02"],
  "by_tag": [
    { "tag_id": "tag_8f2k1", "tag": "interested", "total": 84, "counts": [3, 5] },
    { "tag_id": "tag_c91xq", "tag": "not_interested", "total": 40, "counts": [1, 2] },
    { "tag_id": null, "tag": null, "total": 12, "counts": [0, 1] }
  ],
  "totals": {
    "sessions": 260,
    "replied": 210,
    "booked": 35,
    "human_alerted": 18,
    "unresolved": 12
  }
}

Field notes:

  • by_tag[].tag / by_tag[].tag_id — the contact tag’s name and id; both null on the row of conversations whose contact carries no tag. At most 20 tags are returned, highest volume first.
  • totals.sessions — distinct conversations started in the range. It is not the sum of by_tag[].total: a contact with three tags contributes one conversation to three rows.
  • totals.unresolved — conversations whose contact carries no tag.
  • totals.human_alerted — conversations handed over to a human; this is written on every handover and was not previously surfaced by any endpoint.
  • Same 503/analytics_unavailable posture as Metric series when the reporting database cannot answer.

Conversation costs

Returns what a conversation costs on average over a date range, split by how it went. This is the number to show a client as return on investment: what a conversation the AI handled alone costs, next to one your team had to step into.

GET /analytics/conversation-costs

Parameter Required Description
from No Start date, YYYY-MM-DD, inclusive. Defaults to 30 days ago.
to No End date, YYYY-MM-DD, inclusive. Defaults to today. Maximum range 31 days.
sub_account_id No Agency keys: report on this client account instead of your own.
curl "https://api.youraiconnector.com/v1/analytics/conversation-costs?from=2026-08-26&to=2026-09-24&apiKey=YOUR_API_KEY"

Response

{
  "success": true,
  "from": "2026-08-26",
  "to": "2026-09-24",
  "sessions": 564,
  "total_credits": 5957,
  "summary": {
    "contained": { "sessions": 503, "credits": 5168, "avg_credits": 10.2744 },
    "handed_off": { "sessions": 50, "credits": 781, "avg_credits": 15.62 },
    "no_ai": { "sessions": 11, "credits": 8, "avg_credits": 0.7273 }
  },
  "sessions_truncated": false
}

Field notes:

  • Counts conversations (chat sessions) that started in the range, with the credits charged inside each conversation’s window, refunds subtracted. Credits spent outside any conversation (daily summaries, monthly fees, automations that were not started by a contact, such as webhook or RSS triggers) are not part of it. Automation runs and AI steps started by a contact count toward that contact’s conversation since September 26, 2026.
  • contained: the AI replied and nobody from your team had to step in. handed_off: someone sent a message after the AI had replied, or the AI alerted a human. no_ai: the AI never replied (for example chats your team handles with the AI paused).
  • At most 20,000 conversations are counted; sessions_truncated is true when the range held more, so narrow it.
  • Needs the billing permission for team members. Same 503/analytics_unavailable posture as Metric series.
  • Per contact, the same split is on Get contact cost.

Dashboard insights

Returns the full dashboard payload for a date range in one call: a reply-rate heatmap by weekday and hour, the campaign leaderboard, per-channel volume, exact per-connection totals, per-day metric breakdowns (account-wide, per channel, and per number), where contacts are from, inbox response time, and a recent activity feed. This is the richest reporting payload on the API — it powers the in-app dashboard directly.

GET /analytics/dashboard-insights

Parameter Required Description
startDate Yes Range start, YYYY-MM-DD.
endDate Yes Range end, YYYY-MM-DD.
campaignId No Only include activity belonging to this campaign (campaign_id also accepted). Legacy; prefer agent_id.
agent_id No Only include activity belonging to this AI Agent (agentId also accepted). Under an agent scope, the campaign leaderboard is built from that agent’s activity only.
tag_ids No Comma-separated tag ids (tagIds also accepted, up to 25). Narrows every block to contacts that currently carry any of these tags — the same “match any” rule the Contacts page filter uses. Combines with campaignId or agent_id. Rows with no contact (account-level credit recharges) fall out of a tag-scoped view, and the conversation_outcomes block comes back null under a tag scope. Returns 400 with error_code: 400 when the tag filter is not available for the account.
tag_match No How tag_ids combine (tagMatch also accepted): any (default — a contact needs one of the tags) or all (a contact needs every one of them). Ignored when tag_ids is absent; any other value is a 400 when tag_ids is present.
granularity No Bucket grain for metricDailyBreakdown only: day (default), week (Monday-based, like /analytics/series) or month. Its labels are then the bucket starts, and the block carries granularity back. Every other block is unaffected.

This endpoint uses startDate/endDate (not from/to) because it shares its implementation with the in-app dashboard. The range is capped at 92 days and is clamped, not rejected, when it is wider.

Null means unavailable, not zero. Several blocks (numberStats, channelDailySeries, metricDailyBreakdown, contactsByCountry) are computed from the reporting database and come back null when it cannot answer for your account. Do not render a null block as an empty chart.

cURL

curl "https://api.youraiconnector.com/v1/analytics/dashboard-insights?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({ startDate: "2026-05-01", endDate: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/dashboard-insights?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/dashboard-insights",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"startDate": "2026-05-01", "endDate": "2026-05-31"},
)
data = res.json()

Response (abridged — this payload is large; see the API Reference for the full schema)

{
  "success": true,
  "data": {
    "heatmap": {
      "buckets": [
        { "weekday": 1, "hour": 9, "sent": 12, "replied": 5, "replyRate": 0.42 }
      ]
    },
    "topCampaigns": [
      { "campaignId": "campaign123", "name": "Spring Promo", "sent": 420, "replied": 180, "booked": 22, "replyRate": 0.43, "creditsSpent": 210.5 }
    ],
    "channelVolume": [
      { "channel": "whatsapp", "sent": 800, "received": 540, "lastMessageAt": "2026-05-31T14:02:11.000Z" }
    ],
    "inboxSla": { "medianFirstResponseMs": 92000, "sampleSize": 140 },
    "activityFeed": [
      { "id": "evt_1", "kind": "booked", "at": "2026-05-31T14:02:11.000Z", "contactId": "contact456", "contactName": "Jane Smith", "campaignId": "campaign123", "campaignName": "Spring Promo", "label": "Jane Smith booked an appointment" }
    ],
    "numberStats": null,
    "channelDailySeries": null,
    "metricDailyBreakdown": null,
    "contactsByCountry": null,
    "ai_human_split": null
  }
}

Field notes:

  • heatmap.buckets[].weekday — 0 is Sunday through 6 is Saturday.
  • numberStats, channelDailySeries, metricDailyBreakdown, contactsByCountry, ai_human_split — each independently null when the reporting database is unavailable for your account; every other block still returns.

Dashboard AI insights

Returns three short, AI-written insights about the account’s messaging over a date range: one win, one thing to watch, and one tip — sentences you can paste straight into a report rather than numbers you still have to interpret. Generated from the account’s own message metrics only.

GET /analytics/dashboard-ai-insights

Parameter Required Description
startDate Yes Range start, YYYY-MM-DD.
endDate Yes Range end, YYYY-MM-DD.

This endpoint is account-wide — it takes no campaign or agent scope.

cURL

curl "https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({ startDate: "2026-05-01", endDate: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"startDate": "2026-05-01", "endDate": "2026-05-31"},
)
data = res.json()

Response

{
  "success": true,
  "data": {
    "insights": [
      { "tone": "win", "title": "Reply rate is up", "detail": "Your reply rate climbed to 43% this period, up from 36% the period before." },
      { "tone": "watch", "title": "Bookings slowed midweek", "detail": "Wednesday bookings dropped to a third of Monday's, worth a look at your Wednesday follow-up timing." },
      { "tone": "tip", "title": "Re-send to non-repliers", "detail": "212 contacts received a message but never replied — a short follow-up template often recovers 10-15% of them." }
    ]
  }
}

Missing startDate or endDate returns 400.


Entity activity timeline

Returns a single contact’s, deal’s, or task’s activity as one timeline, newest first: what happened and when, across messages, appointments, notes, and status changes. Use it to answer “what has happened with this person” without stitching several list endpoints together.

GET /analytics/entity-activity

Parameter Required Description
entityType Yes contact, deal, or task.
entityId Yes ID of the record whose timeline to return.

cURL

curl "https://api.youraiconnector.com/v1/analytics/entity-activity?entityType=contact&entityId=contact456&apiKey=YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({ entityType: "contact", entityId: "contact456" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/entity-activity?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/entity-activity",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"entityType": "contact", "entityId": "contact456"},
)
data = res.json()

Response

{
  "success": true,
  "data": {
    "items": [
      {
        "id": "evt_9",
        "kind": "appointment_booked",
        "at": "2026-05-31T14:02:11.000Z",
        "label": "Booked an appointment for June 3",
        "detail": "Consultation call, 30 minutes"
      },
      {
        "id": "evt_8",
        "kind": "message_replied",
        "at": "2026-05-31T13:58:02.000Z",
        "label": "Replied: \"Yes, that time works\""
      }
    ]
  }
}

A missing or invalid entityType/entityId returns 400. An entity that does not exist on your account returns 404, so other accounts’ ids stay unguessable.


Aggregated event counts (legacy)

Returns the same aggregated event counts as Message volume summary, but in the camelCase shape (contactCreated rather than contact_created, byDate rather than by_date) some older integrations were built against. Prefer /analytics/summary for new integrations — this endpoint exists only so the in-app dashboard and the API share one implementation.

GET /analytics/aggregate

Parameter Required Description
startDate No Range start, ISO date or date-time. Defaults to the same window /analytics/summary uses.
endDate No Range end, ISO date or date-time.
campaignId No Only count events belonging to this campaign (campaign_id also accepted). Legacy; prefer agent_id.
agent_id No Only count events belonging to this AI Agent (agentId also accepted).
tag_ids No Comma-separated tag ids (tagIds also accepted, up to 25). Only count events whose contact currently carries any of these tags. Combines with campaignId or agent_id. Events with no contact (creditsRecharged) are excluded under a tag scope.
tag_match No How tag_ids combine (tagMatch also accepted): any (default) or all (only contacts carrying every one of the tags). Ignored when tag_ids is absent; any other value is a 400 when tag_ids is present.

cURL

curl "https://api.youraiconnector.com/v1/analytics/aggregate?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"

Response

{
  "success": true,
  "data": {
    "from": "2026-05-01",
    "to": "2026-05-31",
    "total": 1240,
    "byAnalyticType": {
      "total": 1240,
      "sent": 800,
      "delivered": 760,
      "read": 540,
      "replied": 210,
      "booked": 35,
      "contactCreated": 120,
      "creditsSpent": 412.5,
      "creditsRecharged": 500
    },
    "byDate": [
      { "date": "2026-05-01", "byAnalyticType": { "total": 40, "sent": 25, "delivered": 24, "read": 18, "replied": 7, "booked": 1, "contactCreated": 4, "creditsSpent": 13.5, "creditsRecharged": 0 } }
    ]
  }
}

Agency sub-account rollup


Analytics API errors

Analytics endpoints return the standard error envelope:

{
  "success": false,
  "error": "Date range too large. Maximum is 366 days."
}

On an analytics endpoint, an invalid date format or an out-of-range window returns 400, and an unknown campaign_id or agent_id returns 404. Sending both campaign_id and agent_id on an endpoint that accepts either is also a 400 — pass at most one. The PG-only reporting endpoints (Metric series, Conversation outcomes, Agency rollup) return 503 with "error_code": "analytics_unavailable" rather than a 200 full of zeros when the reporting database cannot answer for your account — retry shortly. The shared codes every endpoint can return — 401, 403 (your plan does not include API access, or, on the agency rollup, your account is not Agency/Dev), 429 (rate limit) and 500 — are listed with retry guidance in Errors & Pagination.


Next steps