On-Domain Events API

Overview

The Events API lets you query pixel events from your website in real-time. When a visitor hits a page with your pixel installed, the platform captures the event and -- if the visitor can be identified -- enriches it with contact and company data.

flowchart LR
    A[Create Pixel] --> B[Install on Site]
    B --> C[Query Events]
    C --> D[Filter and Deduplicate]
    D --> E[Export or Integrate]

    style A fill:#3b82f6,color:#fff
    style B fill:#3b82f6,color:#fff
    style C fill:#3b82f6,color:#fff
    style D fill:#3b82f6,color:#fff
    style E fill:#22c55e,color:#fff

Base URL: https://apiv3.delivr.ai

Prerequisites:

Authentication: Bearer token in the Authorization header, plus your organization ID.

Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
x-organization-id: YOUR_ORGANIZATION_ID

The x-organization-id header is required for enriched (resolved) event queries. Without it, you still get raw events but without identity enrichment.


Step 1: Create a Pixel

Pixels track visitor activity on your website. Create one on your project:

curl -X POST https://api.delivr.ai/public/core/api/pixel/create \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "X-Delivr-Client-ID: YOUR_CLIENT_ID" \
  -H "X-Delivr-Client-Secret: YOUR_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "project_id: YOUR_PROJECT_ID" \
  -d '{
    "title": "My Website Pixel"
  }'

Response

{
  "response": {
    "pixel_id": "8a755c42-b2b1-...",
    "installation_url": "https://cdn.delivr.ai/pixels/8a755c42-b2b1-.../p.js"
  }
}

Install the Pixel

Add this script tag to your website's <head>:

<script id="delivr-ai" src="https://cdn.delivr.ai/pixels/YOUR_PIXEL_ID/p.js" async></script>

Or install via Google Tag Manager.

Find Your Pixel ID

If you already have a pixel installed, find the ID from:

  1. Dashboard: Settings > Pixels > Copy the pixel ID
  2. Your pixel script: The ID is in the URL: https://cdn.delivr.ai/pixels/YOUR_PIXEL_ID/p.js

Step 2: Query Events

Request

GET /api/v1/events?pixel_id=YOUR_PIXEL_ID&start_ms=START_MS&end_ms=END_MS&limit=20&offset=0

Required Parameters

ParameterTypeDescription
pixel_idstring (UUID)Your pixel ID (from dashboard Settings > Pixels)
start_msintegerStart of time window in milliseconds since epoch
end_msintegerEnd of time window in milliseconds since epoch

Optional Parameters

ParameterTypeDefaultDescription
limitinteger100Max rows to return
offsetinteger0Skip this many rows (for pagination)
filterstring--Filter expression (see Filters section)
selectstring--Comma-separated field names to return
distinctstring--Deduplicate by field: hem or company_domain
has_valuable_databoolean--Only return rows with actionable contact or company data
orderbystring--Sort field and direction: field:asc or field:desc

Time Window Limit

Each request can span a maximum of 25 hours. For longer ranges, split into multiple requests with consecutive time windows.

Generating Timestamps

import time

# Current time
end_ms = int(time.time() * 1000)

# 24 hours ago
start_ms = end_ms - (24 * 60 * 60 * 1000)

# Specific date (2026-01-28 00:00 UTC)
import datetime
dt = datetime.datetime(2026, 1, 28, tzinfo=datetime.timezone.utc)
start_ms = int(dt.timestamp() * 1000)

Example Response (200 OK)

Resolved event (visitor was identified):

