# API Integration Guide

**Base URL**: `https://your-domain.com/api`

All endpoints (except login) require:
```
Authorization: Bearer <your_jwt_token>
```

---

## Table of Contents

1. [Authentication](#1-authentication)
2. [Inbound Calls](#2-inbound-calls)
3. [Outbound Calls](#3-outbound-calls)
4. [Missed Calls](#4-missed-calls)
5. [Attendance](#5-attendance)
6. [Performance](#6-performance)
7. [Blacklist](#7-blacklist)
8. [Call Recordings](#8-call-recordings)
9. [Agent Call Details](#9-agent-call-details)
10. [Error Reference](#10-error-reference)
11. [Route Summary](#11-route-summary)
12. [User Management](#12-user-management)
13. [External Client Softphone Integration](#13-external-client-softphone-integration)

---

## 1. Authentication

### Login

```
POST /api/login
```

**Body**

```json
{
  "email": "user@example.com",
  "password": "your_password"
}
```

**Example**
```bash
curl -X POST https://your-domain.com/api/login \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"your_password"}'
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "user": {
      "id": 12,
      "name": "Ahmed Ali",
      "email": "user@example.com"
    }
  }
}
```

**Response (401)**
```json
{
  "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/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 |

**Example**
```bash
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)**
```json
{
  "success": true,
  "data": {
    "data": {
      "data": [
        {
          "call_time": "2025-01-15 09:22:10 AM",
          "queue_description": "Sales Queue",
          "enter_queuename": "101",
          "agent": "Ahmed Ali",
          "hangup_by": "Caller",
          "ring_time": "00:00:18",
          "talk_time": "00:04:32",
          "caller_number": "0501234567",
          "did": "800100",
          "transfers_count": 0,
          "survey": null,
          "linkedid": "1736929330.1452",
          "listen_url": "https://your-domain.com/api/reporting/listen/1736929330.1452",
          "listen_status": "pending"
        }
      ],
      "total": 342,
      "per_page": 10,
      "current_page": 1,
      "last_page": 34
    },
    "filters": {
      "daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59",
      "did_ext": null,
      "user_ext": null,
      "group_ext": null,
      "search": null
    }
  },
  "errors": [],
  "message": "Inbound calls retrieved successfully"
}
```

---

### 2.2 Get Call Transfers

```
GET /api/reporting/inbound/{linkedid}/transfers
```

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/inbound/1736929330.1452/transfers
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "transfers": [
      {
        "calldate": "2025-01-15 09:22:28",
        "duration": 18,
        "user_extension": "205",
        "user_name": "Ahmed Ali"
      }
    ],
    "count": 1
  },
  "errors": [],
  "message": "Transfer data retrieved"
}
```

---

### 2.3 Mark Inbound Call as Done

```
POST /api/reporting/inbound/done/{id}
```

**Example**
```bash
curl -X POST -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/inbound/done/98765
```

**Response (200)**
```json
{
  "success": true,
  "data": { "id": "98765" },
  "errors": [],
  "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) |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/inDist?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "hours_table": [
      { "label": "08:00", "answord": 45, "missed": 5, "offered": 50, "rate": "90.0 %" }
    ],
    "days_table": [
      { "label": "Sunday", "answord": 120, "missed": 18, "offered": 138, "rate": "87.0 %" }
    ],
    "months_table": [
      { "label": "2025-01", "answord": 890, "missed": 110, "offered": 1000, "rate": "89.0 %" }
    ]
  },
  "errors": [],
  "message": "Inbound distribution retrieved"
}
```

---

## 3. Outbound Calls

### 3.1 List Outbound Calls

```
GET /api/reporting/outbound
```

| 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 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 |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/outbound?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59&user_ext=205"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "data": {
      "data": [
        {
          "call_time": "2025-01-15 10:05:33 AM",
          "linkedid": "1736932000.2001",
          "total_duration": "00:03:15",
          "talk_time": "00:03:10",
          "ring_time": "00:00:05",
          "disposition": "ANSWERED",
          "dialed_number": "0501112222",
          "agent_ext": "205",
          "recording": "out-205-1736932000.2001.wav",
          "agent_name": "Mohammed Hassan",
          "listen_url": "https://your-domain.com/api/reporting/listen/1736932000.2001",
          "listen_status": "done"
        }
      ],
      "total": 128,
      "per_page": 10,
      "current_page": 1,
      "last_page": 13
    },
    "filters": {
      "daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59",
      "did_ext": null,
      "user_ext": "205",
      "search": null
    }
  },
  "errors": [],
  "message": "Outbound calls retrieved successfully"
}
```

---

### 3.2 Mark Outbound Call as Done

```
POST /api/reporting/outbound/done/{linkedid}
```

**Example**
```bash
curl -X POST -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/outbound/done/1736932000.2001
```

**Response (200)**
```json
{
  "success": true,
  "data": { "id": "1736932000.2001" },
  "errors": [],
  "message": "Outbound call marked as done"
}
```

---

### 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"` |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/outDist?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "hours_table": [
      { "label": "09:00", "calls": 22, "answered": 18 }
    ],
    "days_table": [
      { "label": "Monday", "calls": 55, "answered": 48 }
    ],
    "months_table": [
      { "label": "2025-01", "calls": 590, "answered": 510 }
    ]
  },
  "errors": [],
  "message": "Outbound distribution retrieved"
}
```

---

## 4. Missed Calls

### 4.1 List Missed Calls

```
GET /api/reporting/missed
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |
| queuename | string | No       | Filter by queue ID |
| search    | string | No       | Search by caller number |
| page      | int    | No       | Default: 1 |
| per_page  | int    | No       | Default: 10 |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/missed?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59&queuename=101"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "data": {
      "data": [
        {
          "call_time": "2025-01-15 11:30:22 AM",
          "callid": "1736929800.1601",
          "caller_name": "",
          "caller_number": "0509876543",
          "queuename": "101",
          "queue_name": "Support Queue",
          "hangup_type": "ABANDON",
          "hangup_reason": "NOANSWER",
          "ring_duration": "00:00:42",
          "done_by": null,
          "ring_details": [
            {
              "agent": "Ahmed Ali",
              "event": "RINGNOANSWER",
              "ring_duration": "00:00:20",
              "time": "2025-01-15 11:30:25"
            }
          ]
        }
      ],
      "total": 87,
      "per_page": 10,
      "current_page": 1,
      "last_page": 9
    },
    "filters": {
      "daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59",
      "queuename": null,
      "search": null
    },
    "options": {
      "queues": { "101": "Support Queue" }
    }
  },
  "errors": [],
  "message": "Missed calls retrieved successfully"
}
```

---

### 4.2 Get Ring Details

```
GET /api/reporting/ring-details/{callid}
```

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/ring-details/1736929800.1601
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "ring_details": [
      {
        "agent": "Ahmed Abdo",
        "event": "RINGNOANSWER",
        "ring_duration": "00:00:20",
        "time": "2025-01-15 11:30:25"
      }
    ],
    "inbound_calls": [ ],
    "outbound_calls": [ ],
    "active_missed_calls": [ ],
    "ring_details_count": 1,
    "inbound_calls_count": 0,
    "outbound_calls_count": 0,
    "active_missed_calls_count": 0
  },
  "errors": [],
  "message": "Ring details retrieved"
}
```

---

### 4.3 Mark Missed Call as Done

```
POST /api/reporting/missed-done/{caller_number}
```

**Example**
```bash
curl -X POST -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/missed-done/0509876543
```

**Response (200)**
```json
{
  "success": true,
  "data": { "caller_number": "0509876543", "done_by": 12 },
  "errors": [],
  "message": "Missed call marked as done"
}
```

**Response (404)**
```json
{
  "success": false,
  "data": {},
  "errors": { "error": "Number not found or already marked" },
  "message": "Not Found"
}
```

---

### 4.4 Missed Call Statistics

```
GET /api/reporting/missed/stats
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/missed/stats?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59"
```

**Response (200)**
```json
{
  "success": 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-01 00:00:00 - 2025-01-31 23:59:59"
    }
  },
  "errors": [],
  "message": "Missed call stats retrieved successfully"
}
```

---

## 5. Attendance

### 5.1 Attendance Log

```
GET /api/reporting/attendance
```

Reads the `attendance` table — 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 are unchanged.

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |
| 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 |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/attendance?daterange=2025-01-15+00:00:00+-+2025-01-15+23:59:59&user_ext=12"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "data": {
      "data": [
        {
          "event_time": "2025-01-15 08:01:22",
          "agent_id": 12,
          "status": "LOGGED_IN",
          "pause_reason": null,
          "agent_name": "Ahmed Ali",
          "agent_email": "ahmed@example.com",
          "duration": "00d 02h 29m 00s"
        },
        {
          "event_time": "2025-01-15 10:30:00",
          "agent_id": 12,
          "status": "pause",
          "pause_reason": "Lunch Break",
          "agent_name": "Ahmed Ali",
          "agent_email": "ahmed@example.com",
          "duration": "00d 00h 30m 00s"
        }
      ],
      "total": 210,
      "per_page": 10,
      "current_page": 1,
      "last_page": 21
    },
    "filters": {
      "daterange": "2025-01-15 00:00:00 - 2025-01-15 23:59:59",
      "user_ext": 12,
      "group_ext": null
    }
  },
  "errors": [],
  "message": "Attendance data retrieved successfully"
}
```

---

### 5.2 Attendance Summary

```
GET /api/reporting/attendance/summary
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |
| user_ext  | int    | No       | Filter by user ID |
| group_ext | int    | No       | Filter by group ID |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/attendance/summary?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59&group_ext=101"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "summary": [
      {
        "name": "Ahmed Ali",
        "email": "ahmed@example.com",
        "code": "1001",
        "pause_reasons": [
          { "reason": "Lunch Break", "duration": 1800, "formatted_duration": "00:30:00" },
          { "reason": "Meeting",     "duration": 900,  "formatted_duration": "00:15:00" }
        ],
        "logged_in_time": "07:32:00",
        "pause_time":     "00:45:00",
        "reachable_time": "06:47:00",
        "total_time":     "08:17:00",
        "LOGGED_IN_formatted": "07:32:00",
        "pause_formatted":     "00:45:00",
        "Reachable_formatted": "06:47:00",
        "total_formatted":     "08:17:00"
      }
    ],
    "filters": {
      "daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59",
      "user_ext": null,
      "group_ext": 101
    }
  },
  "errors": [],
  "message": "Attendance summary retrieved successfully"
}
```

> **Field notes**: `code` is the agent's `users.code` (empty when unset).
> `LOGGED_IN_formatted`, `pause_formatted`, `Reachable_formatted`, and
> `total_formatted` carry the same values as `logged_in_time`, `pause_time`,
> `reachable_time`, and `total_time`, exposed under the web report's field names
> (additive — the `*_time` fields are unchanged).

---

### 5.3 List Users

```
GET /api/reporting/attendance/users
```

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/attendance/users
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "users": [
      { "id": 12, "name": "Ahmed Ali" },
      { "id": 15, "name": "Sara Mohammed" }
    ]
  },
  "errors": [],
  "message": "Users retrieved"
}
```

