Skip to main content
Glama

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
NameRequiredDescriptionDefault
end_dateNoCustom end date (ISO format, overrides timeframe)
group_byNoDimensions to group by
measurementYesMeasurement to use (e.g., count, sum, unique)
metric_idYesID of the metric to aggregate
start_dateNoCustom start date (ISO format, overrides timeframe)
timeframeYesTimeframe to use (e.g., last_30_days, this_month)

Implementation Reference

  • 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 }; } },
  • 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)") },
  • 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" } );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ivan-rivera-projects/Klaviyo-MCP-Server-Enhanced'

If you have feedback or need assistance with the MCP directory API, please join our Discord server