Skip to content

Recording

Endpoints to play / download a single call recording, create bulk export jobs (ZIP), control jobs, and pause/resume recording in real time for PCI compliance.

Pause / resume recording (PCI compliance)

http
POST /api/telesales/calls/{uuid}/recording/pause
POST /api/telesales/calls/{uuid}/recording/resume

Path parameter

FieldTypeDescription
uuidstringUUID of the call in progress

Response fields

FieldTypeDescriptionValid values
uuidstringCall UUID
recordingstringRecording state after the callpaused / recording

Response 200: { "data": { "uuid": "...", "recording": "paused" } }

Use case

The agent can pause recording while the customer reads out sensitive information (credit card number, CVV, ...) to remain PCI-DSS compliant, then resume recording once the sensitive segment is over.

Endpoint summary

EndpointPurpose
GET /api/telesales/recordings/{uuid}Stream audio for playback (returns audio/wav, supports Range requests)
GET /api/telesales/recordings/{uuid}/downloadDownload the .wav file with a filename header
POST /api/telesales/recordings/export-bulkCreate an async ZIP export job
GET /api/telesales/recordings/export-bulk/{jobId}Check job status
GET /api/telesales/recordings/export-bulk/{jobId}/downloadDownload the ZIP when the job is done
DELETE /api/telesales/recordings/export-bulk/{jobId}Cancel a job / clean up the ZIP early

GET /api/telesales/recordings/{uuid} — stream

Path parameter

FieldTypeDescription
uuidstringCall UUID

Response headers

HeaderDescriptionValue
Content-TypeMIME typeaudio/wav
Accept-RangesRange requests supportedbytes
Content-LengthFile size (bytes)
Cache-ControlCache policyprivate, max-age=3600

Response 200:

  • Content-Type: audio/wav
  • Accept-Ranges: bytes (for HTML5 audio scrubbing)
  • Content-Length: <bytes>
  • Cache-Control: private, max-age=3600

Response 206 Partial Content (HTTP Range request) — used by the audio player for scrubbing.

Response 404 — no recording:

json
{ "message": "Recording not found.", "error_code": "RECORDING_NOT_FOUND" }

Response 410 Gone — the recording exceeded the retention window configured by the admin:

json
{ "message": "Recording has exceeded the retention window.", "expired_at": "2026-03-01T00:00:00Z" }

GET /api/telesales/recordings/{uuid}/download

Path parameter

FieldTypeDescription
uuidstringCall UUID

Response headers

HeaderDescriptionValue
Content-TypeMIME typeaudio/wav
Content-DispositionSuggested filename for the browserattachment; filename="call-{uuid}-{date}.wav"

Response 200:

  • Content-Type: audio/wav
  • Content-Disposition: attachment; filename="call-093e1024-2026-06-06.wav"

Errors 404/410 are identical to the stream endpoint.

POST /api/telesales/recordings/export-bulk — create ZIP job

Request body fields

FieldTypeRequiredDescriptionValid values
campaign_idintegeroptionalFilter by campaign
date_fromdatetimeStart timestamp (ISO 8601 UTC)
date_todatetimeEnd timestamp (ISO 8601 UTC)date_from..date_to ≤ 31 days
agent_ids[]array<integer>optionalFilter by agent
disposition_codes[]array<string>optionalOnly export calls with these dispositionsdisposition codes belonging to the account

Body:

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

FieldTypeDescriptionValid values
job_idstringExport job IDexp_<hex>
statusstringInitial statequeued
estimated_filesintegerEstimated recordings to be packaged≥ 1
estimated_size_mbintegerEstimated ZIP size (MB)≥ 0
created_atdatetimeJob creation (ISO 8601 UTC)
expires_atdatetimeWhen the ZIP is auto-deleted (default +30 days)ISO 8601 UTC

Response 201:

json
{
  "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 — validation cases:

json
// Time range exceeds 31 days
{
  "message": "The given data was invalid.",
  "errors": { "date_to": ["The date_from..date_to range may not exceed 31 days."] }
}

// 0 files match the filter → no job is created
{
  "message": "No recordings match the filter.",
  "errors": { "filter": ["Estimated 0 files. Adjust date range or filters."] }
}

Response 403 — caller lacks the supervisor / admin role:

json
{ "message": "You are not allowed to bulk-export recordings. Supervisor or admin role is required." }

GET /api/telesales/recordings/export-bulk/{jobId} — check status

Path parameter

FieldTypeDescription
jobIdstringJob ID returned by the create endpoint

Response fields

FieldTypeDescriptionValid values
job_idstringExport job ID
statusstringJob statequeued / running / ready / failed / expired / cancelled
progress_pctintegerPercent complete0-100
filesintegerFiles packaged (only when ready)≥ 0
files_processedintegerFiles processed so far (only when running)≥ 0
size_mbintegerActual ZIP size (MB)
download_urlstringURL to download the ZIP (when status=ready)
created_atdatetimeJob creation (ISO 8601 UTC)
completed_atdatetime|nullWhen packaging finished
expires_atdatetimeWhen the ZIP is auto-deleted
error_codestringError code when status=failede.g. STORAGE_ERROR
error_messagestringError description when status=failed
failed_atdatetimeWhen the job failed

Response 200:

json
{
  "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.

State running also returns progress_pct (0..99) + files_processed.

State failed also returns:

json
{
  "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 does not exist or does not belong to the account.

GET /api/telesales/recordings/export-bulk/{jobId}/download

Path parameter

FieldTypeDescription
jobIdstringJob ID (status must be ready)

Response headers

HeaderDescriptionValue
Content-TypeMIME typeapplication/zip
Content-DispositionZIP filenameattachment; filename="recordings-{jobId}.zip"

Response 200:

  • Content-Type: application/zip
  • Content-Disposition: attachment; filename="recordings-exp_abc123.zip"

The ZIP contains the .wav files plus a manifest.csv (call UUID, agent extension, agent name, disposition code, start_time, duration, lead phone number).

Response 410 Gone — ZIP has expired (30 days):

json
{ "message": "Export ZIP has expired. Please create a new job." }

Response 409 Conflict — job is not yet ready:

json
{ "message": "Job exp_abc123 is currently in state 'running' (38%). Wait until ready before downloading." }

DELETE /api/telesales/recordings/export-bulk/{jobId} — cancel / clean up

Path parameter

FieldTypeDescription
jobIdstringJob ID to cancel or clean up

Response 204 No Contentqueued/running → cancelled; ready → ZIP is deleted early to free storage.

Cấp phép theo điều khoản sử dụng của Zorio.