---

### 5.4 List Groups

```
GET /api/reporting/attendance/groups
```

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/attendance/groups
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "groups": [
      { "id": 101, "name": "Sales Queue" },
      { "id": 102, "name": "Support Queue" }
    ]
  },
  "errors": [],
  "message": "Groups retrieved"
}
```

---

### 5.5 Pause Reasons

```
GET /api/reporting/attendance/pause-reasons
```

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  https://your-domain.com/api/reporting/attendance/pause-reasons
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "available_reasons": [
      { "name": "Lunch Break", "command": "pause", "color": "#FFA500", "icon": "fa-utensils" },
      { "name": "Meeting",     "command": "pause", "color": "#0000FF", "icon": "fa-users" }
    ],
    "used_reasons": [
      { "reason": "Lunch Break" },
      { "reason": "Meeting" },
      { "reason": "Prayer" }
    ]
  },
  "errors": [],
  "message": "Pause reasons retrieved"
}
```

---

### 5.6 Pause Reason Statistics

```
GET /api/reporting/attendance/pause-stats
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/attendance/pause-stats?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "statistics": [
      { "reason": "Lunch Break", "occurrence_count": 42, "total_duration": 75600, "formatted_duration": "21:00:00" },
      { "reason": "Meeting",     "occurrence_count": 18, "total_duration": 16200, "formatted_duration": "04:30:00" }
    ],
    "filters": { "daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59" }
  },
  "errors": [],
  "message": "Pause reason statistics retrieved"
}
```

