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

# Analytics Events

> Ingest Hub behavioral analytics events for Hub listings via API key authentication

## Overview

The analytics events endpoint lets demand-side SDK clients send Hub behavioral events for a listing. Events are used to populate analytics dashboards and drive tier-gated metrics. The endpoint uses **API key authentication** via the `X-Hub-API-Key` header — distinct from the `Authorization: Bearer` pattern used by other Hub endpoints.

**Base URL:** `https://ezforge.ai`

***

## Ingest analytics event

```
POST /api/v1/hub/analytics/events
```

Records a single Hub analytics event for a listing. Accepts all five Hub event types. Returns `202 Accepted` immediately after validation — the database write is asynchronous (fire-and-forget).

**Authentication:** `X-Hub-API-Key: hub_live_…` header required. Obtain a key at [`POST /api/v1/hub/api-keys`](/hub/api-keys).

### Request headers

| Header          | Required | Description                            |
| --------------- | -------- | -------------------------------------- |
| `X-Hub-API-Key` | Yes      | A Hub API key with prefix `hub_live_`. |

### Request body

```json theme={null}
{
  "listing_id": "01JQXYZ0000000000000000000",
  "event_type": "view",
  "query_text": "restaurant booking agent",
  "metadata": { "source": "search-results" }
}
```

| Field        | Type   | Required | Description                                                                                                                       |
| ------------ | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `listing_id` | string | Yes      | 26-character ULID of the Hub listing.                                                                                             |
| `event_type` | string | Yes      | One of the five Hub event types (see table below).                                                                                |
| `query_text` | string | —        | Free-text search query that led to this event. Strongly recommended for `search_impression` events; optional for all event types. |
| `metadata`   | object | —        | Arbitrary key-value pairs for additional context. Must be a flat or nested JSON object (not an array).                            |

### Event types

| `event_type`        | Description                                                                                                                     |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `view`              | A user or agent viewed the listing detail page. Contributes to `view_count`.                                                    |
| `search_impression` | The listing appeared in a search results page. Contributes to `search_impressions` (Premium).                                   |
| `click`             | The listing was selected from search results. Contributes to `click_count` and `click_through_rate`.                            |
| `interaction`       | A user clicked a referral link originating from Hub discovery. Mapped to `referral_clicks` in the analytics response (Premium). |
| `transaction`       | A transaction was completed through a Hub referral. Contributes to `conversion_rate` (Premium).                                 |

<Info>
  The `interaction` event type maps to `referral_clicks` in the analytics query response. This is the referral-link click signal in the Hub event taxonomy.
</Info>

### Response

**`202 Accepted`** — No response body. The event has been accepted for async recording.

### Error responses

| Status | Code                  | Condition                                                                                                               |
| ------ | --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| 400    | `invalid_input`       | `listing_id` is not a valid 26-character ULID, or `event_type` is not one of the five accepted values.                  |
| 401    | `unauthorized`        | `X-Hub-API-Key` header is missing, the key format is invalid, the key is not found, or the key has been revoked.        |
| 429    | `rate_limited`        | Daily request limit exceeded for this Hub API key. Resets at UTC midnight. `Retry-After: 86400` is set on the response. |
| 503    | `service_unavailable` | Rate-limit service temporarily unavailable.                                                                             |

**Example 401 response:**

```json theme={null}
{
  "error": {
    "code": "unauthorized",
    "message": "X-Hub-API-Key header with a Hub API key (hub_live_…) is required. Obtain one at /api/v1/hub/api-keys."
  }
}
```

**Example 429 response:**

```json theme={null}
{
  "error": {
    "code": "rate_limited",
    "message": "Daily request limit exceeded for this Hub API key."
  }
}
```

***

## Daily rate limits by tier

The daily limit applied to a `429` response is determined by the tier of the Hub API key used:

| Key tier   | Daily limit          |
| ---------- | -------------------- |
| `explorer` | 100 requests/day     |
| `builder`  | 10,000 requests/day  |
| `partner`  | 100,000 requests/day |

Rate limit counters reset at **UTC midnight**. To manage or rotate keys, see [API Keys](/hub/api-keys).

***

## SDK example

```typescript theme={null}
await fetch('https://ezforge.ai/api/v1/hub/analytics/events', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Hub-API-Key': process.env.HUB_API_KEY,
  },
  body: JSON.stringify({
    listing_id: '01JQXYZ0000000000000000000',
    event_type: 'view',
  }),
});
```