{
  "pixel_id": "YOUR_PIXEL_ID",
  "start_ms": 1769558400000,
  "end_ms": 1769644800000,
  "limit": 20,
  "offset": 0,
  "rows": [
    {
      "event_id": "8911fff2-c21e-42c3-85ae-cd31ae79de96",
      "event_type": "page_view",
      "timestamp": "2026-01-28T01:58:12.557202Z",
      "ts_millis": 1769565492557,
      "pixel_id": "YOUR_PIXEL_ID",
      "project_id": "YOUR_PROJECT_ID",
      "cookie_id": 3429795123691521,
      "resolved": true,
      "first_name": "jane",
      "last_name": "smith",
      "job_title": "product analyst",
      "department": "information technology",
      "seniority_level": "staff",
      "company_name": "acme corp",
      "company_domain": "acmecorp.com",
      "company_industry": "government administration",
      "company_employee_count_range": "10000+",
      "current_business_email": "[email protected]",
      "current_business_email_validation_status": "valid",
      "linkedin_url": "https://linkedin.com/in/jane-smith-12345678",
      "email": "[email protected]",
      "referrer_url": "https://www.yoursite.com/",
      "event_data": "{\"url\":\"https://www.yoursite.com/pricing\",\"title\":\"Pricing Page\"}",
      "client_ip": "88.98.217.66",
      "user_agent": "Mozilla/5.0 ...",
      "...": "110 total fields when resolved"
    }
  ],
  "meta": {
    "files_scanned": 29,
    "buckets_scanned": 1,
    "took_ms": 151
  },
  "index_name": "project_id"
}

Unresolved event (visitor was not identified):

{
  "rows": [
    {
      "event_id": "1542601a-3eca-48d1-81af-9a770714ac26",
      "event_type": "page_view",
      "timestamp": "2026-01-28T00:37:48.768321Z",
      "ts_millis": 1769560668768,
      "pixel_id": "YOUR_PIXEL_ID",
      "project_id": "YOUR_PROJECT_ID",
      "cookie_id": 109879807197643124,
      "client_ip": "92.50.23.199",
      "ip": "34.8.133.12",
      "referrer_url": "https://www.yoursite.com/",
      "event_data": "{\"url\":\"https://www.yoursite.com/pricing\",\"title\":\"Pricing\"}",
      "headers": "{...}",
      "user_agent": "Mozilla/5.0 ..."
    }
  ]
}

Unresolved events contain ~13 fields (raw event data only). Resolved events contain ~110 fields (enriched with contact, company, and demographic data).


Step 3: Filter Events

Filters use the format field:operator:value, with multiple filters separated by commas (AND logic).

Filter Operators

OperatorExampleDescription
eqresolved:eq:trueExact match
likecompany_name:like:acmeCase-insensitive contains
not_nullfirst_name:not_nullField has a value

Common Filter Examples

# Only resolved (identified) visitors
filter=resolved:eq:true

# Only page views
filter=event_type:eq:page_view

# Resolved visitors with a company name
filter=resolved:eq:true,company_name:not_null

# Search by name
filter=first_name:like:john

# Specific event type + resolved
filter=resolved:eq:true,event_type:eq:page_view

Filter in a Request

GET /api/v1/events?pixel_id=YOUR_PIXEL_ID&start_ms=START_MS&end_ms=END_MS&limit=20&filter=resolved%3Aeq%3Atrue

URL-encode the filter value. : becomes %3A, so resolved:eq:true becomes resolved%3Aeq%3Atrue.


Step 4: Get Event Counts

Get a count of events without fetching the full rows.

Request

GET /api/v1/event_counts?pixel_id=YOUR_PIXEL_ID&start_ms=START_MS&end_ms=END_MS

Optional Parameters

ParameterTypeDescription
filterstringSame filter syntax as events endpoint
distinctstringCount distinct values: hem or company_domain

Example Response (200 OK)

{
  "count": 287,
  "meta": {
    "files_scanned": 29,
    "buckets_scanned": 1,
    "took_ms": 51
  }
}

Count Examples

# Total events in time window
GET /api/v1/event_counts?pixel_id=...&start_ms=...&end_ms=...

# Only resolved events
GET /api/v1/event_counts?pixel_id=...&start_ms=...&end_ms=...&filter=resolved%3Aeq%3Atrue