---

## 6. Performance

### 6.1 Inbound Performance

```
GET /api/reporting/performance
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |
| user_ext  | string | No       | Filter by agent extension |
| group_ext | int    | No       | Filter by queue/group ID |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/performance?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59&group_ext=101"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "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": "Mohammed Hassan",
        "agent_calls": 120,
        "inbound_rejected": 3,
        "inbound_noanswer": 8,
        "avg_ring_time": "00:00:18",
        "total_talk_time": "01:20:35",
        "avg_talk_time": "00:00:40",
        "agent_hangup": 90,
        "customer_hangup": 30,
        "avg_handle_time": "00:01:20",
        "agent_transfers": 4,
        "transferred_out": 0,
        "transferred_in": 0,
        "agent_code": "205"
      }
    ],
    "queues": [
      {
        "overall_total_callsForQueue": 300,
        "overall_answered_callsForQueue": 270,
        "overall_dropped_callsForQueue": 20,
        "overall_failover_callsForQueue": 10,
        "overall_ring_timeForQueue": 5400,
        "overall_talk_timeForQueue": "01:20:35",
        "average_ring_timeForQueue": "00:00:20",
        "average_call_timeForQueue": "00:02:50",
        "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": 101 }
  },
  "errors": [],
  "message": "Performance report retrieved successfully"
}
```

