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

# List Events

> Retrieve a paginated list of events with optional attribution filtering

## Overview

This endpoint allows you to retrieve a list of events from Cometly with powerful filtering capabilities including date ranges, attribution models, sources, and field selection. Results are cursor-paginated for efficient data retrieval.

## Query Parameters

### Required Parameters

<ParamField query="start_date" type="string" required>
  Start date for the query range in `YYYY-MM-DD HH:MM:SS` format. The timestamp is interpreted in your space's timezone.
  Example: `2024-01-01 00:00:00`
</ParamField>

<ParamField query="end_date" type="string" required>
  End date for the query range in `YYYY-MM-DD HH:MM:SS` format. Must be after start\_date and is interpreted in your space's timezone.
  Example: `2024-01-31 23:59:59`
</ParamField>

### Optional Parameters

<ParamField query="query_mode" type="string" default="profile">
  Determines whether to report metrics by contact or company level.

  Options:

  * `profile` - Contact-level events (default)
  * `company` - Company-level events
</ParamField>

<ParamField query="event_names" type="string[]" placeholder="['purchase', 'lead_generated']">
  Filter results to specific event names. Defaults to all events when omitted.

  **Limits:** Minimum 1, maximum 10 event names. Duplicate values are not allowed.

  Values:

  * `add_payment_info`
  * `add_to_cart`
  * `complete_registration`
  * `contact`
  * `initiate_checkout`
  * `lead_generated`
  * `purchase`
  * `schedule`
  * `sign_up`
  * `start_trial`
  * `submit_application`
  * `subscribe`
  * `upsell_purchase`
  * `view_content`
  * `webinar_registration`

  Custom events: `custom_event_1` through `custom_event_50`.
</ParamField>

<ParamField query="sources" type="string[]" placeholder="['facebook_ads', 'google_ads']">
  Filter events by traffic sources. When provided, `attribution_model` and `attribution_window` become required.

  **Limits:** Minimum 1, maximum 15 sources. Duplicate values are not allowed.

  <Accordion title="Available sources">
    **Paid Ads:**
    `facebook_ads`, `google_ads`, `linkedin_ads`, `tiktok_ads`, `youtube_ads`, `instagram_ads`, `bing_ads`, `yahoo_ads`, `pinterest_ads`, `reddit_ads`, `snapchat_ads`, `telegram_ads`, `twitch_ads`, `x_ads`, `quora_ads`, `duckduckgo_ads`

    **Organic:**
    `facebook_organic`, `google_organic`, `linkedin_organic`, `tiktok_organic`, `youtube_organic`, `instagram_organic`, `bing_organic`, `yahoo_organic`, `pinterest_organic`, `reddit_organic`, `snapchat_organic`, `telegram_organic`, `twitch_organic`, `x_organic`, `quora_organic`, `duckduckgo_organic`, `messenger_organic`, `brave_organic`, `threads_organic`

    **AI Platforms:**
    `ai_chat_gpt`, `ai_perplexity`, `ai_copilot`, `ai_claude`, `ai_grok`, `ai_gemini`, `ai_deepseek`

    **Other:**
    `email`, `sms`, `referral`, `direct`, `shop_app`, `substack`, `capterra`, `trustpilot`, `g2`, `yelp`
  </Accordion>
</ParamField>

<ParamField query="attribution_model" type="string">
  Attribution model to use for filtering events. Required when `sources` is provided.

  Options:

  * `first_touch` - First interaction attribution
  * `last_touch` - Last interaction attribution
  * `linear` - Equal credit across all touchpoints
  * `first_platform_touch` - First paid platform touch
  * `last_platform_touch` - Last paid platform touch
  * `linear_paid` - Linear attribution across paid touchpoints only
  * `u_shaped` - 40% first, 40% last, 20% middle touchpoints
  * `last_non_direct_touch` - Last touch excluding direct traffic
</ParamField>

<ParamField query="attribution_window" type="integer">
  Attribution lookback window in days. Required when `sources` is provided.

  Options: `0` (LTV), `1`, `7`, `14`, `30`, `60`, `90`
</ParamField>

