---
id: "api-reference/events"
type: "doc"
url: "https://affitor.com/docs/api-reference/events"
---
# List Tracking Events

> Retrieve paginated, merged tracking events (clicks, leads, conversions) for a program

`GET /api/tracking/events/:programId`

Returns a merged, reverse-chronological list of click, lead, and conversion events recorded for the specified program. Events from all three tables are fetched, normalized to a common shape, sorted by timestamp, and then paginated.

---

## Authentication

This endpoint uses workspace-policy enforcement. The request must carry a valid authenticated session that has been granted the `tracking:list` action for the program. This is enforced by the `verify-program-access` policy on the Strapi backend.

:::note

This endpoint backs the Affitor dashboard. It accepts only a signed-in dashboard session for a workspace member of the program and does not accept a program API key (`aff_…`), so you cannot call it from a server integration with your API key.

:::

---

## Path Parameter

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `programId` | integer | **Yes** | Numeric ID of the affiliate program |

---

## Query Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `page` | integer | No | `1` | Page number (1-indexed) |
| `pageSize` | integer | No | `10` | Number of events per page |
| `eventType` | string | No | *(all)* | Filter by event type. Accepted values: `click`, `lead`, `conversion` |
| `dateFrom` | string (ISO 8601) | No | *(none)* | Inclusive lower bound on event timestamp |
| `dateTo` | string (ISO 8601) | No | *(none)* | Inclusive upper bound on event timestamp |

### Example request

```bash
GET /api/tracking/events/42?page=1&pageSize=10&eventType=click&dateFrom=2026-06-01T00:00:00Z&dateTo=2026-06-07T23:59:59Z
```

---

## Response

Returns a `data` array of normalized event objects and a `meta.pagination` block.

### Success `200`

```json
{
  "data": [
    {
      "id": 301,
      "event_type": "click",
      "timestamp": "2026-06-07T14:22:10.000Z",
      "click_id": "cust_42_1749305730000",
      "session_id": "sess_1749305730000",
      "page_url": "https://example.com/pricing?aff=PARTNER123",
      "referrer_url": "https://twitter.com",
      "geo_country": "US",
      "geo_region": "CA",
      "geo_city": "San Francisco",
      "device_type": "desktop",
      "device_os": "macOS",
      "browser_name": "Chrome",
      "converted": false,
      "createdAt": "2026-06-07T14:22:10.512Z"
    },
    {
      "id": 87,
      "event_type": "lead",
      "timestamp": "2026-06-06T09:11:42.000Z",
      "click_id": "cust_42_1749218702000",
      "customer_key": "usr_abc123",
      "session_id": "sess_1749218702000",
      "page_url": "https://example.com/signup",
      "converted": false,
      "createdAt": "2026-06-06T09:11:42.301Z"
    },
    {
      "id": 15,
      "event_type": "conversion",
      "timestamp": "2026-06-05T16:45:00.000Z",
      "click_id": "cust_42_1749131100000",
      "amount_cents": 9900,
      "currency": "USD",
      "sale_type": "payment",
      "payment_status": "paid",
      "processor_event_id": "txn_abc123",
      "is_recurring": false,
      "createdAt": "2026-06-05T16:45:01.000Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 10,
      "pageCount": 3,
      "total": 28
    }
  }
}
```

### Field notes

- `event_type` is a normalized field added by the server: `"click"`, `"lead"`, or `"conversion"`.
- `timestamp` is a normalized field set to the source event's native time field (`click_timestamp`, `lead_timestamp`, or `sale_date`).
- Test events (`is_test: true`) are excluded from all three tables before merging.
- Each event type is read newest-first, capped at 3 × `pageSize` rows per type, then merged and paginated. `total` is the size of that merged set, not the full event count: it is at most 3 × `pageSize` for one event type (9 × `pageSize` for all three), and pages beyond it come back empty even when older events exist. Narrow the window with `dateFrom` / `dateTo` to reach older events.

---

## Errors

| Status | When |
|--------|------|
| `404` | `programId` does not match any program |
| `403` | Caller does not have `tracking:list` access for the program |
| `500` | Unexpected server error |