> Business logic, data handling, and access restrictions mirror the web
> `reporting/performance` page exactly. Fields such as `overall_total_transfers`,
> `service_level_over`, `avg_handle_time`, and the transfer counters are additive
> mirrors of the web implementation; all pre-existing field names are unchanged.
> `group_ext` is an API-only convenience filter that only narrows results within
> already-accessible queues.

---

### 6.2 Outbound Performance

```
GET /api/reporting/outPerformance
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |
| user_ext  | int    | No       | Filter by user ID |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/outPerformance?daterange=2025-01-01+00:00:00+-+2025-01-31+23:59:59&user_ext=205"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "summary": {
      "agents_count": 5,
      "total_calls": 128,
      "answered_calls": 98,
      "no_answer_calls": 22,
      "busy_calls": 4,
      "failed_calls": 4,
      "total_duration": "05:12:00",
      "avg_duration": "00:02:26",
      "total_talk_time": "04:04:00",
      "avg_talk_time": "00:02:29"
    },
    "by_agent": [
      {
        "agent_ext": "205",
        "agent_name": "Mohammed Hassan",
        "agent_code": "205",
        "total_calls": 28,
        "answered_calls": 22,
        "no_answer_calls": 4,
        "busy_calls": 1,
        "failed_calls": 1,
        "total_duration": "01:24:00",
        "avg_duration": "00:03:00",
        "total_talk_time": "01:20:00",
        "avg_talk_time": "00:03:38"
      }
    ],
    "by_date": [
      {
        "call_date": "2025-01-15",
        "agent_ext": "205",
        "agent_name": "Mohammed Hassan",
        "total_calls": 12,
        "answered_calls": 10,
        "no_answer_calls": 1,
        "busy_calls": 1,
        "failed_calls": 0,
        "total_duration": "00:36:00",
        "avg_duration": "00:03:00",
        "total_talk_time": "00:33:20",
        "avg_talk_time": "00:03:20"
      }
    ],
    "filters": { "daterange": "2025-01-01 00:00:00 - 2025-01-31 23:59:59", "user_ext": "205" }
  },
  "errors": [],
  "message": "Outbound performance report retrieved successfully"
}
```

---

## 7. Blacklist

### 7.1 List Blacklist

