KPI Conversations API
KPI Conversations API
Internal endpoint for VBET KPI analysis. Returns paginated conversation data scoped to VBET accounts.
Endpoint
GET /api/v1/kpi/conversations
Authentication
Requires an api_access_token header. Access is restricted to the user with email kpi_tracker@vbet.com.
api_access_token: <token>
Any other user receives 401 Unauthorized.
Authorization
Conversations are scoped to account IDs listed in the VBET_ACCOUNT_IDS installation config (comma-separated integers stored in the DB).
If account_id is provided, it must be in that allowlist — otherwise 401 Unauthorized is returned.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
account_id |
integer | No | all VBET accounts | Scope to a single account. Must be in the VBET allowlist. |
since |
integer | No | 100 years ago | Unix timestamp. Return conversations created at or after this time. |
until |
integer | No | end of today | Unix timestamp. Return conversations created at or before this time. |
sort_direction |
string | No | asc |
Sort by created_at. Accepted values: asc, desc. |
page |
integer | No | 1 |
Page number (1-based). |
page_size |
integer | No | 20 |
Records per page. Clamped to [1, 1000]. |
Response
200 OK
{
"meta": {
"items_count": 42,
"current_page": 1,
"page_size": 20
},
"payload": [
{
"id": 101,
"display_id": 5,
"account_id": 3,
"created_time": "2026-01-10T08:30:00Z",
"resolved_time": "2026-01-10T09:15:00Z",
"chat_duration": 2700,
"status": "resolved",
"labels": ["urgent", "billing"],
"assignee": {
"id": 7,
"name": "Jane Smith",
"email": "jane@example.com"
},
"contact": {
"id": 55,
"identifier": "ext-user-123"
}
},
{
"id": 102,
"display_id": 6,
"account_id": 3,
"created_time": "2026-01-11T10:00:00Z",
"resolved_time": null,
"chat_duration": null,
"status": "open",
"labels": [],
"assignee": null,
"contact": null
}
]
}
Field Reference
| Field | Type | Description |
|---|---|---|
meta.items_count |
integer | Total matching conversations (across all pages). |
meta.current_page |
integer | Current page number. |
meta.page_size |
integer | Effective page size (after clamping). |
payload[].id |
integer | Internal conversation ID. |
payload[].display_id |
integer | Human-readable conversation number within the account. |
payload[].account_id |
integer | Account the conversation belongs to. |
payload[].created_time |
ISO 8601 string | When the conversation was created. |
payload[].resolved_time |
string | null | Value from additional_attributes.resolved_time. Null if not set. |
payload[].chat_duration |
integer | null | Seconds from conversation start to resolution. Calculated as resolved_time - (reopen_time \|\| created_at). Null if resolved_time is not set. |
payload[].status |
string | open, resolved, pending, or snoozed. |
payload[].labels |
string[] | Labels attached to the conversation. |
payload[].assignee |
object | null | Assigned agent. Null if unassigned. |
payload[].contact |
object | null | Associated contact. Null if not linked. |
Error Responses
| Status | Condition |
|---|---|
401 Unauthorized |
No token, wrong user email, or account_id not in VBET allowlist. |
422 Unprocessable Entity |
since or until is not a valid Unix timestamp integer. |
Example Requests
Fetch all VBET conversations for a date range:
curl -X GET "https://app.hoory.com/api/v1/kpi/conversations?since=1736467200&until=1736553600&page=1&page_size=100" \
-H "api_access_token: <token>"
Scope to a single account, sorted descending:
curl -X GET "https://app.hoory.com/api/v1/kpi/conversations?account_id=3&sort_direction=desc&page=1&page_size=50" \
-H "api_access_token: <token>"