Providers
ข้อมูล credential ของแหล่งดึงสายเข้าระบบ — ช่องทางที่สายไหลเข้ามา มีสามชนิดในตัว: threecx (3CX PBX), dtac (DTAC carrier) และ minio (bucket แบบ S3 ที่ตู้สาขาของคุณเขียนไฟล์ลงไปอยู่แล้ว) ระบบอื่น ๆ ทีมของเราเพิ่มเป็น ตัวดึงเสียง (connector) ได้ โดยฝั่งคุณไม่ต้องแก้อะไร GET /providers/catalog บอกรายชื่อตัวดึงเสียงทุกตัวที่ธุรกิจของคุณใช้ได้ พร้อมช่องตั้งค่าที่แต่ละตัวต้องการ
ถ้าเป็นระบบโทรศัพท์ เราจะล็อกอินเข้าไปดึงสาย ส่วน object storage ไม่มีการล็อกอินและไม่มีรายชื่อพนักงาน — ระบบจะไล่ดู bucket ตามรอบแล้วดึงไฟล์เสียงที่เจอเข้ามา ทุกอย่างในหน้านี้ใช้ได้กับตัวดึงเสียงทุกตัว ตรงไหนที่ต่างกันจะระบุไว้
Account key: ทุก request ด้านล่างต้องส่ง
X-Business-Id: <business id>เพื่อเลือกธุรกิจที่จะทำงานด้วย (ถ้าไม่ส่งจะได้400 business_required) ส่วน business key จะไม่อ่าน header นี้ เพราะผูกกับธุรกิจเดียวอยู่แล้ว ดูเพิ่มที่ เริ่มต้นใช้งาน → API key ระดับบัญชี
Secret เป็นแบบ write-only provider เก็บ credential ไว้ —
passwordสำหรับชนิดโทรศัพท์secretKeyสำหรับ bucket และช่องใดก็ตามที่ตัวดึงเสียงประกาศว่าเป็นsecretคุณส่งค่าพวกนี้ตอน create/update ได้ แต่GETจะไม่คืนกลับมา — response ของการอ่านจะแสดงเฉพาะส่วนที่ไม่ลับ ส่วน list endpoint จะแสดงpreviewที่ถูกปิดบังแทน ตอนแก้ไข ถ้าส่ง secret มาว่าง ระบบจะใช้ค่าเดิมที่เก็บไว้
GET /providers/catalog
รายชื่อตัวดึงเสียงที่ธุรกิจนี้เชื่อมต่อได้ — คือค่าที่ POST /providers รับเป็น kind — พร้อมช่องตั้งค่าที่แต่ละตัวต้องการ
Scopes: manage_provider_config
curl https://phone.mcloud.co.th/api/v1/providers/catalog \
-H "Authorization: Bearer crk_..."
{
"items": [
{
"slug": "threecx",
"name": { "th": "3CX", "en": "3CX" },
"description": { "th": "ระบบโทรศัพท์ 3CX — …", "en": "…" },
"category": "phone",
"fields": [
{ "key": "baseUrl", "type": "url", "label": { "th": "Base URL", "en": "Base URL" }, "help": null, "placeholder": "https://example.3cx.cloud", "required": true, "default": null, "min": null, "max": null, "options": null },
{ "key": "username", "type": "text", "label": { "th": "Username", "en": "Username" }, "help": null, "placeholder": null, "required": true, "default": null, "min": null, "max": null, "options": null },
{ "key": "password", "type": "secret", "label": { "th": "Password", "en": "Password" }, "help": null, "placeholder": null, "required": true, "default": null, "min": null, "max": null, "options": null }
],
"features": { "people": true, "agentFilter": true, "objectFilter": false, "range": true, "preview": true },
"schedule": { "defaultMinutes": 5, "minMinutes": 5, "maxMinutes": 1440, "rangeMaxDays": 30 },
"available": true
}
]
}
| Field | ความหมาย |
|---|---|
slug | ส่งค่านี้เป็น kind ของ POST /providers |
category | phone (ระบบโทรศัพท์/ระบบบันทึกเสียง) หรือ storage (bucket) |
fields[] | key ที่ config รับ type: text · url (เฉพาะ http/https) · secret (write-only) · number · boolean · select (ค่าหนึ่งใน options[].value) · list (array ของ string) — min/max คือขอบเขตของตัวเลข ความยาวของข้อความ หรือจำนวนรายการของ list ส่วน default ใช้เมื่อไม่ส่ง key นั้นหรือส่งมาว่าง |
features | people → ใช้ GET /providers/{id}/people ได้ · agentFilter → รับ config.agentFilter · objectFilter → รับ config.objectFilter · range / preview → ดึงตามช่วงวันที่ และดูตัวอย่างสายที่จะดึงในหน้าเว็บได้ |
schedule | config.pollIntervalMinutes ต้องอยู่ระหว่าง minMinutes–maxMinutes ถ้าไม่ส่งจะใช้ defaultMinutes ถ้าตั้ง config.pollTimes (เวลาดึงประจำวัน) ไว้ จะใช้เวลานั้นแทนรอบดึง |
available | false = ธุรกิจของคุณเพิ่มตัวดึงเสียงนี้ใหม่ไม่ได้แล้ว (ถูกปิด หรือไม่ได้เปิดให้แล้ว) แต่ยังมีการเชื่อมต่อเดิมอยู่ |
ชื่อและคำอธิบายเป็น { th, en } (มี ja / ko / zh-Hans เมื่อตัวดึงเสียงนั้นใส่มา) ตัวดึงเสียงบางตัวเปิดให้เฉพาะบางธุรกิจ — ตัวที่ธุรกิจของคุณใช้ไม่ได้จะไม่ปรากฏในรายการเลย
GET /providers
ดูแหล่งดึงสายที่ตั้งค่าไว้สำหรับธุรกิจนี้
Scopes: manage_provider_config
curl https://phone.mcloud.co.th/api/v1/providers \
-H "Authorization: Bearer crk_..."
{
"items": [
{
"id": "0192f0...",
"kind": "threecx",
"connector": "threecx",
"name": "Main PBX",
"isActive": true,
"preview": "apiuser@https://pbx.example.com",
"createdAt": "2026-05-01T00:00:00Z"
},
{
"id": "0192f1...",
"kind": "minio",
"connector": "minio",
"name": "PBX drop folder",
"isActive": true,
"preview": "recordings/pbx/2026/ @ https://s3.example.com:9000",
"createdAt": "2026-08-01T00:00:00Z"
}
]
}
kind คือชนิดที่เก็บไว้: threecx, dtac, minio หรือ script สำหรับตัวดึงเสียงทุกตัวที่เพิ่มภายหลัง ให้อ่านจาก connector — คือ slug ของตัวดึงเสียง ซึ่งเท่ากับ kind สำหรับสามชนิดในตัว
preview คือคำใบ้ที่ปิดบังค่าลับไว้: ระบบโทรศัพท์ในตัวเป็น username@baseUrl · bucket เป็น bucket/prefix @ endpoint · ตัวดึงเสียงอื่นเป็นค่าของช่องสรุปที่ตัวดึงเสียงกำหนด (คั่นด้วย ·) — ไม่มีค่าลับอยู่ในนั้น
POST /providers
สร้าง provider — config คือช่องตั้งค่าของตัวดึงเสียงนั้น (ดูด้านล่าง)
Scopes: manage_provider_config
| Param | Type | Note |
|---|---|---|
kind | "threecx" | "dtac" | "minio" | slug ของตัวดึงเสียง | required — slug ใดก็ได้จาก GET /providers/catalog ที่ available: true |
name | string (2-60) | required — ห้ามซ้ำกับ provider อื่นของธุรกิจ |
config | object | required — โครงสร้างขึ้นกับตัวดึงเสียง |
isActive | boolean | optional (default true) |
{ "id": "0192f0...", "connector": "threecx" }
| Error | Status | เมื่อไหร่ |
|---|---|---|
connector_not_available | 403 | kind เป็นตัวดึงเสียงที่ธุรกิจของคุณใช้ไม่ได้ — ไม่มีอยู่จริง ถูกปิด หรือไม่ได้เปิดให้คุณ (ทั้งสามกรณีตอบเหมือนกัน) |
provider_name_taken | 409 | มี provider อื่นใช้ name นี้แล้ว |
validation_failed | 422 | config ไม่ตรงกับช่องตั้งค่าของตัวดึงเสียง — issues บอกว่าช่องไหน |
config ของตัวดึงเสียงใดก็ได้: key ตาม fields ใน catalog บวก key สงวน 4 ตัวที่ทุกตัวดึงเสียงเข้าใจ — pollIntervalMinutes (int อยู่ในขอบเขต schedule ของตัวดึงเสียง), pollTimes (เวลาดึงประจำวัน ดูด้านล่าง), agentFilter (เมื่อ features.agentFilter) และ objectFilter (เมื่อ features.objectFilter) — key อื่นที่ไม่รู้จักจะถูกตัดทิ้ง
กำหนดเวลาดึง — ทุก N นาที หรือตามเวลาที่ตั้งไว้: ปกติระบบจะดึงสายจากการเชื่อมต่อทุก pollIntervalMinutes นาที (ถ้าไม่ส่ง จะใช้ schedule.defaultMinutes ของตัวดึงเสียง) ถ้าต้องการให้ดึงตามเวลาที่กำหนดในแต่ละวันแทน ให้ส่ง pollTimes:
| Field | Type | Note |
|---|---|---|
pollTimes | string[] | optional — รูปแบบ "HH:MM" แบบ 24 ชั่วโมง (00:00–23:59) เวลาประเทศไทย (Asia/Bangkok) ทุกวัน ใส่ได้ 1-24 เวลา ระบบจะเรียงเวลาให้และตัดเวลาที่ซ้ำออก ระหว่างที่ตั้งไว้ ระบบจะไม่ใช้ pollIntervalMinutes แต่ยังเก็บค่าไว้ กลับไปใช้รอบดึงเมื่อไรก็ได้ค่าเดิม ส่ง [] เพื่อลบเวลาที่ตั้งไว้และกลับไปดึงตามรอบ |
{ "config": { "pollTimes": ["08:00", "12:30", "18:00"] } }
สามชนิดในตัวยังใช้โครงสร้างเดิมตามด้านล่าง
config สำหรับ threecx:
| Field | Type | Note |
|---|---|---|
baseUrl | url | required |
username | string | required |
password | string | required (write-only) |
headless | boolean | optional |
pollIntervalMinutes | int 5-1440 | optional |
pollTimes | string[] | optional — ดูด้านบน |
config สำหรับ dtac:
| Field | Type | Note |
|---|---|---|
baseUrl | url | optional |
username | string | required |
password | string | required (write-only) |
pollIntervalMinutes | int 5-1440 | optional |
pollTimes | string[] | optional — ดูด้านบน |
config สำหรับ minio:
bucket แบบ S3 (MinIO, AWS S3, Wasabi, …) ที่ตู้สาขาของคุณเขียนไฟล์เสียงลงไปอยู่แล้ว — เราอ่านอย่างเดียว ไม่เขียนกลับ
| Field | Type | Note |
|---|---|---|
endpoint | string | required — ใส่เป็น host[:port] หรือ URL เต็ม http(s):// ก็ได้ ถ้ามี scheme จะใช้ scheme ตัดสินว่าใช้ TLS หรือไม่ |
accessKey | string | required |
secretKey | string | required (write-only) |
bucket | string | required |
useSSL | boolean | optional (default false) — ใช้เฉพาะตอน endpoint ไม่มี scheme |
prefix | string | optional — โฟลเดอร์ที่จะไล่ดู เช่น recordings/2026/ ถ้าเว้นว่างจะไล่ทั้ง bucket |
region | string | optional |
extensions | string[] | optional — นามสกุลไฟล์เสียงที่จะดึง ตัวพิมพ์เล็กและไม่ต้องมีจุด ถ้าไม่ใส่ จะใช้นามสกุลไฟล์เสียงทั้งหมด (wav, mp3, m4a, ogg, opus, flac, …) เพราะ bucket ที่ตู้สาขาเขียนลงมักมี CDR csv/json และไฟล์ .tmp ปนอยู่ด้วย จึงต้องเป็น allowlist ไม่ใช่ blocklist |
direction | "in" | "out" | optional (default "in") — bucket ไม่บอกว่าเป็นสายเข้าหรือสายออก คุณจึงต้องระบุเองว่าโฟลเดอร์นี้เก็บสายแบบไหน แล้วระบบจะใส่ค่านี้ให้ทุกสายที่ดึงเข้ามา |
lookbackHours | int 1-720 | optional (default 48) — ระบบดูเฉพาะไฟล์ที่แก้ไขภายในช่วงนี้ จึงไม่ต้องไล่ bucket ที่เก็บไฟล์หลายปีใหม่ทั้งหมดทุกรอบ |
pollIntervalMinutes | int 5-1440 | optional (default 15) |
pollTimes | string[] | optional — ดูด้านบน |
maxObjectsPerTick | int 1-5000 | optional (default 500) — เพดานกันงานบานในรอบเดียว |
เงื่อนไขการเก็บสาย — config.agentFilter (ตัวดึงเสียงที่มี features.agentFilter เช่นชนิดโทรศัพท์, optional):
เก็บเฉพาะสายของพนักงานที่เลือก โดยกรองตั้งแต่ ก่อนดาวน์โหลด สายที่กรองออกจะไม่ถูกแปลงไฟล์ (transcode) วิเคราะห์ หรือคิดเงิน ถ้าไม่ใส่ (หรือใช้ mode: "all") จะเก็บทุกสาย ดูค่า keys ที่ใช้ได้จาก GET /providers/{id}/people
| Field | Type | Note |
|---|---|---|
mode | "all" | "include" | "exclude" | default "all" |
keys | string[] | พนักงานที่จะเก็บ/ยกเว้น — ค่า key จาก /people (3CX: extension · DTAC: user id) |
directions | ("in" | "out")[] | optional — ถ้าไม่ใส่ จะเก็บทั้งสายเข้าและสายออก |
minDurationSec | int 0-3600 | optional — ตัดสายที่สั้นกว่านี้ |
maxDurationSec | int 0-28800 | optional — ตัดสายที่ยาวกว่านี้ ถ้าใส่ค่าน้อยกว่า minDurationSec ระบบจะไม่ใช้ค่านี้ (ไม่งั้นจะไม่เหลือสายเลย) |
เงื่อนไขการเก็บสาย — config.objectFilter (ตัวดึงเสียงที่มี features.objectFilter เช่น minio, optional):
bucket ไม่มีรายชื่อพนักงาน สิ่งที่ตั้งเงื่อนไขได้จริงจึงมีสองอย่าง: ไฟล์ อยู่ที่ไหน และเสียง ยาวเท่าไร สองส่วนนี้บังคับใช้คนละจุดและมีผลกับค่าใช้จ่ายต่างกัน — folders ถูกคัดตอน LIST ของ S3 คือก่อนโหลดแม้แต่ไบต์เดียว ส่วนความยาวไม่มีอยู่ในผลลิสต์ จึงตรวจได้หลังโหลดไฟล์มา probe เท่านั้น เสียค่าโหลด 1 ครั้ง แต่ยังข้ามการเก็บไฟล์ การสร้างสาย การแปลงไฟล์ (transcode) การถอดเสียง และงาน AI ทุกขั้น
| Field | Type | Note |
|---|---|---|
mode | "all" | "include" | "exclude" | default "all" |
folders | string[] | โฟลเดอร์ที่จะเก็บ/ยกเว้น — ใส่เป็น path เต็ม (pbx/2026/08), path ที่เทียบจาก prefix (08 เมื่อ prefix คือ pbx/2026/) หรือชื่อโฟลเดอร์อย่างเดียว (sales) ซึ่งจะตรงกับโฟลเดอร์ชื่อนั้นในชั้นไหนก็ได้ |
minDurationSec | int 0-28800 | optional — ตัดเสียงที่สั้นกว่านี้ |
maxDurationSec | int 0-28800 | optional — ตัดเสียงที่ยาวกว่านี้ ถ้าใส่ค่าน้อยกว่า minDurationSec ระบบจะไม่ใช้ค่านี้ |
curl -X POST https://phone.mcloud.co.th/api/v1/providers \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{
"kind": "threecx",
"name": "Main PBX",
"config": {
"baseUrl": "https://pbx.example.com",
"username": "apiuser",
"password": "s3cret"
},
"isActive": true
}'
{ "id": "0192f0...", "connector": "threecx" }
การสร้างแหล่งแบบ bucket เขียนแบบนี้:
curl -X POST https://phone.mcloud.co.th/api/v1/providers \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{
"kind": "minio",
"name": "PBX drop folder",
"config": {
"endpoint": "https://s3.example.com:9000",
"accessKey": "AKIA...",
"secretKey": "s3cret",
"bucket": "recordings",
"prefix": "pbx/2026/",
"direction": "in",
"lookbackHours": 48,
"pollIntervalMinutes": 15
},
"isActive": true
}'
ตัวดึงเสียงอื่นใช้วิธีเดียวกัน — ส่ง slug เป็น kind และใส่ fields จาก catalog ลงใน config:
curl -X POST https://phone.mcloud.co.th/api/v1/providers \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{
"kind": "<slug จาก /providers/catalog>",
"name": "Branch PBX",
"config": { "<key ของช่อง>": "<ค่า>", "pollIntervalMinutes": 10 }
}'
GET /providers/{id}
ดึง provider หนึ่งตัว — จะไม่คืนค่าลับใด ๆ มีแค่ส่วนที่ไม่ลับ
Scopes: manage_provider_config
| Error | Status | เมื่อไหร่ |
|---|---|---|
provider_not_found | 404 | ไม่มี provider นี้ในธุรกิจนี้ |
provider_kind_not_supported | 422 | kind ที่เก็บไว้ไม่ใช่แหล่งดึงสาย (เช่นเป็นค่าตั้งของโมเดล AI) |
config คือค่าตั้งค่าที่ไม่ลับของตัวดึงเสียง — ช่องตั้งค่าของตัวดึงเสียงนั้น รวมกับ pollIntervalMinutes / pollTimes / agentFilter / objectFilter เมื่อตั้งไว้ — มีให้กับทุกตัวดึงเสียง ส่วนสามชนิดในตัวยังมีบล็อกแบบแบนเหมือนเดิม: response มีทั้งสองฝั่งเสมอ ฝั่งที่ไม่เกี่ยวจะเป็น null — client จึงไม่ต้องแยกเงื่อนไขตาม kind เพียงเพื่ออ่านค่า ระบบโทรศัพท์จะเติม baseUrl / username / agentFilter แล้วปล่อย minio เป็น null:
{
"id": "0192f0...",
"kind": "threecx",
"connector": "threecx",
"name": "Main PBX",
"isActive": true,
"config": {
"baseUrl": "https://pbx.example.com",
"username": "apiuser",
"agentFilter": { "mode": "include", "keys": ["12110", "12117"] }
},
"baseUrl": "https://pbx.example.com",
"username": "apiuser",
"agentFilter": {
"mode": "include",
"keys": ["12110", "12117"],
"directions": ["in", "out"],
"minDurationSec": 10,
"maxDurationSec": 3600
},
"minio": null
}
ส่วน bucket จะกลับกัน — คืนทุกอย่างยกเว้น secretKey:
{
"id": "0192f1...",
"kind": "minio",
"connector": "minio",
"name": "PBX drop folder",
"isActive": true,
"config": { "endpoint": "https://s3.example.com:9000", "bucket": "recordings", "…": "…" },
"baseUrl": null,
"username": null,
"agentFilter": null,
"minio": {
"endpoint": "https://s3.example.com:9000",
"useSSL": true,
"accessKey": "AKIA...",
"bucket": "recordings",
"prefix": "pbx/2026/",
"region": null,
"extensions": ["wav", "mp3", "m4a"],
"direction": "in",
"lookbackHours": 48,
"pollIntervalMinutes": 15,
"pollTimes": null,
"maxObjectsPerTick": 500,
"objectFilter": {
"mode": "include",
"folders": ["sales"],
"minDurationSec": 10
}
}
}
ตัวดึงเสียงอื่น (kind: "script") จะมี baseUrl, username และ minio เป็น null และค่าทั้งหมดอยู่ใน config ส่วน agentFilter คือค่าเดียวกับ config.agentFilter
PATCH /providers/{id}
แก้ provider — ระบบจะ merge config เข้ากับค่าที่เก็บไว้ จึงส่งเฉพาะ key ที่ต้องการเปลี่ยนได้ (เช่นเปลี่ยน password โดยไม่ต้องส่ง baseUrl ซ้ำ) ถ้าส่ง secret มาว่าง ระบบจะใช้ค่าเดิม แล้วตรวจผลที่ merge แล้วตามช่องตั้งค่าของตัวดึงเสียง
Scopes: manage_provider_config
| Param | Type | Note |
|---|---|---|
name | string (2-60) | optional |
config | object | optional — merge เข้ากับ config ที่เก็บไว้ |
isActive | boolean | optional |
| Error | Status | เมื่อไหร่ |
|---|---|---|
connector_not_available | 403 | แก้ config หรือส่ง isActive: true ขณะที่ตัวดึงเสียงถูกปิดหรือไม่ได้เปิดให้ธุรกิจของคุณแล้ว — การเปลี่ยนชื่อและการปิดยังทำได้ · การปิดตัวดึงเสียงอาจไม่กระทบการเชื่อมต่อ 3CX, DTAC และ MinIO ที่มีอยู่ กรณีนั้นการแก้ไขจะสำเร็จตามปกติ |
provider_not_found | 404 | ไม่มี provider นี้ในธุรกิจนี้ |
provider_name_taken | 409 | มี provider อื่นใช้ name นี้แล้ว |
validation_failed | 422 | config หลัง merge ไม่ตรงกับช่องตั้งค่าของตัวดึงเสียง |
curl -X PATCH https://phone.mcloud.co.th/api/v1/providers/$ID \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{"config":{"password":"r0tated"}}'
ตั้งเงื่อนไขการเก็บสายด้วยวิธีเดียวกัน — ส่ง config.agentFilter (merge เข้าไป จึงไม่กระทบ credential):
curl -X PATCH https://phone.mcloud.co.th/api/v1/providers/$ID \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{"config":{"agentFilter":{"mode":"include","keys":["12110","12117"]}}}'
ถ้าเป็น bucket ให้ใช้ config.objectFilter แทน — merge แบบเดียวกัน และไม่แตะ credential เหมือนกัน:
curl -X PATCH https://phone.mcloud.co.th/api/v1/providers/$ID \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{"config":{"objectFilter":{"mode":"include","folders":["sales"],"minDurationSec":10}}}'
{ "ok": true }
เปลี่ยนไปดึงตามเวลาที่ตั้งไว้ด้วย config.pollTimes และส่งรายการว่างเพื่อกลับไปดึงตามรอบ:
curl -X PATCH https://phone.mcloud.co.th/api/v1/providers/$ID \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{"config":{"pollTimes":["08:00","12:30","18:00"]}}'
curl -X PATCH https://phone.mcloud.co.th/api/v1/providers/$ID \
-H "Authorization: Bearer crk_..." \
-H "Content-Type: application/json" \
-d '{"config":{"pollTimes":[]}}'
การ merge เป็นราย key ไม่ merge ลึกลงไปข้างใน: การส่ง
objectFilter(หรือagentFilterหรือpollTimes) คือการแทนที่ค่าทั้งก้อน ไม่ใช่แก้ทีละส่วน ให้ส่งเงื่อนไขที่ต้องการมาให้ครบ และถ้าจะล้างเงื่อนไขให้ส่ง{"mode":"all"}
DELETE /providers/{id}
ลบ config ของ provider — เรียกซ้ำได้ (idempotent) id ที่ถูกลบไปแล้วก็ยังตอบ ok
Scopes: manage_provider_config
| Error | Status | เมื่อไหร่ |
|---|---|---|
provider_kind_not_supported | 422 | มี id นี้อยู่จริง แต่ไม่ใช่แหล่งดึงสาย (เป็นค่าตั้งของโมเดล AI) |
{ "ok": true }
GET /providers/{id}/people
ดึงรายชื่อพนักงานที่เลือกได้จาก provider นี้ เพื่อหา key ที่ใช้ตั้งเงื่อนไขการเก็บสาย (config.agentFilter.keys) เป็นการ เรียกสดไปที่ระบบปลายทาง (directory extension ของ 3CX / รายชื่อ user ของ DTAC / ตัวดึงเสียงใดก็ได้ที่ catalog บอก features.people) จึงอาจใช้เวลาสองสามวินาที
ใช้ได้เฉพาะตัวดึงเสียงที่มีรายชื่อ — minio เป็นที่เก็บไฟล์ ไม่ใช่ตู้สาขา ไม่มีบัญชีให้ล็อกอินและไม่มีรายชื่อให้อ่าน อีกทั้งเงื่อนไขของถังเลือกที่ "โฟลเดอร์" ไม่ใช่ "คน" จึงตอบ provider_kind_not_supported (422) โดยเจตนา ให้ไปดูรายการไฟล์ในถังจากหน้า ธุรกิจ → ตั้งค่าธุรกิจ → ผู้ให้บริการ ในหน้าเว็บ แล้วนำ path ที่เห็นมาใส่ใน config.objectFilter.folders
Scopes: manage_provider_config
| Field | ความหมาย |
|---|---|
provider | slug ของตัวดึงเสียง |
key | ค่าที่ใส่ใน agentFilter.keys — extension (3CX) / user id (DTAC) |
name | ชื่อที่แสดง |
number | ค่าที่จะปรากฏเป็น callcenterNumber ของสาย — 3CX: extension · DTAC: เบอร์โทร |
detail | ค่าเดียวกับ number (คงไว้ให้ระบบที่เชื่อมไว้แล้ว) |
active | พนักงานคนนี้ยังเปิดใช้งานอยู่ที่ provider หรือไม่ |
| Error | Status | เมื่อไหร่ |
|---|---|---|
connector_not_available | 403 | ตัวดึงเสียงถูกปิด หรือไม่ได้เปิดให้ธุรกิจของคุณแล้ว · การปิดตัวดึงเสียงอาจไม่กระทบการเชื่อมต่อ 3CX, DTAC และ MinIO ที่มีอยู่ กรณีนั้นคำขอนี้จะสำเร็จตามปกติ |
provider_not_found | 404 | ไม่มี provider นี้ในธุรกิจนี้ |
provider_kind_not_supported | 422 | ตัวดึงเสียงนี้ไม่มีรายชื่อ |
provider_people_unavailable | 502 | ล็อกอินหรือดึงรายชื่อจาก provider ไม่สำเร็จ (ข้อมูลล็อกอินผิด หรือ provider ล่ม) |
curl https://phone.mcloud.co.th/api/v1/providers/$ID/people \
-H "Authorization: Bearer crk_..."
{
"provider": "threecx",
"people": [
{ "key": "12110", "name": "Jintana Promdee", "number": "12110", "detail": "12110", "active": true }
]
}
POST /providers/{id}/test
ทดสอบการเชื่อมต่อด้วย credential ที่เก็บไว้ ตัวดึงเสียงจะตรวจด้วยวิธีของตัวเองในเครื่องรันที่แยกไว้ — สำหรับ minio คือทั้งข้อมูลล็อกอิน และสิทธิ์มองเห็นถัง สำหรับระบบโทรศัพท์คือการล็อกอินจริง การทดสอบที่ได้รันแล้วจะคืน 200 ทั้งสองกรณี ถ้าเชื่อมต่อไม่สำเร็จ ระบบจะแจ้งใน body ไม่ใช่เป็น HTTP error
Scopes: manage_provider_config
| Field ใน body | ความหมาย |
|---|---|
ok | true = เชื่อมต่อได้ |
error | เมื่อ ok เป็น false: auth_failed · unreachable · rate_limited · bad_config · provider_error · failed (กรณีอื่นทั้งหมด — รายละเอียดอยู่ในบันทึกการทำงานของแพลตฟอร์ม) |
message | ประโยคจากตัวดึงเสียงเอง — มีค่าเมื่อสำเร็จ และเมื่อเป็น bad_config นอกนั้นเป็น null |
| Error | Status | เมื่อไหร่ |
|---|---|---|
connector_not_available | 403 | ตัวดึงเสียงถูกปิด หรือไม่ได้เปิดให้ธุรกิจของคุณแล้ว · การปิดตัวดึงเสียงอาจไม่กระทบการเชื่อมต่อ 3CX, DTAC และ MinIO ที่มีอยู่ กรณีนั้นคำขอนี้จะสำเร็จตามปกติ |
provider_not_found | 404 | ไม่มี provider นี้ในธุรกิจนี้ |
service_unavailable | 503 | ตอนนี้ยังเริ่มการทดสอบไม่ได้ — ลองใหม่ภายหลัง |
curl -X POST https://phone.mcloud.co.th/api/v1/providers/$ID/test \
-H "Authorization: Bearer crk_..."
{ "ok": true, "message": "Connected · 14 users" }
{ "ok": false, "error": "auth_failed", "message": null }