```
GET /api/reporting/blacklist
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| search    | string | No       | Filter by phone number (partial match) |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/blacklist?search=0501234"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "blacklist": [
      { "number": "0501234567", "context": "from-pstn" },
      { "number": "0509999000", "context": "from-pstn" }
    ],
    "total": 2
  },
  "errors": [],
  "message": "Blacklist retrieved"
}
```

---

### 7.2 Add to Blacklist

```
POST /api/reporting/blacklistAdd
```

| Field  | Type   | Required | Description |
|--------|--------|----------|-------------|
| number | string | Yes      | Phone number to blacklist |

**Example**
```bash
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"number":"0509999999"}' \
  https://your-domain.com/api/reporting/blacklistAdd
```

**Response (200)**
```json
{
  "success": true,
  "data": { "number": "0509999999" },
  "errors": [],
  "message": "Number added to blacklist"
}
```

**Response (422)**
```json
{
  "success": false,
  "data": {},
  "errors": { "error": "Number is required" },
  "message": "Validation Error"
}
```

---

## 8. Call Recordings

### 8.1 List Calls with Recordings

```
GET /api/reporting/calls
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| daterange | string | No       | `"YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss"` |
| search    | string | No       | Free-text search |
| page      | int    | No       | Default: 1 |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/calls?daterange=2025-01-15+00:00:00+-+2025-01-15+23:59:59"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "calls": [
      {
        "linkedid": "1736929330.1452",
        "calldate": "2025-01-15 09:22:10",
        "src": "0501234567",
        "dst": "800100",
        "disposition": "ANSWERED",
        "duration": "00:04:32",
        "recordingfile": "q-101-1736929330.1452.wav",
        "listen_url": "/api/reporting/listen/1736929330.1452"
      }
    ],
    "pagination": { "total": 55, "per_page": 10, "current_page": 1, "last_page": 3 }
  },
  "errors": [],
  "message": "Calls retrieved successfully"
}
```

---

### 8.2 Stream a Recording

```
GET /api/reporting/listen/{linkedid}
```

Returns the audio file as a stream (`audio/wav`).

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  -o call.wav \
  https://your-domain.com/api/reporting/listen/1736929330.1452
```

**Response (404)**
```json
{
  "success": false,
  "data": {},
  "errors": { "error": "Recording not found" },
  "message": "Not Found"
}
```

---

## 9. Agent Call Details

### 9.1 Rejected Calls (BUSY)

```
GET /api/reporting/rejected-calls
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| user_id   | string | **Yes**  | Agent extension number |
| from      | string | **Yes**  | Start datetime `"YYYY-MM-DD HH:mm:ss"` |
| to        | string | **Yes**  | End datetime `"YYYY-MM-DD HH:mm:ss"` |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/rejected-calls?user_id=205&from=2025-01-01+00:00:00&to=2025-01-31+23:59:59"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "data": [
      {
        "call_time": "2025-01-15 10:05:00",
        "caller_number": "0501234567",
        "disposition": "BUSY",
        "duration": "00:00:04"
      }
    ],
    "count": 1,
    "filters": { "userId": "205", "from": "2025-01-01 00:00:00", "to": "2025-01-31 23:59:59" }
  },
  "errors": [],
  "message": "Rejected calls retrieved successfully"
}
```

**Response (422)**
```json
{
  "success": false,
  "data": {},
  "errors": { "error": "user_id, from and to are required" },
  "message": "Bad Request"
}
```

---

### 9.2 No-Answer / Failed Calls

```
GET /api/reporting/no-answer-calls
```

| Parameter | Type   | Required | Description |
|-----------|--------|----------|-------------|
| user_id   | string | **Yes**  | Agent extension number |
| from      | string | **Yes**  | Start datetime `"YYYY-MM-DD HH:mm:ss"` |
| to        | string | **Yes**  | End datetime `"YYYY-MM-DD HH:mm:ss"` |

**Example**
```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/reporting/no-answer-calls?user_id=205&from=2025-01-01+00:00:00&to=2025-01-31+23:59:59"
```

**Response (200)**
```json
{
  "success": true,
  "data": {
    "data": [
      { "call_time": "2025-01-15 09:10:00", "caller_number": "0509876543", "disposition": "NO ANSWER", "duration": "00:00:05" },
      { "call_time": "2025-01-14 14:35:00", "caller_number": "0501112233", "disposition": "FAILED",    "duration": "00:00:03" }
    ],
    "count": 2,
    "filters": { "userId": "205", "from": "2025-01-01 00:00:00", "to": "2025-01-31 23:59:59" }
  },
  "errors": [],
  "message": "No-answer calls retrieved successfully"
}
```

---

## 10. Error Reference

All responses follow this format:

```json
{
  "success": true | false,
  "data": { },
  "errors": { },
  "message": "..."
}
```

| 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 |

---

## 11. Route Summary

| Method | Endpoint                                        | Description                        |
|--------|-------------------------------------------------|------------------------------------|
| POST   | /api/login                                      | Login and get access token         |
| GET    | /api/users                                      | List users                         |
| POST   | /api/users                                      | Create a user                      |
| DELETE | /api/users/{id}                                 | Delete a user                      |
| 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/{linkedid}         | 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/{caller_number}      | 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/attendance/pause-reasons         | Configured pause reasons           |
| GET    | /api/reporting/attendance/pause-stats           | Pause reason usage stats           |
| 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/{linkedid}                | Stream recording audio file        |
| GET    | /api/reporting/rejected-calls                   | Agent rejected (BUSY) calls        |
| GET    | /api/reporting/no-answer-calls                  | Agent no-answer/failed calls       |
| 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) |

---

## 12. 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>
```

