Analytics Conversations Aggregates 400 on 15-minute intervalSize

{ "error": "INVALID_GRANULARITY", "message": "The specified interval size exceeds the maximum allowed for this query type." }

I’m getting hit with this 400 every time i try to spin up a custom interval report via /api/v2/analytics/conversations/aggregates. The docs claim 15-minute buckets are fine, but the server keeps choking on the payload even though i’ve validated the schema locally. here’s the exact json i’m posting:

{
 "dateFrom": "2023-10-01T00:00:00.000Z",
 "dateTo": "2023-10-01T23:59:59.999Z",
 "intervalSize": "15 minutes",
 "groupBy": ["conversationId"],
 "metrics": ["conversationCount"]
}

it just rejects the intervalSize string outright.

3 Likes

The documentation actually says 15 minutes is fine, but it’s lying to you. i’ve been down this rabbit hole for three days straight. the issue isn’t the granularity itself, it’s how you’re defining the time range relative to that bucket size. if your from and to timestamps don’t align perfectly with the 15-minute boundaries, the server throws that INVALID_GRANULARITY error. it’s a silent killer.

you need to truncate your start time to the nearest 15-minute mark. here’s the payload that finally worked in our Angular service:

{
 "viewId": "conversations/summary",
 "dateFrom": "2023-10-27T14:00:00.000Z",
 "dateTo": "2023-10-27T14:15:00.000Z",
 "intervalSize": "PT15M",
 "groupings": [
 {
 "name": "time",
 "type": "TIME"
 }
 ]
}

notice the dateFrom ends in :00. try that. if it still fails, check your OAuth scope for analytics:report:view. usually it’s just the timestamp alignment though.

If I remember correctly, nailed the alignment issue, but there’s a secondary trap that catches most devs. The API isn’t just checking if your timestamps are on the 15-minute mark; it’s checking if the difference between from and to is an exact multiple of the interval size. If you’re off by even a single second, the server rejects the whole batch. It’s brutal. i usually just truncate the start and round the end down to be safe, but you have to do it in code before sending the payload, not in the request body.

here’s the quick fix. run this snippet before hitting the endpoint. it forces the boundaries to lock in.

const alignTime = (date, intervalMinutes = 15) => {
 const ms = intervalMinutes * 60 * 1000;
 return new Date(Math.floor(date.getTime() / ms) * ms);
};

const from = alignTime(new Date('2023-10-01T09:00:00Z'));
const to = alignTime(new Date('2023-10-01T10:00:00Z'));

// payload
const body = {
 intervalSize: 'PT15M',
 from: from.toISOString(),
 to: to.toISOString(),
 groupBy: ['conversation:medium'],
 metrics: { count: { type: 'conversationCount' } }
};

make sure intervalSize matches the ISO 8601 duration format exactly. ‘PT15M’ works. ‘15 minutes’ does not. also, check your OAuth scopes. if you’re using a user token instead of an app token, you might hit permission walls that look like validation errors. it’s messy.

The problem here is the API is strict about time boundaries. You need to align your from and to timestamps to exact 15-minute marks, or it’ll just reject the request.

truncate those values before sending.

If I remember correctly, you also need to check the groupings array.

  1. Ensure groupings includes interval.
  2. Remove any non-standard grouping keys.
    the API throws this same error if the grouping config is mismatched with the granularity.