<ParamField query="fields" type="string[]" default="['id', 'event_time_utc']" placeholder="['id', 'event_name', 'amount']">
  Specify which fields to include in the response.

  **Limits:** Minimum 1, maximum 20 fields. Duplicate values are not allowed.

  **Note:** `id` and `event_time_utc` are always included in the response. When `sources` are provided for attribution, `touchpoint_id` is also always included. These fields are required for cursor pagination to work properly.

  Available fields:

  * `profile_id` - Contact profile identifier
  * `company_id` - Company identifier
  * `space_id` - Space identifier
  * `event_name` - Event name
  * `configured_name` - The configured name of the event. For custom events (`custom_event_1` through `custom_event_50`), this is the user-configured name. For standard events, this equals `event_name`.
  * `amount` - Transaction amount (with attribution, this is the partial amount credited to the touchpoint)
  * `is_upsell` - Upsell flag
  * `ad_id` - Platform-specific ad identifier (requires `sources` to be provided)
  * `ad_name` - Ad name from the ad platform (requires `sources` to be provided)
  * `adset_id` - Platform-specific ad set identifier (requires `sources` to be provided)
  * `adset_name` - Ad set name from the ad platform (requires `sources` to be provided)
  * `campaign_id` - Platform-specific campaign identifier (requires `sources` to be provided)
  * `campaign_name` - Campaign name from the ad platform (requires `sources` to be provided)
  * `account_id` - Platform-specific ad account identifier (requires `sources` to be provided)
  * `account_name` - Ad account name from the ad platform (requires `sources` to be provided)
  * `order_id` - Order identifier
  * `order_name` - Order name
  * `event_url` - The full URL where the event occurred

  **Auto-included fields (not user-requestable):**

  * `id` - Event identifier (always included for cursor pagination)
  * `event_time_utc` - Event timestamp in UTC (always included for cursor pagination)
  * `touchpoint_id` - Touchpoint identifier (automatically included when sources are provided for cursor pagination)
  * `source` - Traffic source (automatically included when any ad hierarchy field is requested: `ad_id`, `ad_name`, `adset_id`, `adset_name`, `campaign_id`, `campaign_name`, `account_id`, `account_name`)
</ParamField>

<ParamField query="per_page" type="integer" default="200">
  Number of events to return per page. Minimum: 1, Maximum: 4000
</ParamField>

<ParamField query="cursor" type="string">
  Pagination cursor from a previous response. Use this to fetch the next page of results.
</ParamField>

## Response

### Success Response

The response follows Laravel's cursor pagination structure:

<ResponseField name="data" type="array">
  Array of event objects with the requested fields
</ResponseField>

<ResponseField name="path" type="string">
  The base URL path for the endpoint
</ResponseField>

<ResponseField name="per_page" type="integer">
  Number of items per page
</ResponseField>

<ResponseField name="next_cursor" type="string | null">
  Cursor for the next page of results. `null` if there are no more pages.
</ResponseField>

<ResponseField name="next_page_url" type="string | null">
  Full URL for the next page of results. `null` if there are no more pages.
</ResponseField>

<ResponseField name="prev_cursor" type="string | null">
  Cursor for the previous page of results. `null` if on the first page.
</ResponseField>

<ResponseField name="prev_page_url" type="string | null">
  Full URL for the previous page of results. `null` if on the first page.
</ResponseField>

### Error Response

<ResponseField name="message" type="string">
  Error description explaining what went wrong
</ResponseField>

## Example Requests

