Recording
Nhóm endpoint phát/tải ghi âm từng cuộc gọi, tạo job export hàng loạt (ZIP), điều khiển job và pause/resume ghi âm thời gian thực để tuân thủ PCI.
Tạm dừng / tiếp tục ghi âm (PCI compliance)
POST /api/telesales/calls/{uuid}/recording/pause
POST /api/telesales/calls/{uuid}/recording/resumePath parameter
| Field | Type | Mô tả |
|---|---|---|
uuid | string | UUID cuộc gọi đang diễn ra |
Response fields
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
uuid | string | UUID cuộc gọi | |
recording | string | Trạng thái ghi âm sau khi gọi endpoint | paused / recording |
Response 200: { "data": { "uuid": "...", "recording": "paused" } }
Use case
Agent có thể tạm dừng ghi âm khi khách hàng đang đọc thông tin nhạy cảm (số thẻ tín dụng, CVV, ...) để đảm bảo tuân thủ PCI-DSS, sau đó tiếp tục ghi khi đoạn nhạy cảm đã kết thúc.
Tổng quan endpoint
| Endpoint | Mục đích |
|---|---|
GET /api/telesales/recordings/{uuid} | Stream audio để playback (trả audio/wav, hỗ trợ Range request) |
GET /api/telesales/recordings/{uuid}/download | Tải file .wav kèm filename |
POST /api/telesales/recordings/export-bulk | Tạo job export ZIP (async) |
GET /api/telesales/recordings/export-bulk/{jobId} | Kiểm tra trạng thái job |
GET /api/telesales/recordings/export-bulk/{jobId}/download | Tải ZIP khi job hoàn tất |
DELETE /api/telesales/recordings/export-bulk/{jobId} | Huỷ job / dọn ZIP sớm |
GET /api/telesales/recordings/{uuid} — stream
Path parameter
| Field | Type | Mô tả |
|---|---|---|
uuid | string | UUID cuộc gọi |
Response headers
| Header | Mô tả | Giá trị |
|---|---|---|
Content-Type | Loại MIME | audio/wav |
Accept-Ranges | Hỗ trợ Range request | bytes |
Content-Length | Kích thước file (byte) | |
Cache-Control | Cache policy | private, max-age=3600 |
Response 200:
Content-Type: audio/wavAccept-Ranges: bytes(cho HTML5 audio scrubbing)Content-Length: <bytes>Cache-Control: private, max-age=3600
Response 206 Partial Content (HTTP Range request) — audio player dùng để scrub.
Response 404 — không có ghi âm:
{ "message": "Recording not found.", "error_code": "RECORDING_NOT_FOUND" }Response 410 Gone — ghi âm đã hết hạn theo retention rule do admin cấu hình:
{ "message": "Recording has exceeded the retention window.", "expired_at": "2026-03-01T00:00:00Z" }GET /api/telesales/recordings/{uuid}/download
Path parameter
| Field | Type | Mô tả |
|---|---|---|
uuid | string | UUID cuộc gọi |
Response headers
| Header | Mô tả | Giá trị |
|---|---|---|
Content-Type | Loại MIME | audio/wav |
Content-Disposition | Filename gợi ý cho trình duyệt | attachment; filename="call-{uuid}-{date}.wav" |
Response 200:
Content-Type: audio/wavContent-Disposition: attachment; filename="call-093e1024-2026-06-06.wav"
Lỗi 404/410 giống endpoint stream.
POST /api/telesales/recordings/export-bulk — tạo job ZIP
Request body fields
| Field | Type | Required | Mô tả | Giá trị hợp lệ |
|---|---|---|---|---|
campaign_id | integer | optional | Lọc theo chiến dịch | |
date_from | datetime | ✅ | Mốc bắt đầu (ISO 8601 UTC) | |
date_to | datetime | ✅ | Mốc kết thúc (ISO 8601 UTC) | Khoảng date_from..date_to ≤ 31 ngày |
agent_ids[] | array<integer> | optional | Lọc theo agent | |
disposition_codes[] | array<string> | optional | Chỉ export cuộc có disposition này | mã disposition của tài khoản |
Body:
{
"campaign_id": 36,
"date_from": "2026-06-01T00:00:00Z",
"date_to": "2026-06-05T23:59:59Z",
"agent_ids": [25, 26],
"disposition_codes": ["SALE-OK", "CALLBACK_REQ"]
}Response fields
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
job_id | string | ID job export | exp_<hex> |
status | string | Trạng thái khởi tạo | queued |
estimated_files | integer | Ước tính số file ghi âm sẽ đóng gói | ≥ 1 |
estimated_size_mb | integer | Ước tính dung lượng ZIP (MB) | ≥ 0 |
created_at | datetime | Lúc tạo job (ISO 8601 UTC) | |
expires_at | datetime | Lúc ZIP bị xoá tự động (default +30 ngày) | ISO 8601 UTC |
Response 201:
{
"data": {
"job_id": "exp_abc123",
"status": "queued",
"estimated_files": 215,
"estimated_size_mb": 480,
"created_at": "2026-06-06T07:00:00Z",
"expires_at": "2026-07-06T07:00:00Z"
}
}Response 422 — các trường hợp validate sai:
// Khoảng thời gian vượt 31 ngày
{
"message": "The given data was invalid.",
"errors": { "date_to": ["The date_from..date_to range may not exceed 31 days."] }
}
// 0 file match filter → không tạo job
{
"message": "No recordings match the filter.",
"errors": { "filter": ["Estimated 0 files. Adjust date range or filters."] }
}Response 403 — caller không có quyền supervisor / admin:
{ "message": "You are not allowed to bulk-export recordings. Supervisor or admin role is required." }GET /api/telesales/recordings/export-bulk/{jobId} — kiểm tra trạng thái
Path parameter
| Field | Type | Mô tả |
|---|---|---|
jobId | string | ID job trả về từ POST tạo job |
Response fields
| Field | Type | Mô tả | Giá trị hợp lệ |
|---|---|---|---|
job_id | string | ID job export | |
status | string | Trạng thái job | queued / running / ready / failed / expired / cancelled |
progress_pct | integer | Phần trăm hoàn thành | 0-100 |
files | integer | Số file đã đóng gói (chỉ khi ready) | ≥ 0 |
files_processed | integer | Số file đã xử lý (chỉ khi running) | ≥ 0 |
size_mb | integer | Dung lượng ZIP thực tế (MB) | |
download_url | string | URL tải ZIP (khi status=ready) | |
created_at | datetime | Lúc tạo job (ISO 8601 UTC) | |
completed_at | datetime|null | Lúc đóng gói xong | |
expires_at | datetime | Lúc ZIP bị xoá tự động | |
error_code | string | Mã lỗi khi status=failed | vd STORAGE_ERROR |
error_message | string | Mô tả lỗi khi status=failed | |
failed_at | datetime | Lúc job thất bại |
Response 200:
{
"data": {
"job_id": "exp_abc123",
"status": "ready",
"progress_pct": 100,
"files": 215,
"size_mb": 478,
"download_url": "/api/telesales/recordings/export-bulk/exp_abc123/download",
"created_at": "2026-06-06T07:00:00Z",
"completed_at": "2026-06-06T07:08:42Z",
"expires_at": "2026-07-06T07:00:00Z"
}
}Enum status: queued | running | ready | failed | expired | cancelled.
Trạng thái running trả thêm progress_pct (0..99) + files_processed.
Trạng thái failed trả thêm:
{
"data": {
"job_id": "exp_abc123",
"status": "failed",
"error_code": "STORAGE_ERROR",
"error_message": "Storage unavailable during ZIP packaging.",
"failed_at": "2026-06-06T07:05:00Z"
}
}Response 404 — job không tồn tại hoặc không thuộc tài khoản.
GET /api/telesales/recordings/export-bulk/{jobId}/download
Path parameter
| Field | Type | Mô tả |
|---|---|---|
jobId | string | ID job (status phải = ready) |
Response headers
| Header | Mô tả | Giá trị |
|---|---|---|
Content-Type | Loại MIME | application/zip |
Content-Disposition | Filename ZIP | attachment; filename="recordings-{jobId}.zip" |
Response 200:
Content-Type: application/zipContent-Disposition: attachment; filename="recordings-exp_abc123.zip"
ZIP chứa các file .wav cùng một manifest.csv (call UUID, extension agent, tên agent, disposition code, start_time, duration, số điện thoại lead).
Response 410 Gone — ZIP đã hết hạn (30 ngày):
{ "message": "Export ZIP has expired. Please create a new job." }Response 409 Conflict — job chưa sẵn sàng:
{ "message": "Job exp_abc123 is currently in state 'running' (38%). Wait until ready before downloading." }DELETE /api/telesales/recordings/export-bulk/{jobId} — huỷ / dọn
Path parameter
| Field | Type | Mô tả |
|---|---|---|
jobId | string | ID job cần huỷ hoặc dọn |
Response 204 No Content — queued/running → cancelled; ready → ZIP bị xoá sớm để giải phóng storage.
