> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useautumn.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Aggregate Events

> Aggregate usage events by time period. Returns usage totals grouped by feature and optionally by a custom property.

export const DynamicResponseExample = ({json, statusCode = "200"}) => {
  const toCamelCase = str => {
    return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
  };
  const convertKeysToCamelCase = obj => {
    if (Array.isArray(obj)) {
      return obj.map(item => convertKeysToCamelCase(item));
    }
    if (obj !== null && typeof obj === "object") {
      return Object.keys(obj).reduce((acc, key) => {
        const camelKey = toCamelCase(key);
        acc[camelKey] = convertKeysToCamelCase(obj[key]);
        return acc;
      }, {});
    }
    return obj;
  };
  const [isTypeScript, setIsTypeScript] = useState(() => {
    if (typeof window !== "undefined") {
      try {
        const lang = localStorage.getItem("code");
        return JSON.parse(lang) === "typescript";
      } catch {
        return true;
      }
    }
    return true;
  });
  useEffect(() => {
    const onMintlifyStorage = event => {
      if (event.detail?.key === "code") {
        try {
          const value = JSON.parse(event.detail.value);
          setIsTypeScript(value === "typescript");
        } catch {}
      }
    };
    const pollInterval = setInterval(() => {
      try {
        const lang = localStorage.getItem("code");
        const value = JSON.parse(lang);
        setIsTypeScript(value === "typescript");
      } catch {}
    }, 300);
    document.addEventListener("mintlify-localstorage", onMintlifyStorage);
    return () => {
      document.removeEventListener("mintlify-localstorage", onMintlifyStorage);
      clearInterval(pollInterval);
    };
  }, []);
  const camelCaseJson = useMemo(() => convertKeysToCamelCase(json), [json]);
  const snakeCaseString = JSON.stringify(json, null, 2);
  const camelCaseString = JSON.stringify(camelCaseJson, null, 2);
  return <ResponseExample>
			{isTypeScript ? <CodeBlock language="json" filename={statusCode}>
					{camelCaseString}
				</CodeBlock> : <CodeBlock language="json" filename={statusCode}>
					{snakeCaseString}
				</CodeBlock>}
		</ResponseExample>;
};

export const DynamicResponseField = ({children, name, ...props}) => {
  const convertToCamelCase = str => {
    if (typeof str !== "string") return str;
    return str.replace(/[_-](\w)/g, (_, c) => c.toUpperCase());
  };
  const [lang, setLang] = useState(() => {
    if (typeof window !== "undefined") {
      const stored = localStorage.getItem("code");
      return stored || '"typescript"';
    }
    return '"typescript"';
  });
  useEffect(() => {
    const onMintlifyStorage = event => {
      const key = event.detail?.key;
      if (key === "code") {
        setLang(event.detail.value);
      }
    };
    const pollInterval = setInterval(() => {
      const current = localStorage.getItem("code");
      if (current && current !== lang) {
        setLang(current);
      }
    }, 500);
    document.addEventListener("mintlify-localstorage", onMintlifyStorage);
    return () => {
      document.removeEventListener("mintlify-localstorage", onMintlifyStorage);
      clearInterval(pollInterval);
    };
  }, [lang]);
  const resolvedName = useMemo(() => {
    try {
      const value = JSON.parse(lang);
      const useCamelCase = value === "typescript";
      return useCamelCase ? convertToCamelCase(name) : name;
    } catch {
      return name;
    }
  }, [name, lang]);
  return <ResponseField name={resolvedName} {...props}>
			{children}
		</ResponseField>;
};

