curl --request POST \
--url https://api.inya.ai/platform/v1/conversations/stats \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"startDate": "2026-03-18",
"endDate": "2026-03-19"
}
'
{
"status": "success",
"requestId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"message": "Conversation stats retrieved successfully.",
"response": {
"startDate": "2026-03-18",
"endDate": "2026-03-19",
"granularity": "day",
"timezone": "IST",
"groupBy": null,
"pageNo": 1,
"pageSize": 100,
"totalCount": 2,
"totalPages": 1,
"data": [
{
"date": "2026-03-18",
"totalCalls": 1402,
"connected": 1071,
"pickupRate": 0.764,
"avgDurationSec": 137,
"callTransfers": 33
},
{
"date": "2026-03-19",
"totalCalls": 1455,
"connected": 1108,
"pickupRate": 0.762,
"avgDurationSec": 137,
"callTransfers": 35
}
]
}
}{
"status": "failure",
"requestId": "<string>",
"message": "Date range exceeds the maximum allowed span of 93 days."
}{
"status": "failure",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "<string>"
}{
"status": "failure",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "<string>"
}Conversations API
Get Aggregated Stats
Get call volume, pickup rate, duration, and transfers across agents and campaigns for a date range
POST
/
v1
/
conversations
/
stats
curl --request POST \
--url https://api.inya.ai/platform/v1/conversations/stats \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"startDate": "2026-03-18",
"endDate": "2026-03-19"
}
'
{
"status": "success",
"requestId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"message": "Conversation stats retrieved successfully.",
"response": {
"startDate": "2026-03-18",
"endDate": "2026-03-19",
"granularity": "day",
"timezone": "IST",
"groupBy": null,
"pageNo": 1,
"pageSize": 100,
"totalCount": 2,
"totalPages": 1,
"data": [
{
"date": "2026-03-18",
"totalCalls": 1402,
"connected": 1071,
"pickupRate": 0.764,
"avgDurationSec": 137,
"callTransfers": 33
},
{
"date": "2026-03-19",
"totalCalls": 1455,
"connected": 1108,
"pickupRate": 0.762,
"avgDurationSec": 137,
"callTransfers": 35
}
]
}
}{
"status": "failure",
"requestId": "<string>",
"message": "Date range exceeds the maximum allowed span of 93 days."
}{
"status": "failure",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "<string>"
}{
"status": "failure",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "<string>"
}What it does: Returns aggregated call metrics for a date range: total calls, connected calls, pickup rate, average duration, and transfers to a human agent. You can bucket results by hour, day, week, or month, split them by agent, campaign, or both, and filter by agent, campaign, call direction, or call status.
It is built for dashboards and operational reporting. You get the totals directly instead of paging through Get Conversation Logs and counting calls yourself.
You need: An API key with the
This request returns one row per day, totalled across all agents and campaigns. If you omit
Each row in Time buckets (
All labels are in IST.
Grouping (
This filter counts outbound calls from either agent whose status is
Each row in
400 Bad Request
403 Forbidden
conversations permission that belongs to a user with the org_admin or developer role. To filter by agent, get botId values from List Agents.
To get the outcome or transcript of a single call, use Get Conversation Statistics (
GET /v1/conversations/{conversationId}/stats). This endpoint returns totals only. It does not return per-call data.Only production calls are counted. Calls in
development or staging are excluded, and there is no environment parameter.Required Permission
conversations
Required Role
org_admin or developer. API keys that belong to any other role, such as QA, receive 403.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
startDate | string | Yes | First day of the range, YYYY-MM-DD. Starts at 00:00:00 IST. |
endDate | string | Yes | Last day of the range, YYYY-MM-DD. Ends at 23:59:59 IST. Must be on or after startDate. Maximum span: 93 days. |
granularity | string | No | Time bucket: hour, day, week, month, or total. Default: total. |
groupBy | array of strings | No | Split results by botId, campaignId, or both. Maximum 2 values. |
filter.botId | string | array | No | Count only calls handled by these agents. |
filter.campaignId | string | array | No | Count only calls from these campaigns. |
filter.type | string | No | Call direction, for example Inbound or Outbound. |
filter.callStatus | string | array | No | Telephony status, for example ANSWERED, NO ANSWER, BUSY, FAILED. Use "NA" to match calls with no status recorded. |
pageNo | integer | No | Page number, 1-based. Default: 1. |
pageSize | integer | No | Rows per page, 1–500. Default: 100. |
Minimum working example
curl -X POST "https://api.inya.ai/platform/v1/conversations/stats" \
-H "x-api-key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"startDate": "2026-03-18",
"endDate": "2026-03-19",
"granularity": "day"
}'
granularity, you get a single row covering the whole range.
How results are shaped
Three request fields decide what comes back:filter → which calls are counted (agent, campaign, direction, status)
granularity → how time is bucketed (hour / day / week / month / total)
groupBy → how each bucket is split (by agent, by campaign, or both)
data is one time bucket × group combination. For example, granularity: "day" over 7 days with groupBy: ["botId"] and 3 active agents returns up to 21 rows.
Time buckets (granularity)
| Value | Time field on each row | Example label |
|---|---|---|
hour | date | "2026-03-18T14:00" |
day | date | "2026-03-18" |
week | week | "16-03-2026 to 22-03-2026" |
month | month | "2026-03" |
total (default) | none | One row per group for the whole range |
The
week label uses DD-MM-YYYY. The other labels use YYYY-MM-DD, so parse week labels separately.Grouping (groupBy)
groupBy | You get |
|---|---|
| omitted | One row per time bucket, across all agents and campaigns |
["botId"] | One row per agent, with botId and botName |
["campaignId"] | One row per campaign. Calls that are not part of a campaign are grouped under "no_campaign". |
["botId", "campaignId"] | One row per agent and campaign pair |
Filters
Each filter field accepts a single value or an array. Within an array, a call matches if it matches any of the values. Across fields, a call must match all of the filters. You can use any filter with anygroupBy.
"filter": {
"botId": ["fb79920229d144608ebf665a10e50275", "a3c1e0d9b2f84f6e9c7d5b4a3f2e1d0c"],
"type": "Outbound",
"callStatus": ["ANSWERED", "NO ANSWER"]
}
ANSWERED or NO ANSWER.
Metrics on every row
| Field | Plain English | Use it for |
|---|---|---|
totalCalls | How many calls matched? | Volume trends, capacity planning |
connected | How many were picked up? (callStatus is ANSWERED) | Reach |
pickupRate | connected ÷ totalCalls, as a decimal (0.764 = 76.4%) | Comparing campaigns, best time to call |
avgDurationSec | Average call length in seconds | Engagement, cost estimates |
callTransfers | Calls handed off to a human agent | Escalation tracking |
Response
Success (200)
Response to the minimum working example:{
"status": "success",
"requestId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"message": "Conversation stats retrieved successfully.",
"response": {
"startDate": "2026-03-18",
"endDate": "2026-03-19",
"granularity": "day",
"timezone": "IST",
"groupBy": null,
"pageNo": 1,
"pageSize": 100,
"totalCount": 2,
"totalPages": 1,
"data": [
{
"date": "2026-03-18",
"totalCalls": 1402,
"connected": 1071,
"pickupRate": 0.764,
"avgDurationSec": 137,
"callTransfers": 33
},
{
"date": "2026-03-19",
"totalCalls": 1455,
"connected": 1108,
"pickupRate": 0.762,
"avgDurationSec": 137,
"callTransfers": 35
}
]
}
}
All response fields
response
| Field | Type | Description |
|---|---|---|
startDate | string | Echo of the request. |
endDate | string | Echo of the request. |
granularity | string | Bucket size applied. total if you omitted it. |
timezone | string | Always "IST". All dates and labels use this timezone. |
groupBy | array | null | Dimensions applied, or null when ungrouped. |
pageNo | integer | Current page. |
pageSize | integer | Rows per page. |
totalCount | integer | Total rows across all pages. This is not the total number of calls. |
totalPages | integer | Total pages at the current pageSize. |
data | array | Result rows. See below. |
Each row in data
| Field | Type | Present when | Description |
|---|---|---|---|
date | string | granularity is hour or day | Bucket label: YYYY-MM-DD or YYYY-MM-DDTHH:00. |
week | string | granularity is week | Week range: DD-MM-YYYY to DD-MM-YYYY. |
month | string | granularity is month | Month label: YYYY-MM. |
botId | string | groupBy includes botId | Agent for this row. |
botName | string | groupBy includes botId | Agent display name. |
campaignId | string | groupBy includes campaignId | Campaign for this row, or "no_campaign". |
totalCalls | integer | Always | Calls matching the query in this bucket and group. |
connected | integer | Always | Calls with callStatus = ANSWERED. |
pickupRate | number | Always | connected ÷ totalCalls, from 0 to 1. |
avgDurationSec | number | Always | Average call duration in seconds. |
callTransfers | integer | Always | Calls transferred to a human agent. |
More examples
Outbound calls by agent and campaign
curl -X POST "https://api.inya.ai/platform/v1/conversations/stats" \
-H "x-api-key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"startDate": "2026-03-18",
"endDate": "2026-03-18",
"granularity": "day",
"groupBy": ["botId", "campaignId"],
"filter": { "type": "Outbound" }
}'
{
"status": "success",
"requestId": "d4e5f6a7-b8c9-0123-def4-567890123456",
"message": "Conversation stats retrieved successfully.",
"response": {
"startDate": "2026-03-18",
"endDate": "2026-03-18",
"granularity": "day",
"timezone": "IST",
"groupBy": ["botId", "campaignId"],
"pageNo": 1,
"pageSize": 100,
"totalCount": 2,
"totalPages": 1,
"data": [
{
"date": "2026-03-18",
"botId": "fb79920229d144608ebf665a10e50275",
"botName": "Payment Reminder",
"campaignId": "camp_9182",
"totalCalls": 1200,
"connected": 920,
"pickupRate": 0.767,
"avgDurationSec": 145,
"callTransfers": 28
},
{
"date": "2026-03-18",
"botId": "fb79920229d144608ebf665a10e50275",
"botName": "Payment Reminder",
"campaignId": "no_campaign",
"totalCalls": 202,
"connected": 151,
"pickupRate": 0.748,
"avgDurationSec": 92,
"callTransfers": 5
}
]
}
}
Quarter total for one agent
curl -X POST "https://api.inya.ai/platform/v1/conversations/stats" \
-H "x-api-key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"startDate": "2026-01-01",
"endDate": "2026-03-31",
"granularity": "total",
"filter": { "botId": "fb79920229d144608ebf665a10e50275" }
}'
{
"status": "success",
"requestId": "e5f6a7b8-c9d0-1234-ef56-789012345678",
"message": "Conversation stats retrieved successfully.",
"response": {
"startDate": "2026-01-01",
"endDate": "2026-03-31",
"granularity": "total",
"timezone": "IST",
"groupBy": null,
"pageNo": 1,
"pageSize": 100,
"totalCount": 1,
"totalPages": 1,
"data": [
{
"totalCalls": 42560,
"connected": 31920,
"pickupRate": 0.75,
"avgDurationSec": 128,
"callTransfers": 312
}
]
}
}
Pagination
Pagination works on rows, not calls. Hourly buckets over a long range, especially with grouping, can produce more than 500 rows. IncreasepageNo until it equals totalPages.
Edge cases
| Scenario | What happens |
|---|---|
startDate equals endDate | Valid. Returns that single day. |
| Range longer than 93 days | 400. Split it into several requests and combine the results (see below). |
| Call is not part of a campaign | When grouping by campaign, it appears under campaignId: "no_campaign". |
filter.callStatus set to "ANSWERED" | pickupRate is always 1, because only answered calls are counted. Leave callStatus unset to measure pickup rate. |
| Your business day is not on IST | Dates are always interpreted in IST, and there is no timezone parameter. Request granularity: "hour" and re-bucket the rows on your side. |
Combining results across pages or requests
You can add uptotalCalls, connected, and callTransfers directly. Do not average pickupRate or avgDurationSec across rows. Instead:
pickupRate= sum ofconnected÷ sum oftotalCallsavgDurationSec= a weighted average across rows, not a simple average of the row values
Errors
| Status | Condition | Message |
|---|---|---|
400 | startDate is after endDate | 'startDate' must be before 'endDate'. |
400 | Range exceeds 93 days | Date range exceeds the maximum allowed span of 93 days. |
400 | Date is not YYYY-MM-DD | Invalid date format. Expected: YYYY-MM-DD. |
401 | API key missing or invalid | See Authentication. |
403 | Key does not have the required role | Access denied. Only org_admin and developer roles can access call statistics. |
422 | Invalid granularity | Input should be 'hour', 'day', 'week', 'month' or 'total'. |
422 | Invalid groupBy value | Input should be 'botId' or 'campaignId'. |
422 | More than 2 groupBy values | Maximum 2 groupBy dimensions allowed. |
422 | pageSize above 500 | Input should be less than or equal to 500. |
422 | startDate or endDate missing | Field required. |
429 | Rate limit exceeded | Retry after the interval in the Retry-After header. |
500 | Server error | An unexpected error occurred while computing call statistics. |
{
"status": "failure",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "Date range exceeds the maximum allowed span of 93 days."
}
{
"status": "failure",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "Access denied. Only org_admin and developer roles can access call statistics."
}
Save the
requestId from every response. You will need it if you contact Gnani support to trace a specific request.Authorizations
API key with 'conversations' permission
Body
application/json
First day of the range (YYYY-MM-DD), from 00:00:00 IST.
Example:
"2026-03-18"
Last day of the range (YYYY-MM-DD), until 23:59:59 IST. Must be on or after startDate. Maximum span 93 days.
Example:
"2026-03-19"
Time bucket size.
Available options:
hour, day, week, month, total Split results by agent, campaign, or both.
Maximum array length:
2Available options:
botId, campaignId Narrows which calls are counted. Each field accepts a single value or an array.
Show child attributes
Show child attributes
Page number (1-based).
Required range:
x >= 1Rows per page.
Required range:
1 <= x <= 500Was this page helpful?