query_metric_aggregates
Analyze and aggregate metric data by specifying measurements, timeframes, and grouping dimensions to extract actionable insights for marketing performance.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | Custom end date (ISO format, overrides timeframe) | |
| group_by | No | Dimensions to group by | |
| measurement | Yes | Measurement to use (e.g., count, sum, unique) | |
| metric_id | Yes | ID of the metric to aggregate | |
| start_date | No | Custom start date (ISO format, overrides timeframe) | |
| timeframe | Yes | Timeframe to use (e.g., last_30_days, this_month) |
Implementation Reference
- src/tools/reporting.js:127-285 (handler)The handler function that executes the tool: validates parameters, builds the API payload for /metric-aggregates/ including timeframe filters and grouping, calls Klaviyo API with fallback logic, and returns JSON results or error.async (params) => { try { logger.info(`Querying metric aggregates for metric ID: ${params.metric_id}`); // Validate measurement if (!VALID_MEASUREMENTS.includes(params.measurement)) { logger.warn(`Invalid measurement: ${params.measurement}. Using 'count' instead.`); params.measurement = 'count'; } // Create payload const payload = { data: { type: "metric-aggregate", attributes: { metric_id: params.metric_id, measurements: [params.measurement], interval: "day", filter: [], timezone: "UTC" } } }; // Use custom dates if provided, otherwise use timeframe parameter if (params.start_date && params.end_date) { // Use custom date range const startDateStr = params.start_date.split('T')[0]; const endDateStr = params.end_date.split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using custom date range: ${startDateStr} to ${endDateStr}`); } else if (TIMEFRAME_OPTIONS[params.timeframe]) { // Use predefined timeframe if valid if (params.timeframe === "last_30_days") { const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - 30); const startDateStr = startDate.toISOString().split('T')[0]; const endDateStr = endDate.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using timeframe: ${params.timeframe} (${startDateStr} to ${endDateStr})`); } else if (params.timeframe === "this_month") { const now = new Date(); const firstDay = new Date(now.getFullYear(), now.getMonth(), 1); const startDateStr = firstDay.toISOString().split('T')[0]; const endDateStr = now.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using timeframe: ${params.timeframe} (${startDateStr} to ${endDateStr})`); } else { logger.debug(`Using predefined timeframe: ${params.timeframe}`); payload.data.attributes.timeframe = { key: params.timeframe }; } } else { // Default to last 7 days if timeframe is not recognized const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - 7); const startDateStr = startDate.toISOString().split('T')[0]; const endDateStr = endDate.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using default 7-day range: ${startDateStr} to ${endDateStr}`); } if (params.group_by) { payload.data.attributes.by = params.group_by; logger.debug(`Grouping by: ${params.group_by.join(', ')}`); } logger.debug('Metric aggregates request payload', payload); // Define the fallback function const fallbackFn = async (error) => { logger.warn(`Error querying metric aggregates: ${error.message}. Attempting fallback.`); // Simplified fallback payload with minimal parameters const fallbackPayload = { data: { type: "metric-aggregate", attributes: { metric_id: params.metric_id, measurements: ["count"], // Default to count measurement interval: "day", filter: [], timezone: "UTC" } } }; // Use a default time range for the fallback (last 7 days) const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - 7); const startDateStr = startDate.toISOString().split('T')[0]; const endDateStr = endDate.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); fallbackPayload.data.attributes.filter.push(...dateFilters); logger.debug('Metric aggregates fallback payload', fallbackPayload); const fallbackResults = await klaviyoClient.post('/metric-aggregates/', fallbackPayload); logger.info(`Successfully retrieved basic metric aggregates for metric ID: ${params.metric_id} using fallback`); return fallbackResults; }; // Ensure endpoint has trailing slash for consistency const results = await klaviyoClient.post('/metric-aggregates/', payload, fallbackFn); logger.info(`Successfully retrieved metric aggregates for metric ID: ${params.metric_id}`); return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; } catch (error) { logger.error(`Failed to query metric aggregates (including fallback attempt): ${error.message}`, { metricId: params.metric_id }); return { content: [{ type: "text", text: `Error querying metric aggregates (including fallback attempt): ${error.message}` }], isError: true }; } },
- src/tools/reporting.js:119-126 (schema)Zod schema defining the input parameters for the query_metric_aggregates tool.{ metric_id: z.string().describe("ID of the metric to aggregate"), measurement: z.string().describe("Measurement to use (e.g., count, sum, unique)"), timeframe: z.string().describe("Timeframe to use (e.g., last_30_days, this_month)"), group_by: z.array(z.string()).optional().describe("Dimensions to group by"), start_date: z.string().optional().describe("Custom start date (ISO format, overrides timeframe)"), end_date: z.string().optional().describe("Custom end date (ISO format, overrides timeframe)") },
- src/tools/reporting.js:118-287 (registration)Registration of the query_metric_aggregates tool within the registerReportingTools function using server.tool."query_metric_aggregates", { metric_id: z.string().describe("ID of the metric to aggregate"), measurement: z.string().describe("Measurement to use (e.g., count, sum, unique)"), timeframe: z.string().describe("Timeframe to use (e.g., last_30_days, this_month)"), group_by: z.array(z.string()).optional().describe("Dimensions to group by"), start_date: z.string().optional().describe("Custom start date (ISO format, overrides timeframe)"), end_date: z.string().optional().describe("Custom end date (ISO format, overrides timeframe)") }, async (params) => { try { logger.info(`Querying metric aggregates for metric ID: ${params.metric_id}`); // Validate measurement if (!VALID_MEASUREMENTS.includes(params.measurement)) { logger.warn(`Invalid measurement: ${params.measurement}. Using 'count' instead.`); params.measurement = 'count'; } // Create payload const payload = { data: { type: "metric-aggregate", attributes: { metric_id: params.metric_id, measurements: [params.measurement], interval: "day", filter: [], timezone: "UTC" } } }; // Use custom dates if provided, otherwise use timeframe parameter if (params.start_date && params.end_date) { // Use custom date range const startDateStr = params.start_date.split('T')[0]; const endDateStr = params.end_date.split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using custom date range: ${startDateStr} to ${endDateStr}`); } else if (TIMEFRAME_OPTIONS[params.timeframe]) { // Use predefined timeframe if valid if (params.timeframe === "last_30_days") { const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - 30); const startDateStr = startDate.toISOString().split('T')[0]; const endDateStr = endDate.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using timeframe: ${params.timeframe} (${startDateStr} to ${endDateStr})`); } else if (params.timeframe === "this_month") { const now = new Date(); const firstDay = new Date(now.getFullYear(), now.getMonth(), 1); const startDateStr = firstDay.toISOString().split('T')[0]; const endDateStr = now.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using timeframe: ${params.timeframe} (${startDateStr} to ${endDateStr})`); } else { logger.debug(`Using predefined timeframe: ${params.timeframe}`); payload.data.attributes.timeframe = { key: params.timeframe }; } } else { // Default to last 7 days if timeframe is not recognized const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - 7); const startDateStr = startDate.toISOString().split('T')[0]; const endDateStr = endDate.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); payload.data.attributes.filter.push(...dateFilters); logger.debug(`Using default 7-day range: ${startDateStr} to ${endDateStr}`); } if (params.group_by) { payload.data.attributes.by = params.group_by; logger.debug(`Grouping by: ${params.group_by.join(', ')}`); } logger.debug('Metric aggregates request payload', payload); // Define the fallback function const fallbackFn = async (error) => { logger.warn(`Error querying metric aggregates: ${error.message}. Attempting fallback.`); // Simplified fallback payload with minimal parameters const fallbackPayload = { data: { type: "metric-aggregate", attributes: { metric_id: params.metric_id, measurements: ["count"], // Default to count measurement interval: "day", filter: [], timezone: "UTC" } } }; // Use a default time range for the fallback (last 7 days) const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - 7); const startDateStr = startDate.toISOString().split('T')[0]; const endDateStr = endDate.toISOString().split('T')[0]; const dateFilters = FILTER_TEMPLATES.dateRange( `${startDateStr}T00:00:00`, `${endDateStr}T23:59:59` ); fallbackPayload.data.attributes.filter.push(...dateFilters); logger.debug('Metric aggregates fallback payload', fallbackPayload); const fallbackResults = await klaviyoClient.post('/metric-aggregates/', fallbackPayload); logger.info(`Successfully retrieved basic metric aggregates for metric ID: ${params.metric_id} using fallback`); return fallbackResults; }; // Ensure endpoint has trailing slash for consistency const results = await klaviyoClient.post('/metric-aggregates/', payload, fallbackFn); logger.info(`Successfully retrieved metric aggregates for metric ID: ${params.metric_id}`); return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; } catch (error) { logger.error(`Failed to query metric aggregates (including fallback attempt): ${error.message}`, { metricId: params.metric_id }); return { content: [{ type: "text", text: `Error querying metric aggregates (including fallback attempt): ${error.message}` }], isError: true }; } }, { description: "Query aggregated metric data for custom analytics reporting" } );