# Unique identified visitors (distinct HEM)
GET /api/v1/event_counts?pixel_id=...&start_ms=...&end_ms=...&distinct=hem

# Unique companies
GET /api/v1/event_counts?pixel_id=...&start_ms=...&end_ms=...&distinct=company_domain

Step 5: Deduplicate Results

Use distinct and has_valuable_data together to get one row per person or company.

One Row Per Person

GET /api/v1/events?pixel_id=...&start_ms=...&end_ms=...&distinct=hem&has_valuable_data=true&limit=50

Returns one row per unique identity (HEM). Only includes rows where:

  • The visitor has a displayable email, OR
  • The visitor has a name AND company

One Row Per Company

GET /api/v1/events?pixel_id=...&start_ms=...&end_ms=...&distinct=company_domain&has_valuable_data=true&limit=50

Returns one row per unique company domain. Only includes rows where the company name is present.


Field Projection

Use the select parameter to return only specific fields. This reduces response size.

Fields that are null for a given row are omitted from the response. Your code should handle missing keys gracefully.

GET /api/v1/events?pixel_id=...&start_ms=...&end_ms=...&select=event_type,referrer_url,event_data&limit=5

Example Response

{
  "rows": [
    {
      "event_type": "page_view",
      "referrer_url": "https://www.yoursite.com/",
      "event_data": "{\"url\":\"https://www.yoursite.com/pricing\"}"
    }
  ]
}

Available Fields (Schema)

GET /api/v1/events_schema?pixel_id=YOUR_PIXEL_ID

Example Response (200 OK)

{
  "fields": [
    { "name": "event_id", "data_type": "Utf8", "nullable": false },
    { "name": "pixel_id", "data_type": "Utf8", "nullable": false },
    { "name": "event_type", "data_type": "Utf8", "nullable": false },
    { "name": "timestamp", "data_type": "Utf8", "nullable": false },
    { "name": "ts_millis", "data_type": "Int64", "nullable": false },
    { "name": "cookie_id", "data_type": "Int64", "nullable": true },
    { "name": "resolved", "data_type": "Boolean", "nullable": true },
    { "name": "first_name", "data_type": "Utf8", "nullable": true },
    { "name": "last_name", "data_type": "Utf8", "nullable": true },
    { "name": "company_name", "data_type": "Utf8", "nullable": true },
    { "name": "company_domain", "data_type": "Utf8", "nullable": true },
    { "name": "job_title", "data_type": "Utf8", "nullable": true },
    { "name": "email", "data_type": "Utf8", "nullable": true }
  ]
}

This is a partial list. The full schema contains 110+ fields. Call the endpoint to see all fields.

Key Field Categories

CategoryExample Fields
Eventevent_id, event_type, timestamp, ts_millis, cookie_id
Pagereferrer_url, event_data (JSON with URL, title, viewport)
Identityresolved, hem, hems, email, domain_lc
Personfirst_name, last_name, job_title, department, seniority_level
Companycompany_name, company_domain, company_industry, company_employee_count_range
Locationpersonal_city, personal_state, personal_country, company_city
Demographicsage_range, gender, income_range_lc, net_worth, is_homeowner
Contactcurrent_business_email, business_emails, personal_emails, phones, linkedin_url
Hashesemails_sha256_lc_hem, emails_md5_lc_hem, emails_sha1_lc_hem
Networkclient_ip, ip, user_agent, headers

Pagination

The events API uses offset-based pagination. There is no total count in the response -- use the event_counts endpoint for that.

How to Paginate

  1. Request with offset=0&limit=100
  2. If you get back 100 rows (equal to your limit), there may be more -- request offset=100&limit=100
  3. If you get fewer rows than your limit, you've reached the end

Example

import requests

all_rows = []
offset = 0
limit = 100