export const DynamicParamField = ({children, body, path, ...props}) => {
  const convertToCamelCase = str => {
    if (typeof str !== "string") return str;
    return str.replace(/[_-](\w)/g, (_, c) => c.toUpperCase());
  };
  const [lang, setLang] = useState(() => {
    if (typeof window !== "undefined") {
      const stored = localStorage.getItem("code");
      return stored || '"typescript"';
    }
    return '"typescript"';
  });
  useEffect(() => {
    const onMintlifyStorage = event => {
      const key = event.detail?.key;
      if (key === "code") {
        setLang(event.detail.value);
      }
    };
    const pollInterval = setInterval(() => {
      const current = localStorage.getItem("code");
      if (current && current !== lang) {
        setLang(current);
      }
    }, 500);
    document.addEventListener("mintlify-localstorage", onMintlifyStorage);
    return () => {
      document.removeEventListener("mintlify-localstorage", onMintlifyStorage);
      clearInterval(pollInterval);
    };
  }, [lang]);
  const resolvedBody = useMemo(() => {
    try {
      const value = JSON.parse(lang);
      const useCamelCase = value === "typescript";
      return useCamelCase ? convertToCamelCase(body) : body;
    } catch {
      return body;
    }
  }, [body, lang]);
  const resolvedPath = useMemo(() => {
    try {
      const value = JSON.parse(lang);
      const useCamelCase = value === "typescript";
      return useCamelCase ? convertToCamelCase(path) : path;
    } catch {
      return path;
    }
  }, [path, lang]);
  return <ParamField body={resolvedBody} path={resolvedPath} {...props}>
			{children}
		</ParamField>;
};

Aggregate usage events by time period. Returns usage totals grouped by feature and optionally by a custom property.

## Working with Properties

When tracking events, you can attach custom properties that can later be used for grouping aggregations:

```typescript theme={null}
// Track an event with properties
await autumn.track({
  customerId: "cus_123",
  featureId: "api_calls",
  value: 1,
  properties: {
    model: "gpt-4",
    source: "api",
    region: "us-east"
  }
});
```

You can then aggregate events grouped by any property using the `group_by` parameter:

```typescript theme={null}
const result = await autumn.events.aggregate({
  customerId: "cus_123",
  featureId: "api_calls",
  range: "7d",
  groupBy: "properties.model"  // Group by the "model" property
});
```

### Special Group By Operators

In addition to custom properties, you can group by built-in columns using `$`-prefixed operators:

* `$customer_id` -- Group results by customer ID. Useful when aggregating across all customers (i.e. no `customer_id` specified).
* `$entity_id` -- Group results by entity ID. Useful for seeing usage broken down per entity.

```typescript theme={null}
// Aggregate across all customers, grouped by customer
const result = await autumn.events.aggregate({
  featureId: "api_calls",
  range: "7d",
  groupBy: "$customer_id"
});

// Aggregate for a customer, grouped by entity
const result = await autumn.events.aggregate({
  customerId: "cus_123",
  featureId: "api_calls",
  range: "7d",
  groupBy: "$entity_id"
});
```

## Response Format

The response structure changes based on whether `group_by` is provided:

### Without `group_by` (Flat Response)

When no grouping is specified, `values` contains the aggregated sum for each feature:

```json theme={null}
{
  "list": [
    {
      "period": 1762905600000,
      "values": {
        "api_calls": 150,
        "messages": 45
      }
    }
  ],
  "total": {
    "api_calls": { "count": 10, "sum": 150 },
    "messages": { "count": 5, "sum": 45 }
  }
}
```

### With `group_by` (Grouped Response)

When grouping is specified, `values` contains the total sum while `grouped_values` breaks down values by group:

```json theme={null}
{
  "list": [
    {
      "period": 1762905600000,
      "values": {
        "api_calls": 150
      },
      "grouped_values": {
        "api_calls": {
          "gpt-4": 100,
          "gpt-3.5": 50
        }
      }
    }
  ],
  "total": {
    "api_calls": { "count": 10, "sum": 150 }
  }
}
```

<Note>
  The `grouped_values` field is only present when `group_by` is provided in the request.
</Note>

### Body Parameters

<DynamicParamField body="customer_id" type="string">
  Customer ID to aggregate events for
</DynamicParamField>

<DynamicParamField body="entity_id" type="string">
  Entity ID to filter aggregated events for (e.g., per-seat or per-resource limits)
</DynamicParamField>

<DynamicParamField body="feature_id" type="string" required>
  Feature ID(s) to aggregate events for
</DynamicParamField>

<DynamicParamField body="group_by" type="string">
  Property to group events by (e.g. "properties.region"), or "$customer_id" / "$entity\_id" / "\$plan\_id" to group by those columns
</DynamicParamField>

<DynamicParamField body="range" type="'24h' | '7d' | '30d' | '90d' | 'last_cycle' | '1bc' | '3bc'">
  Time range to aggregate events for. Either range or custom\_range must be provided
</DynamicParamField>

