Recordings
หน่วยข้อมูลหลักของระบบ — บันทึกการสนทนาหนึ่งสาย พร้อม transcript + summary
Account key: ทุก request ด้านล่างต้องส่ง
X-Business-Id: <business id>เพื่อเลือก business ที่จะทำงานด้วย (ถ้าไม่ส่งจะได้400 business_required) ส่วน business key ไม่สนใจ header นี้เพราะผูกกับ business เดียวอยู่แล้ว ดูเพิ่มที่ Getting started → API Key ระดับบัญชี
GET /recordings
List recording แบบ paginated
Scopes: view_recording_all · view_recording_self
| Param | Type | Note |
|---|---|---|
limit | int 1-200 | default 20 |
offset | int | default 0 |
direction | "in" | "out" | optional |
sourceProvider | threecx | dtac | upload | optional |
callDateFrom | ISO 8601 datetime | optional |
callDateTo | ISO 8601 datetime | optional |
customerPhone | string (exact match) | optional |
customerPhoneNormalized | string (exact match) | optional |
tag | normal | short | wrong_or_spam | no_answer | other | none | none = ยังไม่ติด tag |
scoreMin | int 0-100 | เฉพาะ row ที่มี score |
scoreMax | int 0-100 | เฉพาะ row ที่มี score |
search | string | ilike ครอบ dataId, customerPhone, customerPhoneNormalized, callcenterNumber, callcenterName |
sortBy | callAt | duration | score | default callAt |
sortDir | asc | desc | default desc; null อยู่ท้ายสุด, tiebreak callAt desc |
agentKey | string, ส่งซ้ำได้ (สูงสุด 500) | เอาเฉพาะสายของ agent เหล่านี้ — เทียบกับ COALESCE(callcenterNumber, callcenterName) (key เดียวกับที่ /recordings/agents คืน) เช่น ?agentKey=%2B66804972699&agentKey=Somchai |
curl "https://phone.mcloud.co.th/api/v1/recordings?limit=10&direction=in&sortBy=score&sortDir=desc" \
-H "Authorization: Bearer crk_..."
{
"items": [
{
"id": "0192b9...",
"dataId": "rec_2026_05_20_001",
"callAt": "2026-05-20T08:14:00+07:00",
"direction": "in",
"customerPhone": "+66812345678",
"customerPhoneNormalized": "0812345678",
"tag": "normal",
"score": 86,
"processingStatus": "completed",
"audioUrl": "/api/recording/audio/0192b9...",
"transcriptUrl": "/api/recording/transcript/0192b9...",
"summaryUrl": "/api/recording/summary/0192b9..."
}
],
"total": 1284,
"limit": 10,
"offset": 0
}
GET /recordings/stats
รวมสถิติ call recording ตามช่วงเวลา — ยอดรวม, จำนวนสายต่อวัน, การกระจาย score, ชั่วโมงที่สายเข้าหนาแน่น, และ top performer
Scopes: view_recording_all · view_recording_self
| Param | Type | Note |
|---|---|---|
dateFrom | ISO 8601 datetime | optional |
dateTo | ISO 8601 datetime | optional |
customerPhoneNormalized | string (exact match) | optional |
tz | IANA timezone | default Asia/Bangkok — ใช้แบ่ง bucket วัน/ชั่วโมง |
agentKey | string, ส่งซ้ำได้ (สูงสุด 500) | เอาเฉพาะสายของ agent เหล่านี้ (ความหมายเดียวกับ endpoint list) |
curl "https://phone.mcloud.co.th/api/v1/recordings/stats?dateFrom=2026-05-01T00:00:00%2B07:00&tz=Asia/Bangkok" \
-H "Authorization: Bearer crk_..."
{
"totals": {
"total": 1284,
"inbound": 902,
"outbound": 382,
"avgDurationMs": 184320.5,
"longestMs": 1432000,
"avgScore": 78.4,
"firstCallAt": "2026-05-01T08:12:00+07:00",
"lastCallAt": "2026-05-31T19:45:00+07:00"
},
"daily": [{ "day": "2026-05-01", "count": 41 }],
"scoreDistribution": { "good": 612, "mid": 388, "low": 96 },
"peakHours": [{ "hour": 0, "count": 3 }],
"topPerformers": [
{ "name": "Somchai", "calls": 214, "avgDurationMs": 176000, "avgScore": 81.2 }
]
}
scoreDistribution: good ≥ 70, mid 40–69.99, low < 40 (เฉพาะ row ที่มี score)peakHours: มีครบ 24 ชั่วโมง (0–23, เติม 0 ให้ชั่วโมงที่ไม่มีสาย)topPerformers: top 10 callcenter name เรียงตามจำนวนสาย
POST /recordings
Ingest metadata + presigned upload (optional) — idempotent ด้วย dataId
Scopes: manage_call_recording
| Param | Type | Note |
|---|---|---|
dataId | string unique | required |
callAt | ISO 8601 | required |
direction | "in" | "out" | required |
customerPhone | string | optional |
callcenterNumber | string | optional |
callcenterName | string | optional |
tag | enum | optional |
score | number 0-100 | optional |
note | string | optional |
contentType | string (MIME) | default audio/wav |
audioPresignedUploadUrl | boolean | ขอ presigned URL? |
curl -X POST https://phone.mcloud.co.th/api/v1/recordings \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{
"dataId": "rec_2026_05_20_001",
"callAt": "2026-05-20T08:14:00+07:00",
"direction": "in",
"audioPresignedUploadUrl": true
}'
GET /recordings/{id}
ดึง recording เดียว
Scopes: view_recording_all · view_recording_self
PATCH /recordings/{id}
Review — score / tag / comment / note / link
Scopes: manage_recording_review · manage_recording_link
| Param | Type | Note |
|---|---|---|
score | number 0-100 | optional |
tag | normal | short | wrong_or_spam | no_answer | other | optional |
reviewComment | string | optional |
note | string | optional |
linkedUserId | uuid | null | requires manage_recording_link |
DELETE /recordings/{id}
Soft-delete (ย้ายไป trash, เก็บ 30 วัน)
Scopes: manage_call_recording
POST /recordings/{id}/reextract
สั่ง AI ทำงานใหม่ (ถอดเสียง + สรุป)
Scopes: manage_call_recording
curl -X POST https://phone.mcloud.co.th/api/v1/recordings/$ID/reextract \
-H "Authorization: Bearer crk_..."
POST /recordings/analyze
วิเคราะห์ไฟล์เสียงแบบ synchronous — อัปโหลดเสียง รัน AI แล้วคืนผลลัพธ์ทั้งหมดพร้อมค่าใช้จ่ายที่คิดเงินแล้วในครั้งเดียว (รอจนเสร็จ) ไฟล์จะถูกบันทึกและแสดงใน dashboard ใช้เวลาประมาณ 1–4 นาที ให้ตั้ง client timeout ยาวๆ
Scopes: manage_call_recording
body เป็น multipart/form-data (ไม่ใช่ JSON)
| Param | Type | Note |
|---|---|---|
file | file (multipart) | required — ไฟล์เสียง wav/mp3/m4a/mp4/aac/ogg/opus/webm/flac, ≤50MB |
direction | "in" | "out" | optional, default "in" |
customerPhone | string | optional |
callcenterName | string | optional |
callcenterNumber | string | optional |
note | string | optional |
callAt | ISO 8601 | optional, default = เวลาปัจจุบัน |
curl -X POST https://phone.mcloud.co.th/api/v1/recordings/analyze \
-H "Authorization: Bearer crk_..." \
-H "X-Business-Id: <business uuid, account keys only>" \
-F "file=@call.wav" \
-F "direction=in" \
-F "customerPhone=+66812345678"
{
"recordingId": "0190f7b2-...",
"dataId": "api-2f1c...",
"status": "completed",
"result": {
"transcript": "แอดมิน: สวัสดีค่ะ...\nลูกค้า: ...",
"segments": [
{ "index": 0, "start_ms": 0, "end_ms": 2400, "speaker": "admin", "text": "สวัสดีค่ะ", "emotion": "neutral", "tone": "polite", "coaching": "" }
],
"summary": "ลูกค้าสอบถามโปรโมชั่น...",
"recommendations": "ควรเสนอ...",
"score": 86,
"tag": "normal",
"overallEmotion": "positive",
"overallTone": "friendly"
},
"cost": { "chargedThb": 0.1234, "currency": "THB" },
"durationMs": 73210
}
cost.chargedThb คือยอดที่คิดเงินกับธุรกิจ (ราคาสุทธิ) ระบบจะไม่เปิดเผยต้นทุนดิบ อัตรา หรือรุ่น AI
Error ที่เป็นไปได้: 402 insufficient_credit, 413 audio_file_too_large, 415 audio_unsupported_format, 422 audio_file_required, 503 worker_unavailable, 504 extraction_timeout
GET /recordings/agents
รายชื่อ callcenter agent ทั้งหมดที่พบใน recording ของ business นี้ พร้อมจำนวนสาย — นำ key ที่ได้ไปใช้เป็น filter agentKey กับ endpoint list และ stats ได้เลย (key คือ COALESCE(callcenterNumber, callcenterName))
Scopes: view_recording_all · view_recording_self
curl https://phone.mcloud.co.th/api/v1/recordings/agents \
-H "Authorization: Bearer crk_..."
{
"items": [
{
"key": "+66804972699",
"name": "66804972699 FIN4YOU 07",
"number": "+66804972699",
"calls": 412,
"lastCallAt": "2026-06-09T14:13:53.000Z"
}
],
"total": 7
}
PATCH /recordings/agents/{extension}
ตั้งหรือล้างป้ายชื่อ (label) ของ callcenter agent — เหมือนการแก้ label บนการ์ดในหน้าทีม โดย {extension} คือ number ของ agent ที่ได้จาก endpoint list (ต้อง URL-encode เช่น +66804972699 → %2B66804972699) ป้ายชื่อใหม่จะ cascade ไปยังทุก recording ที่มี callcenter_number เดียวกัน ทำให้ leaderboard, รายการสาย และหัว player แสดงชื่อใหม่ทันที
ส่ง customName: null เพื่อล้าง override แล้วกลับไปใช้ชื่อที่ provider ตั้งให้
Scope: manage_recording_link
| field | type | notes |
|---|---|---|
customName | string (1–128) | null, required | ป้ายชื่อใหม่ — ส่ง null เพื่อล้าง override |
curl -X PATCH "https://phone.mcloud.co.th/api/v1/recordings/agents/%2B66804972699" \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{"customName":"ทีมขาย A"}'
{
"ok": true,
"extension": "+66804972699",
"customName": "ทีมขาย A",
"effectiveName": "ทีมขาย A"
}
จะคืน 404 extension_not_found เมื่อไม่พบ extension นี้ใน business
GET /recordings/prompt-config
อ่าน config การวิเคราะห์สายด้วย AI ของ business — บริบทธุรกิจที่ AI ใช้เป็น persona, คำอธิบาย tag ทั้ง 4 ประเภท และเกณฑ์การให้คะแนนแบบถ่วงน้ำหนัก (เป็น config เดียวกับที่หน้า /app/prompt ในแอปใช้จัดการ) AI จะนำไปประกอบเป็น persona ทุกครั้งที่ถอดเสียง/วิเคราะห์สาย · business ที่ยังไม่เคยตั้งค่าจะได้ค่าเริ่มต้น (คำอธิบาย tag + เกณฑ์รวม 100 คะแนน) โดย businessName จะ fallback เป็นชื่อ business
Scopes: manage_recording_prompt · view_recording_all
curl "https://phone.mcloud.co.th/api/v1/recordings/prompt-config" \
-H "Authorization: Bearer crk_..."
{
"businessName": "Acme Co.",
"businessAbout": "ขายอสังหาริมทรัพย์ ลูกค้าเป็นกลุ่มครอบครัว",
"businessProducts": "บ้านเดี่ยว, ทาวน์โฮม, คอนโด",
"tagDescriptions": {
"normal": "บทสนทนาปกติ มีเนื้อหา/ติดต่อธุรกิจจริง",
"short": "สายสั้นมาก ไม่มีเนื้อหา หรือวางสายก่อนพูดจบ",
"wrong_or_spam": "โทรผิด สายขายของ spam สแกม หรือไม่เกี่ยวกับธุรกิจ",
"no_answer": "สายที่ไม่มีคนรับ ไม่มีบทสนทนา (missed call)",
"other": "อื่นๆ ที่ไม่เข้ากลุ่มข้างบน"
},
"scoreCategories": [
{ "label": "การทักทายและมารยาท", "maxPoints": 20 },
{ "label": "การสอบถามข้อมูลครบถ้วน", "maxPoints": 30 },
{ "label": "การจัดการข้อโต้แย้ง", "maxPoints": 20 },
{ "label": "การปิดการสนทนา/นัดหมาย", "maxPoints": 30 }
],
"updatedAt": "2026-06-10T04:54:12.745Z",
"updatedBy": null
}
PUT /recordings/prompt-config
บันทึก/อัปเดต config การวิเคราะห์ด้วย AI (1 แถวต่อ 1 business) · ช่องบริบทธุรกิจที่เว้นว่างจะถูกเก็บเป็น null แล้ว businessName จะ fallback เป็นชื่อ business · scoreCategories มีได้ 1–20 หมวด · endpoint ตรวจรูปแบบข้อมูลแต่ไม่บังคับให้ผลรวมน้ำหนักเท่ากับ 100 (ตัว editor ในแอปบังคับให้เอง)
Scope: manage_recording_prompt
| field | type | notes |
|---|---|---|
businessName | string (≤200) | ชื่อที่ AI ใช้ — เว้นว่าง → fallback เป็นชื่อ business |
businessAbout | string (≤4000) | ธุรกิจทำเกี่ยวกับอะไร (บริบทให้ AI) |
businessProducts | string (≤4000) | สินค้า/บริการที่พูดถึงในสาย |
tagDescriptions | object, required | ต้องครบ 5 คีย์: normal, short, wrong_or_spam, no_answer, other (แต่ละค่า ≤1000) |
scoreCategories | array 1–20, required | แต่ละหมวด { label (1–200), maxPoints (1–100 จำนวนเต็ม) } |
curl -X PUT "https://phone.mcloud.co.th/api/v1/recordings/prompt-config" \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{
"businessName": "Acme Co.",
"businessAbout": "ขายอสังหาริมทรัพย์ ลูกค้าเป็นกลุ่มครอบครัว",
"businessProducts": "บ้านเดี่ยว, ทาวน์โฮม, คอนโด",
"tagDescriptions": {
"normal": "บทสนทนาปกติ",
"short": "สายสั้นมาก",
"wrong_or_spam": "โทรผิด/สแปม",
"no_answer": "ไม่รับสาย",
"other": "อื่นๆ"
},
"scoreCategories": [
{ "label": "การทักทายและมารยาท", "maxPoints": 50 },
{ "label": "การปิดการสนทนา/นัดหมาย", "maxPoints": 50 }
]
}'
{ "ok": true }
จะคืน 422 validation_failed เมื่อข้อมูลไม่ถูกต้อง — เช่น ขาด tag key, scoreCategories ว่าง, หรือ maxPoints อยู่นอกช่วง 1–100
