General authentication:Header
Authorization(X-Api-Key) is required for all endpoints. Kong dual-auth: prioritizeX-Tenant-IDheader, fallback to query DB by key.
Base URL:Dev:
https://xapi-dev.alohub.vn| Prod:https://xapi.alohub.vn
/v1/reports/call-logsRetrieve the list of call logs filtered by phone number, time period, call type, and pagination. Returns summary information for each call along with customerNamelinks.
Authentication:Header
X-Api-Key, scope:report
Note:This endpoint uses
POST(notGET) because the filter is passed through the request body.
{
"phoneNumber": "0912345678",
"callStartTime": "2026-04-14T00:00:00+07:00",
"callEndtime": "2026-04-20T23:59:59+07:00",
"callType": 0,
"page": 1,
"limit": 50
}Field | Type | Required | Description |
|---|---|---|---|
| string | No | Filter by phone number — match with |
| string (ISO 8601) | No | Start time, format |
| string (ISO 8601) | No | Note typo:field name is |
| number | No | Call type: |
| number | No | Page number, starting from |
| number | No | Number of records per page. Default: |
Gotcha:Field backend is
callEndtime(typo — lowercaset). FE must send the correct spelling, otherwise the endTime filter will not be applied.
curl -X POST "https://xapi.alohub.vn/v1/reports/call-logs" \
-H "X-Api-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "0912345678",
"callStartTime": "2026-04-14T00:00:00+07:00",
"callEndtime": "2026-04-20T23:59:59+07:00",
"callType": 0,
"page": 1,
"limit": 50
}'const axios = require('axios');
const response = await axios.post(
'{{host}}/api/v1/reports/call-logs',
{
phoneNumber: '0912345678',
callStartTime: '2026-04-14T00:00:00+07:00',
callEndtime: '2026-04-20T23:59:59+07:00', // ⚠️ typo: lowercase t
callType: 0,
page: 1,
limit: 50
},
{ headers: { 'X-Api-Key': '{{api-key}}' } }
);
console.log(response.data);import requests
payload = {
"phoneNumber": "0912345678",
"callStartTime": "2026-04-14T00:00:00+07:00",
"callEndtime": "2026-04-20T23:59:59+07:00", # typo: lowercase t
"callType": 0,
"page": 1,
"limit": 50
}
response = requests.post(
'{{host}}/api/v1/reports/call-logs',
json=payload,
headers={"X-Api-Key": "{{api-key}}"}
)
print(response.json()){
"success": "1",
"error_code": "SUCCESS",
"error_message": "SUCCESS",
"totalRecord": 3829,
"data": [
{
"callId": "20260310095227-ABCXYZ-342",
"caller": "0912345678",
"called": "alohub2",
"startTime": "21/01/2026 09:52:33",
"waitingTime": "6",
"firstRingTime": "21/01/2026 09:52:35",
"firstConnectTime": "",
"agentId": "AloHub",
"endTime": "21/01/2026 09:52:41",
"acdTime": "0",
"description": "INBOUND-Khách hàng kết thúc trước khi timeout",
"customerName": "0912345678",
"url": ""
}
]
}Field | Type | Description |
|---|---|---|
| string | "1" = success, "0" = error |
| string | Error code ( |
| number | Total number of records matching the filter (not the number of rows on the current page) |
| string | Call code |
| string | Outgoing number |
| string | Number / hotline called |
| string | Username of the handling agent (empty if no one answered) |
| string | Start time, format |
| string | End time |
| string | First ringing time |
| string | First time the agent picked up (empty if not connected) |
| string | Customer wait time — seconds, type string(requires |
| string | ACD time — seconds, type string |
| string | Description of the call end status |
| string | Customer name / code associated |
| string | URL of the recording file (empty if none) |
Duplicate rows:The response may return multiple rows with the same
callIdbut differentcustomerName— due to BE JOIN call with the customer table (1-n). FE should deduplicate if it wants to display 1 row/call:Array.from(new Map(data.map(r => [r.callId, r])).values())
HTTP | error_code | Description | FE handling |
|---|---|---|---|
401 | UNAUTHORIZED | Missing or incorrect | Redirect to re-enter key |
403 | INSUFFICIENT_SCOPE | Key does not have scope | Notify to contact admin |
400 | INVALID_INPUT | Body incorrect format (date, page/limit not a number) | Show specific error |
429 | RATE_LIMIT_EXCEEDED | Exceeded request limit | Retry after |
500 | FAIL | System error | General error toast |
Header | Description |
|---|---|
| Tenant limit/10s |
| Remaining tenant/10s |
| Route limit/10s |
| Remaining route/10s |
| Seconds to wait when hit 429 |
/v1/reports/call-logs/{callId}Retrieve details of a call by callId, including caller/called information, handling agent, time, duration, end status, and URL of the recording file.
Authentication:Header
X-Api-Key, scope:report
Note on time:Time fields (
startTime,endTime, ...) are string formatdd/MM/yyyy HH:mm:ssin UTC+7, not ISO 8601 — FE needs to parse manually.
Parameter | Location | Required | Type | Description | Example |
|---|---|---|---|---|---|
| path | Yes | string | Call identifier, format |
|
None (method GET).
curl -X GET "https://xapi.alohub.vn/v1/reports/call-logs/20260310095227-ABCXYZ-342" \
-H "X-Api-Key: sk_live_xxx" \
-H "Accept: application/json"const axios = require('axios');
const callId = '20260310095227-ABCXYZ-342';
const response = await axios.get(
`{{host}}/api/v1/reports/call-logs/${encodeURIComponent(callId)}`,
{ headers: { 'X-Api-Key': '{{api-key}}' } }
);
// response.data.data[0] là object chi tiết (null nếu không tìm thấy)
console.log(response.data.data[0]);import requests
call_id = '20260310095227-ABCXYZ-342'
response = requests.get(
f'{{host}}/api/v1/reports/call-logs/{call_id}',
headers={"X-Api-Key": "{{api-key}}"}
)
data = response.json()
# data["data"][0] là object chi tiết
print(data["data"][0] if data["data"] else None){
"success": "1",
"error_code": "SUCCESS",
"error_message": "SUCCESS",
"totalRecord": 1,
"data": [
{
"callId": "20260310095227-ABCXYZ-342",
"caller": "0912345678",
"called": "alohub2",
"agentId": "AloHub",
"startTime": "21/01/2026 09:52:33",
"endTime": "21/01/2026 09:52:41",
"ringTime": "21/01/2026 09:52:35",
"connectTime": "",
"answerTime": 0,
"duration": 8,
"callType": "0",
"description": "INBOUND-Khách hàng kết thúc trước khi timeout",
"customerName": "20260107172924-KZGTVFTE-600",
"recordingUrl": ""
}
]
}Field | Type | Description |
|---|---|---|
| string | "1" = success, "0" = error |
| number | Always = |
| string | Call code |
| string | Phone number / extension called |
| string | Number / hotline / extension being called |
| string | Username of the handling agent (empty if no one answered) |
| string | Start time, format |
| string | End time |
| string | Ringing time (cf. |
| string | Time the agent picked up (empty if not connected) |
| number | Wait time until answered (seconds). |
| number | Total duration of the call (seconds) |
| string |
|
| string | Description of the call end status |
| string | Customer name / code associated |
| string | URL of the recording file (empty if none) |
Difference from List API:
answerTimeanddurationis number(not string likewaitingTime/acdTimein list). The recording field isrecordingUrl(detail) vsurl(list). The ringing time isringTime(detail) vsfirstRingTime(list).
HTTP | error_code | Description | FE handling |
|---|---|---|---|
401 | UNAUTHORIZED | Missing or incorrect | Redirect to re-enter key |
403 | INSUFFICIENT_SCOPE | Key does not have scope | Notify to contact admin |
404 | NOT_FOUND | Call log not found with | Notify "Call not found" |
400 | INVALID_INPUT |
| Check input again |
429 | RATE_LIMIT_EXCEEDED | Exceeded request limit | Retry after |
500 | FAIL | System error | General error toast |
Header | Description |
|---|---|
| Tenant limit/10s |
| Remaining tenant/10s |
| Route limit/10s |
| Remaining route/10s |
| Seconds to wait when hit 429 |