<DynamicParamField body="bin_size" type="'day' | 'hour' | 'week' | 'month'">
  Size of the time bins to aggregate events for. Defaults to hour if range is 24h, otherwise day
</DynamicParamField>

<DynamicParamField body="custom_range" type="object">
  Custom time range to aggregate events for. If provided, range must not be provided

  <Expandable title="properties">
    <DynamicParamField body="start" type="number" required />

    <DynamicParamField body="end" type="number" required />
  </Expandable>
</DynamicParamField>

<DynamicParamField body="filter_by.{key}" type="string">
  Filter events by property values, e.g. \{"model": "gpt-4", "region": "us"}. Maximum 5 filters.
</DynamicParamField>

<DynamicParamField body="max_groups" type="integer">
  Maximum number of distinct group values to return per time bin when using group\_by. Remaining values are bundled into an 'Other' bucket. Defaults to 9
</DynamicParamField>

### Response

<DynamicResponseField name="list" type="object[]">
  Array of time periods with aggregated values

  <Expandable title="properties">
    <DynamicResponseField name="period" type="number">
      Unix timestamp (epoch ms) for this time period
    </DynamicResponseField>

    <DynamicResponseField name="values.{key}" type="number">
      Aggregated values per feature: \{ \[featureId]: number }
    </DynamicResponseField>

    <DynamicResponseField name="grouped_values" type="object">
      Values broken down by group (only present when group\_by is used): \{ \[featureId]: \{ \[groupValue]: number } }

      <Expandable title="properties">
        <DynamicResponseField name="{key}.{key}" type="number" />
      </Expandable>
    </DynamicResponseField>
  </Expandable>
</DynamicResponseField>

<DynamicResponseField name="total.{key}" type="object">
  Total aggregations per feature. Keys are feature IDs, values contain count and sum.

  <Expandable title="properties">
    <DynamicResponseField name="count" type="number">
      Number of events for this feature
    </DynamicResponseField>

    <DynamicResponseField name="sum" type="number">
      Sum of event values for this feature
    </DynamicResponseField>
  </Expandable>
</DynamicResponseField>

<ResponseExample>
  ```json 200 theme={null}
  {
    "list": [
      {
        "period": 1762905600000,
        "values": {
          "messages": 10,
          "sessions": 3
        }
      },
      {
        "period": 1762992000000,
        "values": {
          "messages": 3,
          "sessions": 12
        }
      }
    ],
    "total": {
      "messages": {
        "count": 2,
        "sum": 13
      },
      "sessions": {
        "count": 2,
        "sum": 15
      }
    }
  }
  ```
</ResponseExample>


## OpenAPI

````yaml openapi POST /v1/events.aggregate
openapi: 3.1.0
info:
  title: Autumn API
  version: 2.3.0
servers:
  - url: https://api.useautumn.com
    description: Production server
security:
  - secretKey: []