### 12.1 List Users

```
GET /api/users
```

**Query parameters**

| Parameter | Type | Required | Description                   |
|-----------|------|----------|-------------------------------|
| per_page  | int  | No       | Users per page (default `10`) |

**Example**

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://your-domain.com/api/users?per_page=10"
```

**Response (200)**

```json
{
  "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
  }
}
```

### 12.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**

```bash
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)**

```json
{
  "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)**

```json
{
  "success": false,
  "message": "Full Name is required. Valid Email is required.",
  "errors": [
    "Full Name is required.",
    "Valid Email is required."
  ]
}
```

### 12.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**

```bash
curl -X DELETE https://your-domain.com/api/users/997 \
  -H "Authorization: Bearer $TOKEN"
```

**Response (200)**

```json
{
  "success": true,
  "message": "User deleted successfully."
}
```

**Response (404)**

```json
{
  "success": false,
  "message": "User not found."
}
```

---

## 13. 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
```

### 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.

The integration is enabled and allow-listed per company in **Company Data Setup → Integrations**:

| Setting | Description |
| --- | --- |
| Enable External Client Softphone Integration | Master switch. When off, every integration request returns HTTP 503. |
| Allowed Origins (Frame Ancestors) | Exact origins authorized to call the API and embed the iframe, one per line or comma separated. Used for CORS and the CSP `frame-ancestors` directive. |

No `.env` configuration or extra user permission is required. Access is granted only when the company switch is on
and the calling origin matches the company's allow-list.

```js
const API_URL = 'https://your-domain.com';
const token   = '<user_api_token>';   // from POST /api/login
```

### Step 2 — Request a session

```
POST /api/softphone/session
Authorization: Bearer <user_api_token>
```

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.

**Response (201)**

```json
{
  "success": true,
  "iframe_url": "https://your-domain.com/softphone/integration"
}
```

```js
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();
```

**Errors**

| Status | Meaning |
| --- | --- |
| 503 | The integration is disabled for the user's company. |
| 403 | The calling origin is not in the company's allow-list, or the user is inactive. |

### Step 3 — Embed the iframe

Use the returned `iframe_url`. The cookie you just received signs the user in inside the iframe.

```html
<iframe
    src="https://your-domain.com/softphone/integration"
    allow="microphone; autoplay"
    style="width:100%;height:100%;border:0;">
</iframe>
```

### Step 4 — Revoke the session

```
POST /api/softphone/session/revoke
Authorization: Bearer <user_api_token>
```

Closing the iframe does not end the session. Call this when the user logs out or leaves your page.

**Response (200)**

```json
{
  "success": true,
  "revoked": 1
}
```

