List Events
curl --request GET \
--url https://app.cometly.com/public-api/v1/events \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.cometly.com/public-api/v1/events"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.cometly.com/public-api/v1/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.cometly.com/public-api/v1/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.cometly.com/public-api/v1/events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.cometly.com/public-api/v1/events")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.cometly.com/public-api/v1/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{}
],
"path": "<string>",
"per_page": 123,
"next_cursor": {},
"next_page_url": {},
"prev_cursor": {},
"prev_page_url": {},
"message": "<string>"
}Events
List Events
Retrieve a paginated list of events with optional attribution filtering
GET
/
public-api
/
v1
/
events
List Events
curl --request GET \
--url https://app.cometly.com/public-api/v1/events \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.cometly.com/public-api/v1/events"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.cometly.com/public-api/v1/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.cometly.com/public-api/v1/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.cometly.com/public-api/v1/events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.cometly.com/public-api/v1/events")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.cometly.com/public-api/v1/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{}
],
"path": "<string>",
"per_page": 123,
"next_cursor": {},
"next_page_url": {},
"prev_cursor": {},
"prev_page_url": {},
"message": "<string>"
}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
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:00string
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:59Optional Parameters
string
default:"profile"
Determines whether to report metrics by contact or company level.Options:
profile- Contact-level events (default)company- Company-level events
string[]
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_infoadd_to_cartcomplete_registrationcontactinitiate_checkoutlead_generatedpurchaseschedulesign_upstart_trialsubmit_applicationsubscribeupsell_purchaseview_contentwebinar_registration
custom_event_1 through custom_event_50.string[]
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.Available sources
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, whop_adsOrganic:
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_organicAI Platforms:
ai_chat_gpt, ai_perplexity, ai_copilot, ai_claude, ai_grok, ai_gemini, ai_deepseekOther:
email, sms, referral, direct, shop_app, substack, capterra, trustpilot, g2, yelpstring
Attribution model to use for filtering events. Required when
sources is provided.Options:first_touch- First interaction attributionlast_touch- Last interaction attributionlinear- Equal credit across all touchpointsfirst_platform_touch- First paid platform touchlast_platform_touch- Last paid platform touchlinear_paid- Linear attribution across paid touchpoints onlyu_shaped- 40% first, 40% last, 20% middle touchpointslast_non_direct_touch- Last touch excluding direct traffic
integer
Attribution lookback window in days. Required when
sources is provided.Options: 0 (LTV), 1, 7, 14, 30, 60, 90string[]
default:"['id', 'event_time_utc']"
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 identifiercompany_id- Company identifierspace_id- Space identifierevent_name- Event nameconfigured_name- The configured name of the event. For custom events (custom_event_1throughcustom_event_50), this is the user-configured name. For standard events, this equalsevent_name.amount- Transaction amount (with attribution, this is the partial amount credited to the touchpoint)is_upsell- Upsell flagad_id- Platform-specific ad identifier (requiressourcesto be provided)ad_name- Ad name from the ad platform (requiressourcesto be provided)adset_id- Platform-specific ad set identifier (requiressourcesto be provided)adset_name- Ad set name from the ad platform (requiressourcesto be provided)campaign_id- Platform-specific campaign identifier (requiressourcesto be provided)campaign_name- Campaign name from the ad platform (requiressourcesto be provided)account_id- Platform-specific ad account identifier (requiressourcesto be provided)account_name- Ad account name from the ad platform (requiressourcesto be provided)order_id- Order identifierorder_name- Order nameevent_url- The full URL where the event occurred
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)
integer
default:"200"
Number of events to return per page. Minimum: 1, Maximum: 4000
string
Pagination cursor from a previous response. Use this to fetch the next page of results.
array
Filter events by their owning contact’s custom profile field values. Array of AND-joined conditions, each
{ "field": "profile_field_N", "operator": "<op>", "value": <val> }, or for ranges { "field": "profile_field_N", "operator": "between", "start": <a>, "end": <b> }. The field must reference a custom field slot configured with a label in your space (e.g. profile_field_5). Same shape and operator vocabulary as the List Contacts endpoint. Maximum 10 conditions per request.Operator vocabulary by field type:| Slot range | Type | Valid operators |
|---|---|---|
profile_field_1 – profile_field_15 | text | equal_to, not_equal_to, contains, not_contains, starts_with, ends_with, contains_word, any, unknown |
profile_field_16 – profile_field_25 | number | equal_to, not_equal_to, greater_than, greater_than_or_equal_to, less_than, less_than_or_equal_to, any, unknown |
profile_field_26 – profile_field_30 | date | equal_to, between, greater_than, less_than, age_greater_than, age_equal_to, age_less_than, any, unknown |
any matches contacts where the field has a value; unknown matches contacts where the field is empty or unset. For numeric fields, any requires a value greater than 0 — unknown matches 0 or unset. Date comparisons (equal_to, greater_than, less_than, between) are evaluated in your space’s configured timezone; equal_to matches the full calendar day. not_equal_to and not_contains do not include contacts where the field is unset — add a separate unknown condition if you need those.Example query string: custom_field_filters[0][field]=profile_field_5&custom_field_filters[0][operator]=equal_to&custom_field_filters[0][value]=PremiumResponse
Success Response
The response follows Laravel’s cursor pagination structure:array
Array of event objects with the requested fields
string
The base URL path for the endpoint
integer
Number of items per page
string | null
Cursor for the next page of results.
null if there are no more pages.string | null
Full URL for the next page of results.
null if there are no more pages.string | null
Cursor for the previous page of results.
null if on the first page.string | null
Full URL for the previous page of results.
null if on the first page.Error Response
string
Error description explaining what went wrong
Example Requests
# 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" \
--data-urlencode "start_date=2024-01-01 00:00:00" \
--data-urlencode "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" \
--data-urlencode "start_date=2024-01-01 00:00:00" \
--data-urlencode "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"
# Filter events by the owning contact's custom field value
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" \
--data-urlencode "start_date=2024-01-01 00:00:00" \
--data-urlencode "end_date=2024-01-31 23:59:59" \
-d "event_names[]=purchase" \
-d "custom_field_filters[0][field]=profile_field_5" \
-d "custom_field_filters[0][operator]=equal_to" \
-d "custom_field_filters[0][value]=Premium"
# 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" \
--data-urlencode "start_date=2024-01-01 00:00:00" \
--data-urlencode "end_date=2024-01-31 23:59:59" \
-d "cursor=eyJldmVudF90aW1lX3V0YyI6IjIwMjQtMDEtMTUgMTI..."
// 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
// 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);
}
?>
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()
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 |
Notes
- Rate Limit: This endpoint has a limit of 7 requests per minute per Space. See Rate Limiting for details.
- When
sourcesare 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
sourcesare 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) requiresourcesto be provided. Requesting higher-level hierarchy fields (such asaccount_name) may increase processing time compared to requesting only lower-level fields (such asad_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
idandevent_time_utcfields are always included in responses. When attribution is used (sources provided),touchpoint_idis also always included. - Dates are provided in your space’s configured timezone
- By default, only
idandevent_time_utcare returned (plustouchpoint_idwhen using attribution). Specify additional fields as needed to minimize response size. - Custom Field Filters: Use
custom_field_filtersto narrow results to events whose owning contact matches conditions on custom profile fields. Filters are AND-joined; up to 10 per request. Slots that haven’t been configured with a label in your space are rejected with a 422. Age operators (age_greater_than,age_equal_to,age_less_than) accept a whole-number day count and are supported on date fields. The_and\characters in text filter values are treated as literals, not LIKE wildcards.