API Integration Guide
Complete reference for integrating with the System reporting and analytics API. All endpoints are secured with JWT Bearer tokens.
1 Authentication
All endpoints except /api/login require the header:
Authorization: Bearer <your_jwt_token>
Login
POST/api/login
Request Body
{
"email": "user@example.com",
"password": "your_password"
}
cURL Example
curl -X POST https://your-domain.com/api/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"your_password"}'
Response 200
{
"success": true,
"data": {
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"user": {
"id": 12,
"name": "Agent Name",
"email": "user@example.com"
}
}
}
Response 401
{
"success": false,
"errors": {
"error": "invalid_login_or_password"
}
}
2 Inbound Calls
2.1 List Inbound Calls
GET/api/reporting/inbound
| Parameter | Type | Required | Description |
daterange | string | No | "YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss" |
did_ext | string | No | Filter by DID number |
user_ext | string | No | Filter by agent extension or user ID |
group_ext | string | No | Filter by queue / group ID |
search | string | No | Search by queue name, agent, caller number |
page | int | No | Default: 1 |
per_page | int | No | Default: 10, max: 200 |
cURL Example
curl -H "Authorization: Bearer $TOKEN" \
"https://your-domain.com/api/reporting/inbound?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59&group_ext=101"
Response 200
{
"success": true,
"data": {
"data": {
"data": [{
"call_time": "2025-01-15 09:22:10 AM",
"queue_description": "Sales Queue",
"agent": "Agent Name",
"hangup_by": "Caller",
"ring_time": "00:00:18",
"talk_time": "00:04:32",
"caller_number": "0501234567",
"listen_url": "https://your-domain.com/api/reporting/listen/1736929330.1452"
}],
"total": 342,
"per_page": 10,
"current_page": 1,
"last_page": 34
}
},
"message": "Inbound calls retrieved successfully"
}
2.2 Get Call Transfers
GET/api/reporting/inbound/{linkedid}/transfers
cURL Example
curl -H "Authorization: Bearer $TOKEN" \
https://your-domain.com/api/reporting/inbound/1736929330.1452/transfers
Response 200
{
"success": true,
"data": [
{
"calldate": "2025-01-15 09:23:11",
"src": "1001",
"dst": "1002",
"duration": 95,
"billsec": 88,
"disposition": "ANSWERED"
}
],
"message": "Transfers retrieved successfully"
}
2.3 Mark Inbound Call as Done
POST/api/reporting/inbound/done/{id}
Response 200
{
"success": true,
"data": {
"id": "1736929330.1452"
},
"message": "Inbound call marked as done"
}
2.4 Inbound Distribution
GET/api/reporting/inDist
Data source: inbound_reports (one row per call; rows are classified by call_status — answered or missed) — same table as the Inbound and Inbound & Missed reports; no CDR / queuelog dependency. Response structure unchanged; filters additionally echoes the applied group_ext (additive, null when not provided).
| Parameter | Type | Required | Description |
daterange | string | No | "YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss" |
group_ext | int | No | Group (queue) ID — narrows to that one queue within the caller's visible queues (same as Inbound) |
Response includes
{
"hours_table": [
{
"label": "08:00",
"answord": 45,
"missed": 5,
"rate": "90.0 %"
}
],
"days_table": [
{
"label": "Sunday",
"answord": 120,
"missed": 18,
"rate": "87.0 %"
}
],
"months_table": [
{
"label": "2025-01",
"answord": 890,
"missed": 110,
"rate": "89.0 %"
}
]
}
3 Outbound Calls
3.1 List Outbound Calls
GET/api/reporting/outbound
| Parameter | Type | Required | Description |
daterange | string | No | Date range filter |
did_ext | string | No | Filter by source extension |
user_ext | string | No | Filter by user ID |
search | string | No | Search by destination number |
page | int | No | Default: 1 |
per_page | int | No | Default: 10 |
Response 200
{
"status": true,
"data": {
"data": {
"current_page": 1,
"data": [
{
"call_time": "2025-01-15 10:05:22 AM",
"linkedid": "1736929330.1452",
"total_duration": "00:02:05",
"talk_time": "00:01:50",
"ring_time": "00:00:15",
"disposition": "ANSWERED",
"dialed_number": "0501234567",
"agent_ext": "1001",
"agent_name": "Agent Name",
"listen_url": "/api/reporting/listen/1736929330.1452",
"listen_status": "done"
}
],
"total": 87,
"per_page": 10,
"last_page": 9
},
"filters": {
"daterange": "2025-01-15 00:00:00 - 2025-01-15 23:59:59",
"did_ext": null,
"user_ext": null,
"search": null
}
},
"message": "Outbound calls retrieved successfully",
"errors": []
}
3.2 Mark Outbound Call as Done
POST/api/reporting/outbound/done/{id}
Response 200
{
"status": true,
"data": {
"id": "1736929330.1452"
},
"message": "Outbound call marked as done",
"errors": []
}
3.3 Outbound Distribution
GET/api/reporting/outDist
Data source: outbound_reports (one row per call) — same table and query logic as the Outbound Calls report; no CDR / queuelog dependency. Response structure, field names, labels, and formats unchanged.
| Parameter | Type | Required | Description |
daterange | string | No | "YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss" |
Response 200
{
"status": true,
"data": {
"months": {
"labels": ["01-2025", "02-2025"],
"data": [320, 410],
"chart_data": {
"answered": [260, 340],
"busy": [20, 30],
"failed": [15, 18],
"unanswered": [25, 22]
}
},
"days": {
"labels": ["2025-01-15", "2025-01-16"],
"data": [48, 92],
"chart_data": {
"answered": [38, 78],
"busy": [3, 6],
"failed": [2, 4],
"unanswered": [5, 4]
}
},
"hours": {
"labels": ["08", "09"],
"data": [12, 35],
"chart_data": {
"answered": [10, 29],
"busy": [1, 2],
"failed": [0, 2],
"unanswered": [1, 2]
}
},
"summary": {
"total_answered": 600,
"total_unanswered": 95,
"total_busy": 50,
"total_failed": 33,
"total_calls": 695,
"success_rate": 86.3
},
"filters": {
"daterange": "2025-01-15 00:00:00 - 2025-01-31 23:59:59"
}
},
"message": "Outbound distribution data retrieved successfully",
"errors": []
}
4 Missed Calls
4.1 List Missed Calls
GET/api/reporting/missed
| Parameter | Type | Required | Description |
daterange | string | No | Date range filter |
queuename | string | No | Filter by queue ID |
search | string | No | Search by queue name, caller number, or DID |
page | int | No | Default: 1 |
per_page | int | No | Default: 10 |
Response 200
{
"status": true,
"data": {
"data": {
"current_page": 1,
"data": [
{
"callid": "1736929282.1440",
"call_time": "2025-01-15 09:08:02 AM",
"queuename": "101",
"queue_name": "Sales Queue",
"hangup_type": "ABANDON",
"hangup_reason": "NO AGENT",
"ring_duration": "00:00:45",
"caller_number": "0501234567",
"ring_details": [
{
"agent": "SIP/1001",
"event": "RINGNOANSWER",
"ring_duration": "00:00:18",
"time": "2025-01-15 09:08:05"
}
],
"done_by": null
}
],
"total": 42,
"per_page": 10,
"last_page": 5
},
"filters": {
"daterange": "2025-01-15 00:00:00 - 2025-01-15 23:59:59",
"queuename": null,
"search": null
},
"options": {
"queues": { "1": "Sales", "2": "Support" }
}
},
"message": "Missed calls retrieved successfully",
"errors": []
}
4.2 Get Ring Details
GET/api/reporting/ring-details/{callid}
Response 200
{
"status": true,
"data": {
"ring_details": [
{
"agent": "SIP/1001",
"event": "RINGNOANSWER",
"ring_duration": "00:00:18",
"time": "2025-01-15 09:10:05"
}
],
"inbound_calls": [],
"outbound_calls": [],
"active_missed_calls": [],
"ring_details_count": 1,
"inbound_calls_count": 0,
"outbound_calls_count": 0,
"active_missed_calls_count": 0
},
"message": "Ring details retrieved",
"errors": []
}
4.3 Mark Missed Call as Done
POST/api/reporting/missed-done/{num}
Response 200
{
"status": true,
"data": {
"caller_number": "0501234567",
"done_by": 12
},
"message": "Missed call marked as done",
"errors": []
}
4.4 Missed Call Statistics
GET/api/reporting/missed/stats
Response 200
{
"status": true,
"data": {
"status_data": {
"labels": ["ABANDON", "EXITWITHTIMEOUT"],
"counts": [65, 22]
},
"reason_data": {
"labels": ["Unknown", "Busy", "Timeout"],
"counts": [45, 28, 14]
},
"total_missed": 87,
"filters": {
"daterange": "2025-01-15 00:00:00 - 2025-01-15 23:59:59"
}
},
"message": "Missed call stats retrieved successfully",
"errors": []
}
5 Attendance
5.1 Attendance Log
GET/api/reporting/attendance
Data source: attendance — the canonical AMI event store, the same source as the web Attendance report (activity_log is no longer used). Response structure, field names, labels, and formats unchanged.
| Parameter | Type | Required | Description |
daterange | string | No | Date range filter |
user_ext | int | No | Filter by user ID |
group_ext | int | No | Filter by group ID |
search | string | No | Search by user name |
page | int | No | Default: 1 |
per_page | int | No | Default: 10 |
Response 200
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"created_at": "2025-01-15 08:01:22",
"agent_id": 12,
"status": "logged in",
"pause_reason": null,
"agent_name": "Agent Name",
"agent_email": "agent@company.com",
"duration": "00d 00h 58m 30s"
}
],
"total": 158,
"per_page": 10,
"last_page": 16
},
"filters": {
"daterange": "2025-01-15 00:00:00 - 2025-01-15 23:59:59",
"user_ext": null,
"group_ext": null
},
"message": "Attendance data retrieved successfully"
}
5.2 Attendance Summary
GET/api/reporting/attendance/summary
Response 200
{
"success": true,
"data": {
"summary": [
{
"agent_id": 12,
"agent_name": "Agent Name",
"agent_email": "agent@company.com",
"total_online": "07:30:00",
"total_paused": "00:45:00",
"total_offline": "00:15:00",
"code": "1001",
"logged_in_time": "07:30:00",
"pause_time": "00:45:00",
"reachable_time": "00:15:00",
"total_time": "08:30:00",
"LOGGED_IN_formatted": "07:30:00",
"pause_formatted": "00:45:00",
"Reachable_formatted": "00:15:00",
"total_formatted": "08:30:00"
}
],
"filters": {
"daterange": "2025-01-15 00:00:00 - 2025-01-15 23:59:59",
"user_ext": null,
"group_ext": null
}
},
"message": "Attendance data retrieved successfully"
}
5.3 List Users
GET/api/reporting/attendance/users
Response 200
{
"success": true,
"data": {
"agents": [
{ "id": 12, "name": "Agent Name", "email": "agent@company.com" },
{ "id": 13, "name": "Agent Two", "email": "agent2@company.com" }
]
},
"message": "Users retrieved"
}
5.4 List Groups
GET/api/reporting/attendance/groups
Response 200
{
"success": true,
"data": {
"groups": [
{ "id": 101, "name": "Sales Queue" },
{ "id": 102, "name": "Support Queue" }
]
},
"message": "Groups retrieved"
}
6 Performance
6.1 Inbound Performance
GET/api/reporting/performance
| Parameter | Type | Required | Description |
daterange | string | No | Date range filter |
user_ext | string | No | Filter by agent extension |
group_ext | int | No | Filter by queue / group ID |
Response 200
{
"summary": {
"overall_total_calls": 500,
"overall_answered_calls": 440,
"overall_dropped_calls": 40,
"overall_failover_calls": 20,
"overall_talk_time": "01:20:35",
"average_ring_time": "00:00:22",
"average_call_time": "00:02:50",
"service_level": {
"0_to_5": 120,
"6_to_10": 95,
"11_to_15": 80,
"16_to_20": 60,
"21_to_25": 40,
"26_to_30": 25,
"31_to_35": 12,
"36_to_40": 5,
"41_to_up": 3
},
"overall_ring_time": "00:03:02",
"overall_total_transfers": 5,
"service_level_over": 82.4
},
"agents": [
{
"agent_id": 5,
"agent_name": "Agent Name",
"agent_calls": 42,
"inbound_rejected": 3,
"inbound_noanswer": 5,
"avg_ring_time": "00:00:10",
"total_talk_time": "03:12:00",
"avg_talk_time": "00:04:34",
"agent_hangup": 18,
"customer_hangup": 24,
"avg_handle_time": "00:09:08",
"agent_transfers": 2,
"transferred_out": 0,
"transferred_in": 0,
"agent_code": "1001"
}
],
"queues": [
{
"overall_total_callsForQueue": 210,
"overall_answered_callsForQueue": 190,
"overall_dropped_callsForQueue": 12,
"overall_failover_callsForQueue": 8,
"overall_ring_timeForQueue": 2520,
"overall_talk_timeForQueue": "01:10:00",
"average_ring_timeForQueue": "00:00:12",
"average_call_timeForQueue": "00:02:13",
"queueExt": "101",
"queueName": "Sales Queue",
"overall_transfers_countForQueue": 3
}
],
"filters": {
"daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59",
"group_ext": null
}
}
6.2 Outbound Performance
GET/api/reporting/outPerformance
| Parameter | Type | Required | Description |
daterange | string | No | Date range filter |
user_ext | int | No | Filter by user ID |
Response 200
{
"summary": {
"agents_count": 8,
"total_calls": 320,
"answered_calls": 210,
"no_answer_calls": 70,
"busy_calls": 25,
"failed_calls": 15,
"total_duration": "28:14:00",
"avg_duration": "00:05:17",
"total_talk_time": "22:08:00",
"avg_talk_time": "00:06:19"
},
"by_agent": [
{
"agent_ext": "1001",
"agent_name": "Agent Name",
"agent_code": "1001",
"total_calls": 40,
"answered_calls": 28,
"avg_talk_time": "00:05:50"
}
],
"by_date": [
{
"call_date": "2025-01-15",
"agent_ext": "1001",
"total_calls": 12,
"answered_calls": 9
}
],
"filters": {
"daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59",
"user_ext": null
}
}
7 Blacklist
7.1 List Blacklist
GET/api/reporting/blacklist
| Parameter | Type | Required | Description |
search | string | No | Filter by phone number (partial match) |
page | int | No | Default: 1 |
per_page | int | No | Default: 10 |
Response 200
{
"success": true,
"data": {
"current_page": 1,
"data": [
{ "number": "0501112233", "description": "Spam caller" },
{ "number": "0509998877", "description": null }
],
"total": 24,
"per_page": 10,
"last_page": 3
},
"total": 24
}
7.2 Add to Blacklist
POST/api/reporting/blacklistAdd
The number field is required. Returns 422 if missing. The value "1" is reserved and not allowed for desc.
Request Body
{ "number": "0509999999", "desc": "Spam caller" }
| Field | Type | Required | Description |
number | string | Yes | Phone number or CallerID to block |
desc | string | No | Human-readable reason. Value "1" is reserved. |
Response 200
{
"success": true,
"data": {
"number": "0509999999"
},
"message": "0509999999 Blocked Successfully"
}
8 Call Recordings
8.1 List Calls with Recordings
GET/api/reporting/calls
| Parameter | Type | Required | Description |
daterange | string | No | Date range filter |
search | string | No | Free-text search |
page | int | No | Default: 1 |
Response 200
{
"success": true,
"data": {
"calls": {
"current_page": 1,
"data": [
{
"linkedid": "1736929330.1452",
"direction": "Inbound",
"status": "Answered",
"talktime_formatted": "01:45",
"recording_path": "/api/reporting/listen/1736929330.1452"
}
],
"total": 214,
"per_page": 10,
"last_page": 22
},
"filters": {
"daterange": "2025-01-15 00:00:00 - 2025-01-15 23:59:59",
"search": null
}
},
"message": "Calls retrieved successfully"
}
8.2 Stream a Recording
GET/api/reporting/listen/{id}
Returns the audio file as a stream (audio/wav). Use the listen_url field returned in call list responses.
cURL Download Example
curl -H "Authorization: Bearer $TOKEN" \
-o call.wav \
https://your-domain.com/api/reporting/listen/1736929330.1452
@can('leads.browse')
9 Leads API
9.1 List Leads
GET/api/leads/
Returns paginated lead records. Each item contains the complete lead object plus an optional index_fields array of pre-selected display values.
| Parameter | Type | Description |
search | string | Searches name, email, phone, mobile |
lead_status_id | int|csv | Filter by status ID(s) |
lead_source_id | int|csv | Filter by source ID(s) |
lead_industry_id | int|csv | Filter by industry ID(s) |
lead_rating_id | int|csv | Filter by rating ID(s) |
email / phone / mobile | string | Partial match |
company_name | string | Partial company name |
created_from / created_to | Y-m-d | Date range |
per_page | int | Default 15 |
Response (each item)
{
"id": 42,
"first_name": "Jane", "last_name": "Smith",
"email": "jane@example.com",
"lead_status_id": 1,
"priority_score": 8,
/* … all other fields … */
"index_fields": [
{ "key": "full_name", "label": "Full Name", "value": "Jane Smith" }
]
}
9.2 Get Lead
GET/api/leads/get/{id}
Response
{
"lead": {
"id": 42, "first_name": "Jane", "last_name": "Smith",
"lead_status_id": 1, "priority_score": 8,
/* … all fields as flat keys … */
}
}
9.3 Create Lead
POST/api/leads/create
Request body
{
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"lead_status_id": 1,
"priority_score": 8
}
9.4 Update Lead
POST/api/leads/update/{id}
Send only the fields you want to change. All fields are optional.
9.5 Delete Lead
DELETE/api/leads/delete/{id}
Lookup helpers
GET/api/leads/all-statuses
GET/api/leads/all-sources
GET/api/leads/all-industries
GET/api/leads/all-ratings
@endcan
@can('contacts.browse')
@endcan
@can('calllogs.browse')
11 Call Logs API
All request fields are sent as flat top-level keys. Responses always return a uniform flat object — all field types are indistinguishable from the client perspective.
11.1 List Call Logs
GET/api/calllogs/
| Parameter | Type | Description |
search | string | Searches phone number, subject, notes |
direction | string | inbound | outbound |
status | string | Partial match on call status |
source | string | Partial match on call source |
outcome | string | Partial match on call outcome |
user_id | int|csv | Filter by agent user ID |
lead_id / contact_id | int|csv | Filter by linked entity |
call_date_from / call_date_to | Y-m-d | Call date range |
follow_up_from / follow_up_to | Y-m-d | Follow-up date range |
created_from / created_to | Y-m-d | Created date range |
sort_by | string | phone_number | call_date | status | source | outcome | created_at |
sort_dir | string | asc | desc (default desc) |
per_page | int | Default 15 |
11.2 Get Call Log
GET/api/calllogs/get/{id}
Response
{
"call_log": {
"id": 5,
"phone_number": "01000000000",
"direction": "inbound",
"subject": "Support call",
"status": "New",
"call_rating": "Good",
/* … all other fields … */
}
}
11.3 Create / Update / Delete
POST/api/calllogs/create
POST/api/calllogs/update/{id}
DELETE/api/calllogs/delete/{id}
Create request body
{
"phone_number": "01000000000",
"direction": "inbound",
"call_date": "2026-07-16 10:00:00",
"subject": "Support call",
"status": "New",
"lead_id": 42,
"call_rating": "Good"
}
For updates, all fields are optional. Send only the fields you want to change.
@endcan
@can('tickets.browse')
12 Tickets API
All request fields are sent as flat top-level keys. Responses return a uniform flat object — all field types are indistinguishable from the client perspective.
12.1 List Tickets
GET/api/tickets/
| Parameter | Type | Description |
search | string | Searches name, description, notes and related entity names |
ticket_status_id | int|csv|array | Filter by status |
ticket_priority_id | int|csv|array | Filter by priority |
ticket_severity_id | int|csv|array | Filter by severity |
ticket_category_id | int|csv|array | Filter by category |
contact_id / lead_id / account_id | int|csv | Filter by related entity |
ticket_owner_id | int|csv | Filter by owner |
name | string | Partial text match |
status_name / priority_name / category_name | string | Partial match on related name |
due_date_from / due_date_to | Y-m-d | Due date range |
created_from / created_to | Y-m-d | Created date range |
sort_by | string | id | name | due_date | created_at | ticket_status_id |
sort_dir | string | asc | desc (default desc) |
per_page | int | Default 15 |
12.2 Get Ticket
GET/api/tickets/get/{id}
Response
{
"ticket": {
"id": 9,
"name": "Login page broken",
"ticket_status_id": 1,
"owned_by": "user-5",
"internal_ref": "BUG-2026-001",
/* … all other fields … */
}
}
12.3 Create / Update / Delete
POST/api/tickets/create
POST/api/tickets/update/{id}
DELETE/api/tickets/delete/{id}
Create request body
{
"name": "Login page broken",
"ticket_status_id": 1,
"ticket_priority_id": 2,
"contact_id": 7,
"description": "Cannot log in since the 2026-07-15 deployment.",
"internal_ref": "BUG-2026-001"
}
For updates, all fields are optional. Send only the fields you want to change.
Lookup helpers
GET/api/tickets/all-statuses
GET/api/tickets/all-priorities
GET/api/tickets/all-severities
GET/api/tickets/all-categories
@endcan
@can('sms.browse')
13 SMS API
13.1 Send SMS
POST/api/sms/send
Sends an SMS message and saves a record to the sms_msg table.
| Field | Type | Required | Description |
phone_number | string | Yes | Destination phone number (max 30 chars) |
message | string | Yes | SMS text content (max 1000 chars) |
cURL Example
curl -X POST https://your-domain.com/api/sms/send \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"phone_number":"01000000000","message":"Hello from API"}'
Response 200
{
"success": true,
"data": {
"sms_id": 123,
"status": "Sent"
},
"message": "SMS sent successfully"
}
Response 500 (send failure)
{
"success": false,
"data": {
"sms_id": 123,
"status": "Failed"
},
"errors": { "error": "Failed to send SMS" },
"message": "Failed to send SMS"
}
Requires the sms.create permission.
13.2 Check SMS Quota
GET/api/sms/quota
Returns the remaining SMS balance or credits from the configured provider.
cURL Example
curl -H "Authorization: Bearer $TOKEN" \
https://your-domain.com/api/sms/quota
Response
{
"success": true,
"data": {
"credits": 450
},
"message": "Quota fetched successfully"
}
Requires the sms.browse permission.
@endcan
@can('user.settings')
16 User Management
Users are managed with three endpoints. All of them require the same authentication as the rest of the
API:
Authorization: Bearer <your_jwt_token>
16.1 List Users
GET/api/users
Query parameters
| Parameter | Type | Required | Description |
per_page | int | No | Users per page (default 10) |
Example
curl -H "Authorization: Bearer $TOKEN" \
"https://your-domain.com/api/users?per_page=10"
Response (200)
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"extension": 997,
"first_name": "Ahmed",
"last_name": "",
"email": "ahmed@example.com",
"server": "https://your-domain.com",
"created_at": "2026-10-08 12:00:00"
}
],
"per_page": 10,
"total": 1
}
}
16.2 Create User
POST/api/users
Body
| Parameter | Type | Required | Description |
name | string | Yes | Full name |
email | string | Yes | Valid email address |
password | string | Yes | Password |
Example
curl -X POST https://your-domain.com/api/users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Ahmed","email":"ahmed@example.com","password":"Secret123"}'
Response (201)
{
"success": true,
"message": "User created successfully.",
"data": {
"extension": 997,
"name": "Ahmed",
"first_name": "Ahmed",
"last_name": "",
"email": "ahmed@example.com",
"server": "https://your-domain.com"
}
}
Save the returned user ID. The response contains our internal user ID in
data.extension. Use it for later calls that take a user id, such as
DELETE /api/users/{id}.
Validation error (422)
{
"success": false,
"message": "Full Name is required. Valid Email is required.",
"errors": [
"Full Name is required.",
"Valid Email is required."
]
}
16.3 Delete User
DELETE/api/users/{id}
Path parameters
| Parameter | Type | Required | Description |
id | int | Yes | Our internal user ID (data.extension from create) |
Example
curl -X DELETE https://your-domain.com/api/users/997 \
-H "Authorization: Bearer $TOKEN"
Response (200)
{
"success": true,
"message": "User deleted successfully."
}
Response (404)
{
"success": false,
"message": "User not found."
}
@endcan
@can('help.softphone.integration')
17 External Client Softphone Integration
Embed our Softphone in your own page without asking the user to log in again. One fixed iframe URL is used
for every user: https://your-domain.com/softphone/integration.
17.1 Step 1 — Configure the API URL and token
API URL — the base URL of our platform, for example
https://your-domain.com.
Token — the user's API token from POST /api/login. Send it on every request
below as Authorization: Bearer <token>. The token identifies the user, so you never send
a user id.
Send us the exact origin of your page (for example https://app.customer.com) so we can
allow-list it. The browser blocks the session request and refuses to display the iframe without it.
const API_URL = 'https://your-domain.com';
const token = '<user_api_token>'; // from POST /api/login
17.2 Step 2 — Request a session
POST/api/softphone/session
Call this from your front-end with the user's token. The response sets the session cookie and returns the iframe URL. No request body.
Request
Authorization: Bearer <user_api_token>
Response (201)
{
"success": true,
"iframe_url": "https://your-domain.com/softphone/integration"
}
Example
const res = await fetch(`${API_URL}/api/softphone/session`, {
method: 'POST',
credentials: 'include', // keeps the session cookie in the browser
headers: { Authorization: `Bearer ${token}` }
});
const { iframe_url } = await res.json();
17.3 Step 3 — Embed the iframe
Use the returned iframe_url. The cookie you just received signs the user in inside the iframe.
<iframe
src="https://your-domain.com/softphone/integration"
allow="microphone; autoplay"
style="width:100%;height:100%;border:0;">
</iframe>
17.4 Step 4 — Revoke the session
POST/api/softphone/session/revoke
Closing the iframe does not end the session. Call this when the user logs out or leaves your page.
Request
Authorization: Bearer <user_api_token>
Response (200)
{
"success": true,
"revoked": 1
}
@endcan
14 Error Reference
All responses share this envelope structure:
{ "status": true|false, "data": {}, "message": "...", "errors": [] }
| Status | Meaning |
| 200 | Success |
| 401 | Invalid or missing token |
| 403 | Insufficient permissions |
| 404 | Record not found |
| 422 | Missing or invalid parameters |
| 500 | Server error — contact support |
15 Route Summary
| Method | Endpoint | Description |
| POST | /api/login | Login and get access token |
@can('user.settings')
| GET | /api/users | List users |
| POST | /api/users | Create a user |
| DELETE | /api/users/{id} | Delete a user |
@endcan
| GET | /api/reporting/inbound | List answered inbound calls |
| GET | /api/reporting/inbound/{linkedid}/transfers | Get transfer legs of a call |
| POST | /api/reporting/inbound/done/{id} | Mark inbound call as done |
| GET | /api/reporting/inDist | Inbound call distribution |
| GET | /api/reporting/outbound | List outbound calls |
| POST | /api/reporting/outbound/done/{id} | Mark outbound call as done |
| GET | /api/reporting/outDist | Outbound call distribution |
| GET | /api/reporting/missed | List missed calls |
| GET | /api/reporting/ring-details/{callid} | Ring attempt history |
| POST | /api/reporting/missed-done/{num} | Mark missed caller as handled |
| GET | /api/reporting/missed/stats | Missed call type/reason stats |
| GET | /api/reporting/attendance | Attendance event log |
| GET | /api/reporting/attendance/summary | Per-agent attendance totals |
| GET | /api/reporting/attendance/users | List company users |
| GET | /api/reporting/attendance/groups | List company groups / queues |
| GET | /api/reporting/performance | Inbound queue performance |
| GET | /api/reporting/outPerformance | Outbound agent performance |
| GET | /api/reporting/blacklist | List blacklisted numbers |
| POST | /api/reporting/blacklistAdd | Add number to blacklist |
| GET | /api/reporting/calls | List calls with recordings |
| GET | /api/reporting/listen/{id} | Stream recording audio file |
@can('leads.browse')
| CRM — Leads |
| GET | /api/leads/ | Paginated lead list with API index fields |
| GET | /api/leads/get/{id} | Lead record with field metadata and values |
| POST | /api/leads/create | Create a lead |
| POST | /api/leads/update/{id} | Update a lead |
| DELETE | /api/leads/delete/{id} | Delete a lead |
| GET | /api/leads/all-statuses | Available lead statuses |
| GET | /api/leads/all-sources | Available lead sources |
| GET | /api/leads/all-industries | Available industries |
| GET | /api/leads/all-ratings | Available ratings |
@endcan
@can('contacts.browse')
| CRM — Contacts |
| GET | /api/contacts/ | Paginated contact list with API index fields |
| GET | /api/contacts/get/{id} | Contact record with field metadata |
| POST | /api/contacts/create | Create a contact |
| POST | /api/contacts/update/{id} | Update a contact |
| DELETE | /api/contacts/delete/{id} | Delete a contact |
| GET | /api/contacts/all-statuses | Available contact statuses |
| GET | /api/contacts/all-sources | Available contact sources |
@endcan
@can('calllogs.browse')
| CRM — Call Logs |
| GET | /api/calllogs/ | Paginated call log list with API index fields |
| GET | /api/calllogs/get/{id} | Call log record with field metadata |
| POST | /api/calllogs/create | Create a call log |
| POST | /api/calllogs/update/{id} | Update a call log |
| DELETE | /api/calllogs/delete/{id} | Delete a call log |
@endcan
@can('tickets.browse')
| CRM — Tickets |
| GET | /api/tickets/ | Paginated ticket list with API index fields |
| GET | /api/tickets/get/{id} | Ticket record with field metadata |
| POST | /api/tickets/create | Create a ticket |
| POST | /api/tickets/update/{id} | Update a ticket |
| DELETE | /api/tickets/delete/{id} | Delete (soft delete) a ticket |
| GET | /api/tickets/all-statuses | Available ticket statuses |
| GET | /api/tickets/all-priorities | Available ticket priorities |
| GET | /api/tickets/all-severities | Available ticket severities |
| GET | /api/tickets/all-categories | Available ticket categories |
@endcan
@can('sms.browse')
| SMS |
| POST | /api/sms/send | Send an SMS and save the record |
| GET | /api/sms/quota | Get remaining SMS balance / credits |
@endcan
@can('help.softphone.integration')
| Integrations — External Client Softphone |
| POST | /api/softphone/session | Create the browser session for the authenticated user |
| POST | /api/softphone/session/revoke | End the authenticated user's sessions |
| GET | /softphone/integration | Fixed iframe page (requires the authenticated session) |
@endcan