paths:
  /v1/events.aggregate:
    post:
      tags:
        - events
      description: >-
        Aggregate usage events by time period. Returns usage totals grouped by
        feature and optionally by a custom property.
      operationId: aggregateEvents
      parameters:
        - name: x-api-version
          in: header
          required: true
          schema:
            type: string
            default: 2.3.0
          x-speakeasy-globals-hidden: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                customer_id:
                  type: string
                  minLength: 1
                  description: Customer ID to aggregate events for
                entity_id:
                  type: string
                  minLength: 1
                  description: >-
                    Entity ID to filter aggregated events for (e.g., per-seat or
                    per-resource limits)
                feature_id:
                  anyOf:
                    - type: string
                      minLength: 1
                    - type: array
                      items:
                        type: string
                        minLength: 1
                  description: Feature ID(s) to aggregate events for
                group_by:
                  type: string
                  description: >-
                    Property to group events by (e.g. "properties.region"), or
                    "$customer_id" / "$entity_id" / "$plan_id" to group by those
                    columns
                range:
                  enum:
                    - 24h
                    - 7d
                    - 30d
                    - 90d
                    - last_cycle
                    - 1bc
                    - 3bc
                  type: string
                  description: >-
                    Time range to aggregate events for. Either range or
                    custom_range must be provided
                bin_size:
                  enum:
                    - day
                    - hour
                    - week
                    - month
                  type: string
                  default: day
                  description: >-
                    Size of the time bins to aggregate events for. Defaults to
                    hour if range is 24h, otherwise day
                custom_range:
                  type: object
                  properties:
                    start:
                      type: number
                    end:
                      type: number
                  required:
                    - start
                    - end
                  description: >-
                    Custom time range to aggregate events for. If provided,
                    range must not be provided
                filter_by:
                  type: object
                  propertyNames:
                    type: string
                  additionalProperties:
                    type: string
                  description: >-
                    Filter events by property values, e.g. {"model": "gpt-4",
                    "region": "us"}. Maximum 5 filters.
                max_groups:
                  type: integer
                  minimum: 1
                  maximum: 250
                  description: >-
                    Maximum number of distinct group values to return per time
                    bin when using group_by. Remaining values are bundled into
                    an 'Other' bucket. Defaults to 9
              required:
                - feature_id
              title: EventsAggregateParams
              examples:
                - customer_id: cus_123
                  feature_id: api_calls
                  range: 30d
                  bin_size: day
                - customer_id: cus_123
                  feature_id:
                    - api_calls
                    - messages
                  range: 7d
                  group_by: properties.model
            example:
              customer_id: cus_123
              feature_id: api_calls
              range: 30d
              bin_size: day
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  list:
                    type: array
                    items:
                      type: object
                      properties:
                        period:
                          type: number
                          description: Unix timestamp (epoch ms) for this time period
                        values:
                          type: object
                          propertyNames:
                            type: string
                          additionalProperties:
                            type: number
                          description: >-
                            Aggregated values per feature: { [featureId]: number
                            }
                        grouped_values:
                          type: object
                          propertyNames:
                            type: string
                          additionalProperties:
                            type: object
                            propertyNames:
                              type: string
                            additionalProperties:
                              type: number
                          description: >-
                            Values broken down by group (only present when
                            group_by is used): { [featureId]: { [groupValue]:
                            number } }
                      required:
                        - period
                        - values
                    description: Array of time periods with aggregated values
                  total:
                    type: object
                    propertyNames:
                      type: string
                    additionalProperties:
                      type: object
                      properties:
                        count:
                          type: number
                          description: Number of events for this feature
                        sum:
                          type: number
                          description: Sum of event values for this feature
                      required:
                        - count
                        - sum
                    description: >-
                      Total aggregations per feature. Keys are feature IDs,
                      values contain count and sum.
                required:
                  - list
                  - total
                examples:
                  - list:
                      - period: 1762905600000
                        values:
                          messages: 10
                          sessions: 3
                      - period: 1762992000000
                        values:
                          messages: 3
                          sessions: 12
                    total:
                      messages:
                        count: 2
                        sum: 13
                      sessions:
                        count: 2
                        sum: 15
                  - list:
                      - period: 1762905600000
                        values:
                          messages: 10
                          sessions: 3
                        grouped_values:
                          messages:
                            api: 5
                            web: 5
                          sessions:
                            api: 2
                            web: 1
                      - period: 1762992000000
                        values:
                          messages: 3
                          sessions: 12
                        grouped_values:
                          messages:
                            api: 1
                            web: 2
                          sessions:
                            api: 10
                            web: 2
                    total:
                      messages:
                        count: 2
                        sum: 13
                      sessions:
                        count: 2
                        sum: 15
              example:
                list:
                  - period: 1762905600000
                    values:
                      messages: 10
                      sessions: 3
                  - period: 1762992000000
                    values:
                      messages: 3
                      sessions: 12
                total:
                  messages:
                    count: 2
                    sum: 13
                  sessions:
                    count: 2
                    sum: 15
      x-codeSamples:
        - lang: typescript
          label: Typescript (SDK)
          source: |-
            import { Autumn } from 'autumn-js'

            const autumn = new Autumn()

            const result = await autumn.events.aggregate({
              customerId: "cus_123",
              featureId: "api_calls",
              range: "30d",
            });
        - lang: python
          label: Python (SDK)
          source: |-
            from autumn_sdk import Autumn

            autumn = Autumn(secret_key="am_sk_test...")

            res = autumn.events.aggregate(
                feature_id="api_calls",
                customer_id="cus_123",
                range="30d",
                bin_size="day",
            )
components:
  securitySchemes:
    secretKey:
      type: http
      scheme: bearer
      bearerFormat: JWT

````