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.
| Header | Required | Description |
|---|
X-Hub-API-Key | Yes | A Hub API key with prefix hub_live_. |
Request body
{
"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). |
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.
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:
{
"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:
{
"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.
SDK example
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',
}),
});