<CodeGroup>
  ```bash cURL theme={null}
  # Basic request with only required parameters
  curl -G "https://app.cometly.com/public-api/v1/events" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d "start_date=2024-01-01 00:00:00" \
    -d "end_date=2024-01-31 23:59:59"

  # Request with attribution filtering and specific fields
  curl -G "https://app.cometly.com/public-api/v1/events" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d "start_date=2024-01-01 00:00:00" \
    -d "end_date=2024-01-31 23:59:59" \
    -d "query_mode=profile" \
    -d "event_names[]=purchase" \
    -d "event_names[]=sign_up" \
    -d "sources[]=facebook_ads" \
    -d "sources[]=google_ads" \
    -d "attribution_model=last_touch" \
    -d "attribution_window=30" \
    -d "fields[]=id" \
    -d "fields[]=event_name" \
    -d "fields[]=amount" \
    -d "fields[]=event_time_utc" \
    -d "per_page=100"

  # Pagination request using cursor
  curl -G "https://app.cometly.com/public-api/v1/events" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d "start_date=2024-01-01 00:00:00" \
    -d "end_date=2024-01-31 23:59:59" \
    -d "cursor=eyJldmVudF90aW1lX3V0YyI6IjIwMjQtMDEtMTUgMTI..."
  ```

  ```javascript JavaScript theme={null}
  // Basic request with only required parameters
  const params = new URLSearchParams({
    start_date: '2024-01-01 00:00:00',
    end_date: '2024-01-31 23:59:59'
  });

  const response = await fetch(`https://app.cometly.com/public-api/v1/events?${params}`, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }
  });

  const data = await response.json();

  // Request with attribution filtering and specific fields
  const advancedParams = new URLSearchParams({
    start_date: '2024-01-01 00:00:00',
    end_date: '2024-01-31 23:59:59',
    query_mode: 'profile',
    attribution_model: 'last_touch',
    attribution_window: '30',
    per_page: '100'
  });

  // Add array parameters
  ['purchase', 'sign_up'].forEach(eventName =>
    advancedParams.append('event_names[]', eventName)
  );

  ['facebook_ads', 'google_ads'].forEach(source =>
    advancedParams.append('sources[]', source)
  );

  ['id', 'event_name', 'amount', 'event_time_utc'].forEach(field =>
    advancedParams.append('fields[]', field)
  );

  const advancedResponse = await fetch(`https://app.cometly.com/public-api/v1/events?${advancedParams}`, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }
  });

  const advancedData = await advancedResponse.json();

  // Pagination using cursor from previous response
  if (advancedData.next_cursor) {
    const nextParams = new URLSearchParams({
      start_date: '2024-01-01 00:00:00',
      end_date: '2024-01-31 23:59:59',
      cursor: advancedData.next_cursor
    });

    const nextPage = await fetch(`https://app.cometly.com/public-api/v1/events?${nextParams}`, {
      method: 'GET',
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      }
    });
  }
  ```

  ```php PHP theme={null}
  <?php
  // Basic request with only required parameters
  $baseUrl = 'https://app.cometly.com/public-api/v1/events';
  $params = http_build_query([
      'start_date' => '2024-01-01 00:00:00',
      'end_date' => '2024-01-31 23:59:59'
  ]);

  $headers = [
      'Authorization: Bearer YOUR_API_KEY',
      'Accept: application/json',
      'Content-Type: application/json'
  ];

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $baseUrl . '?' . $params);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  $data = json_decode($response, true);
  curl_close($ch);

  // Request with attribution filtering and specific fields
  $advancedParams = [
      'start_date' => '2024-01-01 00:00:00',
      'end_date' => '2024-01-31 23:59:59',
      'query_mode' => 'profile',
      'event_names' => ['purchase', 'sign_up'],
      'sources' => ['facebook_ads', 'google_ads'],
      'attribution_model' => 'last_touch',
      'attribution_window' => 30,
      'fields' => ['id', 'event_name', 'amount', 'event_time_utc'],
      'per_page' => 100
  ];

  $queryString = http_build_query($advancedParams);

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $baseUrl . '?' . $queryString);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  $data = json_decode($response, true);
  curl_close($ch);

  // Pagination using cursor
  if (!empty($data['next_cursor'])) {
      $nextParams = http_build_query([
          'start_date' => '2024-01-01 00:00:00',
          'end_date' => '2024-01-31 23:59:59',
          'cursor' => $data['next_cursor']
      ]);

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $baseUrl . '?' . $nextParams);
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

      $nextResponse = curl_exec($ch);
      curl_close($ch);
  }
  ?>
  ```

  ```python Python theme={null}
  import requests
  from urllib.parse import urlencode

  # Basic request with only required parameters
  base_url = 'https://app.cometly.com/public-api/v1/events'
  headers = {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
  }

  params = {
      'start_date': '2024-01-01 00:00:00',
      'end_date': '2024-01-31 23:59:59'
  }

  response = requests.get(base_url, headers=headers, params=params)
  data = response.json()

  # Request with attribution filtering and specific fields
  advanced_params = {
      'start_date': '2024-01-01 00:00:00',
      'end_date': '2024-01-31 23:59:59',
      'query_mode': 'profile',
      'event_names[]': ['purchase', 'sign_up'],
      'sources[]': ['facebook_ads', 'google_ads'],
      'attribution_model': 'last_touch',
      'attribution_window': 30,
      'fields[]': ['id', 'event_name', 'amount', 'event_time_utc'],
      'per_page': 100
  }

  response = requests.get(base_url, headers=headers, params=advanced_params)
  data = response.json()

  # Pagination using cursor from previous response
  if data.get('next_cursor'):
      next_params = {
          'start_date': '2024-01-01 00:00:00',
          'end_date': '2024-01-31 23:59:59',
          'cursor': data['next_cursor']
      }

      next_response = requests.get(base_url, headers=headers, params=next_params)
      next_data = next_response.json()
  ```
</CodeGroup>

## Status Codes

| Status Code | Description                                                                               |
| ----------- | ----------------------------------------------------------------------------------------- |
| 200         | Events successfully retrieved                                                             |
| 401         | Missing or invalid API key                                                                |
| 403         | API key doesn't have permission or subscription is inactive                               |
| 422         | Invalid parameters provided (check error message for details)                             |
| 429         | Too many requests - rate limit exceeded. See [Rate Limiting](/introduction/rate-limiting) |

## Notes

* **Rate Limit**: This endpoint has a limit of **7 requests per minute** per Space. See [Rate Limiting](/introduction/rate-limiting) for details.
* When `sources` are provided, attribution filtering is applied and only events matching the attribution criteria are returned
* **Attribution Breakdown:** With multi-touch attribution models (linear, u\_shaped, linear\_paid), each event may return **multiple rows** - one per attributed touchpoint. Each row contains the touchpoint's partial credit (e.g., a \$100 conversion with 4 touchpoints returns 4 rows with \$25 each). Single-touch models (first\_touch, last\_touch) return one row per event.
* When `sources` are not provided, all events in the specified date range are returned without attribution filtering (one row per event)
* The ad hierarchy fields (`ad_id`, `ad_name`, `adset_id`, `adset_name`, `campaign_id`, `campaign_name`, `account_id`, `account_name`) require `sources` to be provided. Requesting higher-level hierarchy fields (such as `account_name`) may increase processing time compared to requesting only lower-level fields (such as `ad_name`), so selecting only the fields you need will generally be more efficient.
* Cursor pagination is used for efficient traversal of large result sets
* The `id` and `event_time_utc` fields are always included in responses. When attribution is used (sources provided), `touchpoint_id` is also always included.
* Dates are provided in your space's configured timezone
* By default, only `id` and `event_time_utc` are returned (plus `touchpoint_id` when using attribution). Specify additional fields as needed to minimize response size.