while True:
    resp = requests.get(
        "https://apiv3.delivr.ai/api/v1/events",
        params={
            "pixel_id": "YOUR_PIXEL_ID",
            "start_ms": start_ms,
            "end_ms": end_ms,
            "limit": limit,
            "offset": offset,
            "filter": "resolved:eq:true",
        },
        headers={
            "Authorization": "Bearer YOUR_API_TOKEN",
            "x-organization-id": "YOUR_ORGANIZATION_ID",
        },
    )
    data = resp.json()
    rows = data.get("rows", [])
    all_rows.extend(rows)

    if len(rows) < limit:
        break  # No more rows
    offset += limit

print(f"Total rows fetched: {len(all_rows)}")

For ranges longer than 25 hours, split into 24-hour chunks and paginate within each chunk.


Complete Example

Python: Fetch Resolved Visitors from the Last 24 Hours

import time
import requests

API_TOKEN = "YOUR_API_TOKEN"
ORG_ID = "YOUR_ORGANIZATION_ID"
PIXEL_ID = "YOUR_PIXEL_ID"

end_ms = int(time.time() * 1000)
start_ms = end_ms - (24 * 60 * 60 * 1000)

resp = requests.get(
    "https://apiv3.delivr.ai/api/v1/events",
    params={
        "pixel_id": PIXEL_ID,
        "start_ms": start_ms,
        "end_ms": end_ms,
        "limit": 50,
        "filter": "resolved:eq:true",
        "distinct": "hem",
        "has_valuable_data": "true",
    },
    headers={
        "Authorization": f"Bearer {API_TOKEN}",
        "Content-Type": "application/json",
        "x-organization-id": ORG_ID,
    },
)

data = resp.json()
rows = data.get("rows", [])

print(f"Found {len(rows)} unique identified visitors")
for row in rows:
    print(f"  {row.get('first_name')} {row.get('last_name')}")
    print(f"    {row.get('job_title')} at {row.get('company_name')}")
    print(f"    Email: {row.get('current_business_email')}")
    print()

curl: Quick Check

# Count total events in the last 24 hours
END_MS=$(python3 -c "import time; print(int(time.time()*1000))")
START_MS=$(python3 -c "import time; print(int((time.time()-86400)*1000))")

curl "https://apiv3.delivr.ai/api/v1/event_counts?pixel_id=YOUR_PIXEL_ID&start_ms=$START_MS&end_ms=$END_MS" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "x-organization-id: YOUR_ORGANIZATION_ID"

# Fetch 5 resolved events
curl "https://apiv3.delivr.ai/api/v1/events?pixel_id=YOUR_PIXEL_ID&start_ms=$START_MS&end_ms=$END_MS&limit=5&filter=resolved%3Aeq%3Atrue" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "x-organization-id: YOUR_ORGANIZATION_ID"

Event Types

Event TypeDescription
page_viewPage was loaded
clickElement was clicked
form_submissionForm was submitted
file_downloadFile was downloaded
copyText was copied
exit_intentMouse moved toward browser close/back
user_idleUser went idle on the page
video_playVideo started playing
video_pauseVideo was paused
video_completeVideo finished playing

Filter by type: filter=event_type:eq:page_view


Errors

HTTP StatusErrorCause
400"pixel_id is required"Missing pixel_id parameter
400"missing field start_ms"Missing start_ms parameter
401"invalid jwt token"Invalid or expired Bearer token

Response Reference

Events Response

{
  "pixel_id": "...",
  "start_ms": 1769558400000,
  "end_ms": 1769644800000,
  "limit": 20,
  "offset": 0,
  "rows": [ ... ],
  "meta": {
    "files_scanned": 29,
    "buckets_scanned": 1,
    "took_ms": 151
  }
}

Counts Response

{
  "count": 287,
  "meta": {
    "files_scanned": 29,
    "buckets_scanned": 1,
    "took_ms": 51
  }
}

Schema Response

{
  "fields": [
    { "name": "field_name", "data_type": "Utf8", "nullable": true }
  ]
}

Next Steps