Asosiy kontentga o'tish

4phone mijoz qo'ng'iroqlari API qo'llanmasi

Ushbu qo'llanma qo'ng'iroqlar va audioyozuvlarni yuklab olish uchun production API ishlashini, API kalitlarini sozlashni, webhook hodisalarini va mijozning CRM, ERP, BI yoki ichki tizimini ulashning namunaviy tartibini tavsiflaydi.

1. Imkoniyatlar​

Integratsiya quyidagilarni qo'llab-quvvatlaydi:

  • CRM tizimidan chiquvchi qo'ng'iroqni boshlash uchun REST API.
  • Qo'ng'iroqlar ro'yxati, qo'ng'iroq kartochkasi va audioyozuv faylini so'rash uchun REST API.
  • Kiruvchi qo'ng'iroq boshlangani, yakunlangani va yozuv fayli tayyor bo'lgani haqida avtomatik xabar berish uchun Webhooks.

Tavsiya etilgan ishlash sxemasi:

  1. Yangi hodisalarni webhooklar orqali qabul qilish.
  2. Qo'ng'iroqni o'z bazangizda id maydoni bo'yicha saqlash.
  3. CALL_RECORDING_READY hodisasidan keyin audioyozuvni yuklab olish.
  4. Mijoz endpointi vaqtincha ishlamay qolganligi sababli o'tkazib yuborilgan hodisalarni tiklash uchun ma'lumotlarni REST API orqali davriy ravishda solishtirib borish.

2. Manzillar​

REST API bazaviy manzili:

https://api.4phone.uz/api/v1/external

API kalitlari bo'limi manzili:

https://4phone.uz/dashboard/settings/integrations/api-keys

Webhooks bo'limi manzili:

https://4phone.uz/dashboard/settings/integrations/webhooks

Yetkazib berishlar tarixi manzili:

https://4phone.uz/dashboard/settings/integrations/deliveries

3. API kalitini yaratish​

OWNER va ADMIN roliga ega foydalanuvchilar kalitlarni yaratishi va bekor qilishi (chaqirib olishi) mumkin.

Sozlash tartibi:

  1. Sozlamalar bo'limini oching.
  2. Integratsiyalar bo'limiga o'ting.
  3. API kalitlari sahifasini oching.
  4. Kalit yaratish tugmasini bosing.
  5. Tushunarli nom kiriting, masalan Bitrix export yoki BI production.
  6. calls:read ruxsatini (scope) tanlang.
  7. Agar CRM tugma orqali qo'ng'iroqni boshlashi kerak bo'lsa, calls:create ruxsatini tanlang.
  8. Agar mijoz tizimiga audioyozuv fayllari kerak bo'lsa, recordings:read ruxsatini tanlang.
  9. Zarurat bo'lsa, kalitni bo'lim, IP manzillar va amal qilish muddati bo'yicha cheklang.
  10. Kalitni yarating va ko'rsatilgan maxfiy qiymatni (sekretni) darhol saqlab qo'ying.

Kalitning to'liq qiymati faqat bir marta ko'rsatiladi. Yo'qotilgan sekretni tiklab bo'lmaydi. Eski kalitni bekor qilib, yangisini yaratish kerak bo'ladi.

Har bir tashqi tizim uchun alohida kalit yaratish tavsiya etiladi. Bu ruxsatlarni, IP cheklovlarini va amal qilish muddatini bir-biridan mustaqil ravishda o'zgartirish imkonini beradi.

3.1. Ruxsatlar (Scopes)​

Qo'ng'iroqlar API uchun uchta ruxsat (scope) ishlatiladi:

  • calls:read yakunlangan qo'ng'iroqlar ro'yxati va kartochkasini olishga ruxsat beradi.
  • calls:create CRM tizimidan chiquvchi qo'ng'iroqni boshlashga ruxsat beradi.
  • recordings:read audioyozuv fayllarini tekshirish va yuklab olishga ruxsat beradi.

Faqat recordings:read ruxsatiga ega kalit ma'lum id bo'yicha yozuvni yuklab olishi mumkin, lekin qo'ng'iroqlar ro'yxatini so'ray olmaydi. CRM dagi qo'ng'iroq tugmasi uchun alohida calls:create ruxsati zarur; qo'ng'iroqni boshlash uchun calls:read ruxsatining o'zi yetarli emas.

3.2. Bo'lim bo'yicha cheklov​

Agar Bo'lim maydoni to'ldirilmagan bo'lsa, kalit o'z tenantining barcha ruxsat etilgan qo'ng'iroqlariga kirish huquqini oladi.

Agar bo'lim tanlansa, API faqat shu bo'limning ichki raqamlari (extension) ishtirokidagi qo'ng'iroqlarni qaytaradi. Boshqa bo'limning ichki raqamini so'rash bo'sh ro'yxat qaytaradi. Begona bo'lim qo'ng'irog'ining kartochkasi esa 404 qaytaradi.

Bo'lim cheklovi audioyozuvni yuklab olishga va qo'ng'iroqni boshlashga ham qo'llanadi: boshqa bo'limning ichki raqamidan qo'ng'iroq boshlashga urinish 404 qaytaradi.

3.3. IP whitelist​

IP whitelist maydoni quyidagilarni qabul qiladi:

  • alohida IPv4 manzil, masalan 45.147.253.34;
  • IPv4 qism tarmog'i (subnet), masalan 45.147.253.32/27;
  • alohida IPv6 manzil;
  • CIDR formatidagi IPv6 qism tarmog'i.

Qiymatlarni vergul, bo'sh joy yoki yangi qator bilan ajratish mumkin. Agar ro'yxat bo'sh bo'lsa, IP bo'yicha cheklov qo'llanmaydi.

API ga murojaat qiladigan serverning tashqi (public) chiquvchi IP manzilini ko'rsating. Mos kelmagan taqdirda API api_key.ip_not_allowed kodi bilan 403 qaytaradi.

3.4. Amal qilish muddati va bekor qilish​

Amal qilish muddati majburiy emas, ammo vaqtinchalik integratsiyalar va sinov (test) muhitlari uchun tavsiya etiladi.

Bekor qilingan yoki muddati o'tgan kalit boshqa qabul qilinmaydi. Bekor qilishni ortga qaytarib bo'lmaydi. Kalitlarni yaratish va bekor qilish platforma auditiga yozib boriladi.

4. So'rovlarni avtorizatsiya qilish​

Tavsiya etilgan sarlavha (header):

X-Api-Key: cpbx_XXXXXXXX_SECRET

Shuningdek, Bearer formati ham qo'llab-quvvatlanadi:

Authorization: Bearer cpbx_XXXXXXXX_SECRET

Kalitni quyidagi joylarda uzatmang:

  • URL ning query parametrlarida;
  • fayl nomida;
  • brauzerning mijoz tomonidagi JavaScript kodida;
  • xatolik xabarlarida va ochiq loglarda.

Kalitni secret manager tizimida yoki muhit o'zgaruvchisida (environment variable) saqlang:

export FOURPHONE_API_KEY='cpbx_XXXXXXXX_SECRET'

Kirish huquqini tekshirish:

curl -sS \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
"https://api.4phone.uz/api/v1/external/calls?limit=1"

5. Qo'ng'iroqlar ro'yxati​

GET /calls​

To'liq manzil:

https://api.4phone.uz/api/v1/external/calls

Talab qilinadigan scope: calls:read.

API faqat yakunlangan kiruvchi va chiquvchi qo'ng'iroqlarni qaytaradi. Ichki qo'ng'iroqlar mijoz eksportiga kirmaydi.

Mavjud statuslar:

  • ANSWERED
  • BUSY
  • NO_ANSWER
  • FAILED
  • CANCELLED

5.1. Filtrlar​

Quyidagi parametrlar qo'llab-quvvatlanadi:

  • direction — INBOUND yoki OUTBOUND qiymati bilan;
  • status — vergul orqali ajratilgan statuslar ro'yxati bilan;
  • startedFrom — RFC 3339 formatidagi davr boshlanishi, chegara hisobga olinadi;
  • startedTo — RFC 3339 formatidagi davr tugashi, chegara hisobga olinmaydi;
  • phone — telefon raqami yoki uning bir qismi bilan;
  • extensionNumber — ichki raqam bilan;
  • hasRecording — true yoki false qiymati bilan;
  • limit — 1 dan 100 gacha, standart qiymati 50;
  • cursor — oldingi javobning meta.nextCursor maydonidan olingan qiymat.

phone filtrida raqamlardan tashqari barcha belgilar olib tashlanadi. Qidiruv qo'ng'iroq qiluvchining raqami va belgilangan (manzil) raqam bo'yicha bajariladi.

hasRecording=true qo'ng'iroqda audioyozuvga havola borligini bildiradi. Fayl hali qayta ishlanayotgan bo'lishi mumkin. Yuklab olishdan oldin recording.available=true ekanligini tekshiring.

Javob berilgan kiruvchi qo'ng'iroqlarni so'rash misoli:

curl -sS \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
"https://api.4phone.uz/api/v1/external/calls?direction=INBOUND&status=ANSWERED&startedFrom=2026-07-01T00%3A00%3A00%2B05%3A00&limit=50"

Raqam bo'yicha qidirish misoli:

curl -sS \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
"https://api.4phone.uz/api/v1/external/calls?phone=998901234567&limit=50"

5.2. Javob formati​

{
"data": [
{
"id": "847cc73c-6aaf-4a5e-aea8-d106fae10c45",
"callId": "17ed2d85-a64a-4ce0-9151-a4dc57505dc6",
"direction": "INBOUND",
"status": "ANSWERED",
"date": "23.07.2026 10:40:59",
"dateIso": "2026-07-23T05:40:59Z",
"timeZone": "Asia/Tashkent",
"from": "998901234567",
"to": "781139788",
"durationSeconds": 83,
"extensionNumber": "101",
"recording": {
"status": "AVAILABLE",
"available": true,
"fileName": "17ed2d85-a64a-4ce0-9151-a4dc57505dc6.wav",
"contentType": "audio/wav",
"sizeBytes": 1382400,
"downloadUrl": "/api/v1/external/calls/847cc73c-6aaf-4a5e-aea8-d106fae10c45/recording"
}
}
],
"meta": {
"limit": 50,
"hasMore": false,
"nextCursor": null
}
}

5.3. Maydonlarning ma'nosi​

  • id — qo'ng'iroq yozuvining ID raqami. Kartochkani olish va audioyozuvni yuklab olish uchun aynan shundan foydalaning.
  • callId — telefon sessiyasining texnik ID raqami.
  • direction — INBOUND yoki OUTBOUND qiymatini oladi.
  • status — yakuniy statusni bildiradi.
  • date — tenantning mahalliy sanasi va vaqtini soniyagacha aniqlikda saqlaydi.
  • dateIso — xuddi shu vaqtni UTC va RFC 3339 formatida saqlaydi.
  • timeZone — date uchun ishlatilgan vaqt mintaqasini ko'rsatadi.
  • durationSeconds — sof suhbat vaqtini soniyalarda saqlaydi. Javob berilmagan qo'ng'iroq uchun qiymat 0 ga teng.
  • extensionNumber — xodimning ichki raqamini yoki null qiymatini saqlaydi.

Kiruvchi qo'ng'iroq uchun:

  • from — qo'ng'iroq qiluvchining tashqi raqamini + belgisisiz saqlaydi;
  • to — qo'ng'iroq kelib tushgan dastlabki DID raqamini saqlaydi.

Chiquvchi qo'ng'iroq uchun:

  • from — agar ichki raqam foydalanuvchisida uchala maydon ham to'ldirilgan bo'lsa, Familiya Ism Sharif qiymatini saqlaydi;
  • agar F.I.Sh. to'liq to'ldirilmagan bo'lsa, from telefon raqamini saqlaydi;
  • to — terilgan tashqi maqsadli raqamni + belgisisiz saqlaydi.

5.4. Audioyozuv obyekti​

Agar audioyozuv yaratilmagan bo'lsa, recording maydoni null ga teng bo'ladi.

recording.status ning mumkin bo'lgan qiymatlari:

  • CAPTURED
  • ACCEPTED
  • UPLOADED
  • AVAILABLE
  • FAILED
  • ARCHIVED

Yuklab olishga faqat quyidagi holatda ruxsat beriladi:

{
"available": true
}

available=true qiymati AVAILABLE va ARCHIVED statuslari uchun ishlatiladi. Qolgan barcha statuslarda downloadUrl qiymati null ga teng bo'ladi.

5.5. CRM tizimidan qo'ng'iroqni boshlash​

POST /calls​

Talab qilinadigan scope: calls:create.

Ushbu metod CRM tizimida qo'ng'iroqni boshlash tugmasi uchun mo'ljallangan. Avval 4phone xodimning ichki raqamiga qo'ng'iroq qiladi. Xodim javob berganidan so'ng 4phone tenantning odatiy chiquvchi marshrutlari bo'yicha mijozning tashqi raqamini teradi.

curl -sS \
-X POST \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"extensionNumber": "101",
"phoneNumber": "+998901234567"
}' \
"https://api.4phone.uz/api/v1/external/calls"

So'rov maydonlari:

  • extensionNumber: xodimning ichki raqami, 2 tadan 6 tagacha raqam.
  • phoneNumber: mijozning tashqi raqami. + belgisi, bo'sh joylar, qavslar va defislarga ruxsat beriladi. Normalizatsiyadan so'ng 7 tadan 15 tagacha raqam qolishi kerak.

Muvaffaqiyatli javob HTTP 202 kodiga ega bo'ladi:

{
"callId": "17ed2d85-a64a-4ce0-9151-a4dc57505dc6",
"jobId": "8f4a3b2c-1234-4567-89ab-1234567890ab",
"status": "INITIATED",
"extensionNumber": "101",
"phoneNumber": "998901234567"
}

callId — telefon sessiyasining texnik ID raqami. Qo'ng'iroq yakunlangandan so'ng uni qo'ng'iroqlar ro'yxatidan callId maydoni bo'yicha topish, yakuniy natijani esa CALL_COMPLETED webhooki orqali olish mumkin.

INITIATED statusi faqatgina platforma qo'ng'iroqni boshlash vazifasini qabul qilganini anglatadi. Bu xodim yoki mijoz allaqachon javob berganini bildirmaydi. Agar xodim javob bermasa, mijozga qo'ng'iroq qilinmaydi va yakunlangan natija tarixda NO_ANSWER, BUSY, CANCELLED yoki FAILED statusi bilan paydo bo'ladi.

Ushbu metod uchun API kalitining alohida limiti amal qiladi: daqiqasiga 30 ta qo'ng'iroq boshlash. Tugma qayta bosilganda bitta mijozga ikkita qo'ng'iroq yaratib yubormaslik uchun CRM API javob berguniga qadar takroriy yuborishni bloklashi kerak.

6. Sahifalash (Paginatsiya)​

Natijalar qo'ng'iroq boshlangan vaqt bo'yicha yangilaridan eskilariga qarab saralanadi.

Agar meta.hasMore=true bo'lsa, meta.nextCursor qiymatini o'zgartirmasdan uzating:

curl -sS \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
"https://api.4phone.uz/api/v1/external/calls?limit=50&cursor=NEXT_CURSOR_QIYMATI"

Cursor quyidagilarga bog'langan:

  • tenantga;
  • kalit bo'limiga;
  • yo'nalishga (direction);
  • statuslarga;
  • davrga;
  • telefon raqamiga;
  • ichki raqamga;
  • audioyozuv filtriga.

Sahifalar orasida filtrlarni o'zgartirish mumkin emas. Filtr o'zgartirilganda so'rovni cursor parametrisiz boshlang. O'zgartirilgan yoki shikastlangan cursor 400 xatoligini qaytaradi.

Muntazam sinxronizatsiya uchun kichik vaqt ustma-ust tushishi (overlap) bilan davrdan foydalaning va takroriy yozuvlarni id bo'yicha filtrlang. Bu vaqtinchalik tarmoq xatoligida qo'ng'iroqlarni o'tkazib yuborishdan himoya qiladi.

7. Qo'ng'iroq kartochkasi​

GET /calls/{id}​

Talab qilinadigan scope: calls:read.

curl -sS \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
"https://api.4phone.uz/api/v1/external/calls/$CALL_ID"

Javob data massividagi element bilan bir xil obyektni o'z ichiga oladi.

API quyidagi hollarda 404 qaytaradi, agar:

  • qo'ng'iroq mavjud bo'lmasa;
  • qo'ng'iroq boshqa tenantga tegishli bo'lsa;
  • qo'ng'iroq ruxsat berilmagan bo'limda bo'lsa;
  • qo'ng'iroq ichki bo'lsa;
  • qo'ng'iroq hali yakunlangan statusni olmagan bo'lsa.

Bir xil 404 javobi begona ma'lumotlar mavjudligini oshkor qilmaydi.

8. Audioyozuvni olish​

HEAD /calls/{id}/recording​

Faylni uzatmasdan turib uning mavjudligini va metama'lumotlarini tekshiradi.

curl -sS -I \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
"https://api.4phone.uz/api/v1/external/calls/$CALL_ID/recording"

GET /calls/{id}/recording​

Faylni yuklab oladi.

curl -fS \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
-o call-recording.wav \
"https://api.4phone.uz/api/v1/external/calls/$CALL_ID/recording"

Har ikkala metod uchun talab qilinadigan scope: recordings:read.

8.1. WAV kanallari​

Agar audioyozuv ikki kanalli (stereo) bo'lsa:

  • fayl WAV formatida qoladi;
  • birinchi kanal chaqiruvning dastlabki tomonidan keluvchi oqimni saqlaydi;
  • ikkinchi kanal chaqiruvning dastlabki tomoniga yo'naltirilgan chiquvchi oqimni saqlaydi;
  • kiruvchi qo'ng'iroq uchun bu odatda birinchi kanalda mijoz va ikkinchi kanalda operator bo'ladi;
  • chiquvchi qo'ng'iroq uchun bu odatda birinchi kanalda operator va ikkinchi kanalda mijoz bo'ladi;
  • navbatlar (queues) va chaqiruvni boshqa raqamga o'tkazishda (transfer) ham yozuv ishlashda davom etadi.

Eski yozuvlar bir kanalli bo'lib qolishi mumkin. Integratsiya kanallar sonini sana yoki fayl nomiga qarab emas, balki WAV sarlavhasidan (header) o'qishi kerak.

GET metodi dastlabki faylni qayta kodlashsiz va kanallarni birlashtirmasdan uzatadi, HEAD esa uning metama'lumotlarini qaytaradi. Ikki kanalli yozuvlar uchun URL, recordings:read ruxsati, Range-so'rovlar va API ning qolgan qoidalari o'zgarmaydi. JSON ichidagi recording obyekti kanallar sonini o'z ichiga olmaydi — u yuklab olingan WAV fayl sarlavhasidan aniqlanadi.

Faylni tekshirish misoli:

ffprobe -v error \
-select_streams a:0 \
-show_entries stream=codec_name,sample_rate,channels,channel_layout \
-of default=noprint_wrappers=1 \
call-recording.wav

Ikki kanalli WAV xuddi shu davomiylikdagi bir kanalli yozuvga qaraganda taxminan ikki baravar ko'p joy egallaydi.

Javob quyidagilarni o'z ichiga oladi:

  • fayl formatiga ega Content-Type;
  • xavfsiz fayl nomiga ega Content-Disposition;
  • agar hajmi ma'lum bo'lsa, Content-Length;
  • Accept-Ranges: bytes;
  • Cache-Control: private, no-store.

Qisman yuklab olish (Range request) qo'llab-quvvatlanadi:

curl -fS \
-H "X-Api-Key: $FOURPHONE_API_KEY" \
-H "Range: bytes=0-1048575" \
-o first-megabyte.bin \
"https://api.4phone.uz/api/v1/external/calls/$CALL_ID/recording"

Qisman javob uchun HTTP 206 va Content-Range sarlavhasi qaytariladi.

9. Qo'ng'iroqlar webhooklari​

REST API ma'lumotlarni yuklab olish va solishtirish uchun mos keladi. Qo'ng'iroqlarni real vaqt rejimida olish uchun webhook sozlang.

9.1. Yaratish​

  1. Sozlamalar bo'limini oching.
  2. Integratsiyalar bo'limiga o'ting.
  3. Webhooks sahifasini oching.
  4. Webhook qo'shish tugmasini bosing.
  5. Nomini kiriting.
  6. Mijoz ishlov beruvchisining (handler) ommaviy HTTPS URL manzilini kiriting.
  7. Kiruvchi qo'ng'iroq kelgan paytda kontakt kartochkasini ko'rsatish kerak bo'lsa, CALL_START hodisasini tanlang.
  8. CALL_COMPLETED hodisasini tanlang.
  9. Agar audioyozuv kerak bo'lsa, CALL_RECORDING_READY hodisasini tanlang.
  10. Xavfsiz avtomatik generatsiya uchun sekret maydonini bo'sh qoldiring.
  11. Ko'rsatilgan sekretni mijoz tizimining secret manager xizmatida saqlang.

Webhook URL manzili quyidagi talablarga javob berishi kerak:

  • HTTPS protokolidan foydalanishi;
  • login va parolni o'z ichiga olmasligi;
  • ommaviy DNS nomiga yoki ommaviy IP manzilga ega bo'lishi;
  • faqat ommaviy (public) IP manzillarga yechilishi (resolve bo'lishi);
  • internetdan ochiq bo'lishi.

SSRF hujumlaridan himoya qilish maqsadida lokal, loopback, link-local va xususiy (private) tarmoqlar bloklanadi. URL siyosati saqlash vaqtida va har bir yetkazib berishdan oldin tekshiriladi.

Sekret uzunligi 16 tadan 256 tagacha belgidan iborat bo'lishi kerak. Yaratilgandan so'ng sekret qayta ko'rsatilmaydi.

Agar sekret yo'qolgan bo'lsa, Sekretni almashtirish tugmasini bosing. Rotatsiyadan so'ng mijoz ishlov beruvchisini darhol yangi qiymatga o'tkazish zarur.

9.2. CALL_START​

Hodisa kiruvchi qo'ng'iroq xodimning telefonida jiringlay boshlagan paytda yaratiladi. Bu mijoz tizimi qo'ng'iroqqa javob berilishini yoki u tugashini kutmasdan, data.from raqami bo'yicha kontakt kartochkasini ko'rsatishi mumkin bo'lgan eng erta lahzadir.

{
"id": "5d0c6a52-8d2b-4a39-9f0e-0a6b7b0f4c11",
"event": "CALL_START",
"data": {
"schemaVersion": 1,
"callId": "17ed2d85-a64a-4ce0-9151-a4dc57505dc6",
"direction": "INBOUND",
"status": "RINGING",
"date": "23.07.2026 10:40:59",
"dateIso": "2026-07-23T05:40:59Z",
"timeZone": "Asia/Tashkent",
"from": "998901234567",
"to": "781139788",
"extensionNumber": "101"
},
"sentAt": "2026-07-23T05:40:59.000Z",
"timestamp": 1784770859
}

Bilish muhim bo'lgan jihatlar:

  • Hodisa faqat mijozlardan kelgan kiruvchi qo'ng'iroqlar uchun yaratiladi. Chiquvchi va ichki qo'ng'iroqlar uni yaratmaydi.
  • data.from mijozning raqami, data.to mijoz tergan raqam, data.extensionNumber esa telefoni jiringlayotgan xodimning ichki raqami. Kartochkani kerakli operatorga ko'rsatish uchun undan foydalaning.
  • Hodisa jiringlayotgan har bir ichki raqam uchun alohida yuboriladi. Agar qo'ng'iroq bir vaqtning o'zida bir nechta xodimga jiringlaydigan navbat yoki guruhga tushsa, bir xil data.callId va turli data.extensionNumber qiymatlariga ega bir nechta hodisa keladi.
  • Agar qo'ng'iroq avval ovozli menyudan o'tsa yoki navbatda kutsa, hodisa qo'ng'iroq aniq xodimga taklif qilingan paytda yuboriladi.
  • Hodisa data.callId va data.extensionNumber juftligi uchun bir marta yuboriladi.
  • Bu paytda qo'ng'iroq yozuvi tarixda hali yaratilmagan, shuning uchun hodisada data.id, durationSeconds va recording yo'q. CALL_COMPLETED va CALL_RECORDING_READY bilan bog'lash uchun data.callId dan foydalaning: u uchala hodisada ham bir xil.
  • Yetkazib berish qayta urinishlar bilan amalga oshiriladi, shuning uchun hodisalar tartibi kafolatlanmaydi. Agar CALL_START xuddi shu data.callId bilan CALL_COMPLETED dan keyin kelsa, kartochkani ko'rsatmang.
  • Ishlov beruvchi tez javob berishi kerak (10 soniya ichida), aks holda kartochka kechikib chiqadi. Og'ir amallarni javobdan keyin bajaring.

Hodisa uchun sekretli webhook kerak: imzo va yetkazib berish formati boshqa qo'ng'iroq hodisalari bilan bir xil.

9.3. CALL_COMPLETED​

Hodisa kiruvchi yoki chiquvchi qo'ng'iroq uchun CDR qayta ishlanishi yakunlangandan so'ng yaratiladi. Ichki qo'ng'iroqlar bundan mustasno.

Agar audioyozuv hali qayta ishlanayotgan bo'lsa, hodisa qo'ng'iroq ma'lumotlarini o'z ichiga oladi, lekin:

{
"recording": {
"available": false,
"downloadUrl": null
}
}

9.4. CALL_RECORDING_READY​

Hodisa fayl AVAILABLE yoki ARCHIVED statusini olganida alohida yaratiladi. Kutilayotgan yozuvlarni tekshirish har 30 soniyada bajariladi.

Hodisa CALL_COMPLETED bilan bir xil data.id qiymatini va quyidagilarni o'z ichiga oladi:

{
"recording": {
"available": true,
"downloadUrl": "/api/v1/external/calls/847cc73c-6aaf-4a5e-aea8-d106fae10c45/recording"
}
}

Agar yozuvni qayta ishlash FAILED statusi bilan yakunlansa, CALL_RECORDING_READY yuborilmaydi.

9.5. Webhook formati​

POST /your/4phone/webhook
Content-Type: application/json
X-Webhook-Id: 8f4a3b2c-1234-4567-89ab-1234567890ab
X-Webhook-Timestamp: 1784770859
X-Webhook-Event: CALL_COMPLETED
X-Webhook-Signature: v1,abcdef1234567890
{
"id": "8f4a3b2c-1234-4567-89ab-1234567890ab",
"event": "CALL_COMPLETED",
"data": {
"schemaVersion": 1,
"id": "847cc73c-6aaf-4a5e-aea8-d106fae10c45",
"callId": "17ed2d85-a64a-4ce0-9151-a4dc57505dc6",
"direction": "INBOUND",
"status": "ANSWERED",
"date": "23.07.2026 10:40:59",
"dateIso": "2026-07-23T05:40:59Z",
"timeZone": "Asia/Tashkent",
"from": "998901234567",
"to": "781139788",
"durationSeconds": 83,
"extensionNumber": "101",
"recording": {
"status": "CAPTURED",
"available": false,
"fileName": "17ed2d85-a64a-4ce0-9151-a4dc57505dc6.wav",
"contentType": "audio/wav",
"sizeBytes": null,
"downloadUrl": null
}
},
"sentAt": "2026-07-23T05:40:59.000Z",
"timestamp": 1784770859
}

Ildizdagi (root) id — webhook xabarining ID raqami. data.id esa qo'ng'iroqning ID raqamidir.

9.6. HMAC imzosini tekshirish​

Imzo HTTP body ning dastlabki (raw) baytlaridan hisoblanadi:

signedContent = X-Webhook-Id + "." + X-Webhook-Timestamp + "." + rawBody
signature = "v1," + HMAC_SHA256_HEX(secret, signedContent)

JSON tahlilidan (parse qilishdan) oldingi dastlabki body dan foydalanish juda muhim. JSON ni qayta serializatsiya qilish baytlarni o'zgartirib yuborishi va imzo mos kelmasligiga olib kelishi mumkin.

Node.js va Express uchun misol:

import crypto from "node:crypto";
import express from "express";

const app = express();
const secret = process.env.FOURPHONE_WEBHOOK_SECRET;

app.post(
"/4phone/webhook",
express.raw({ type: "application/json" }),
(request, response) => {
const messageId = String(request.header("X-Webhook-Id") || "");
const timestamp = String(request.header("X-Webhook-Timestamp") || "");
const received = String(request.header("X-Webhook-Signature") || "");
const rawBody = request.body;
const signedContent = Buffer.concat([
Buffer.from(`${messageId}.${timestamp}.`),
rawBody,
]);
const expected =
"v1," +
crypto.createHmac("sha256", secret).update(signedContent).digest("hex");

const valid =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));

const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!valid || !Number.isFinite(age) || age > 300) {
return response.status(401).json({ accepted: false });
}

const payload = JSON.parse(rawBody.toString("utf8"));

// Avval o'z bazangizda payload.id noyobligini tekshiring.
// So'ngra qayta ishlashni lokal navbatga qo'ying.

return response.status(202).json({ accepted: true });
},
);

Tekshirishning xuddi shu formulasi Python va PHP da ham qo'llanadi: asosiysi, JSON ni qayta serializatsiya qilmasdan HTTP body ning dastlabki baytlarini HMAC funksiyasiga uzatishdir.

9.7. Idempotentlik​

4phone «kamida bir marta» (at-least-once) yetkazib berish tamoyilidan foydalanadi. Mijoz tizimi takroriy xabarlarni to'g'ri qayta ishlashi shart.

Ildizdagi id yoki X-Webhook-Id qiymatini qayta ishlangan xabarlar jadvalida saqlang. Agar bunday ID allaqachon mavjud bo'lsa, biznes amaliyotni qayta bajarmasdan muvaffaqiyatli HTTP javobini qaytaring.

Qo'ng'iroqlar uchun data.id maydonini ham yozuvning noyob kaliti sifatida ishlating. CALL_COMPLETED va CALL_RECORDING_READY hodisalari turli webhook ID qiymatlariga, ammo bitta umumiy data.id qiymatiga ega bo'ladi. CALL_START qo'ng'iroq yozuvi yaratilishidan oldin yuboriladi va data.id ni o'z ichiga olmaydi: uni boshqa hodisalar bilan data.callId orqali bog'lang.

9.8. Javob va qayta urinishlar​

Endpoint 200 dan 299 gacha bo'lgan HTTP status qaytargan yetkazib berish muvaffaqiyatli hisoblanadi.

Ishlov beruvchiga (handler) qo'yiladigan talablar:

  • imzoni tekshirish;
  • timestamp vaqtini tekshirish;
  • idempotentlikni tekshirish;
  • hodisani tezda saqlash yoki uni lokal navbatga qo'yish;
  • 10 soniya ichida javob qaytarish.

Tarmoq xatoligi, timeout yoki muvaffaqiyatsiz HTTP status yuz berganda 8 tagacha urinish amalga oshiriladi. Xatolardan keyingi oraliqlar: 30, 60, 120, 240, 480, 960 va 1920 soniya.

Har bir urinish uchun timestamp, sentAt va HMAC imzosi yangilanadi. X-Webhook-Id esa o'zgarishsiz qoladi.

10. Yetkazib berishlar tarixi​

Sozlamalar, Integratsiyalar, Yetkazib berishlar tarixi bo'limida quyidagilar aks etadi:

  • hodisa turi;
  • maqsadli webhook;
  • status;
  • oxirgi HTTP kod;
  • urinishlar soni;
  • oxirgi xatolik;
  • oxirgi urinishlarning har birining vaqti.

Statuslar:

  • PENDING — yuborilishini kutmoqda;
  • PROCESSING — hozir yuborilmoqda;
  • DELIVERED — mijoz tomonidan muvaffaqiyatli qabul qilindi;
  • FAILED — keyingi urinishni kutmoqda;
  • DLQ — avtomatik urinishlar tugadi.

FAILED va DLQ statuslari uchun qo'lda qayta yuborish (Replay) mavjud.

11. Rate limit​

API kaliti limitlari 60 soniyalik oynada har bir metod uchun alohida hisoblanadi:

  • oddiy metodga 300 tagacha so'rov;
  • audioyozuvning GET yoki HEAD metodiga 120 tagacha so'rov;
  • POST /calls metodi orqali 30 tagacha qo'ng'iroq boshlash.

Javob quyidagi sarlavhalarni o'z ichiga oladi:

X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset

Limitdan oshib ketganda 429 va Retry-After: 60 qaytariladi.

Mijoz tizimi 429 javobini qayta ishlashi, Retry-After qiymatini inobatga olishi va qayta urinishdan oldin eksponensial pauzadan foydalanishi kerak.

12. Xatoliklar​

Xatolik JSON formatida qaytariladi:

{
"statusCode": 403,
"timestamp": "2026-07-30T12:41:59.676Z",
"path": "/api/v1/external/calls?limit=1",
"code": "api_key.scope_missing",
"message": "Missing API key scopes: calls:read"
}

Asosiy HTTP statuslar va kodlar:

  • 400 calls.invalid_date_range — noto'g'ri sanalar oralig'ini bildiradi;
  • 400 calls.invalid_phone — telefon filtrida raqamlar yo'qligini bildiradi;
  • 400 calls.invalid_cursor — shikastlangan cursorni bildiradi;
  • 400 calls.cursor_filter_mismatch — sahifalash filtrlarining o'zgarganini bildiradi;
  • 401 api_key.required — kalit berilmaganini bildiradi;
  • 401 api_key.invalid — noto'g'ri yoki bekor qilingan kalitni bildiradi;
  • 401 api_key.expired — muddati o'tgan kalitni bildiradi;
  • 403 api_key.ip_not_allowed — IP whitelist mos kelmaganini bildiradi;
  • 403 api_key.scope_missing — kerakli scope yo'qligini bildiradi;
  • 400 calls.invalid_phone (qo'ng'iroq boshlashda) — noto'g'ri tashqi raqamni bildiradi;
  • 404 calls.not_found — qo'ng'iroq topilmaganini yoki ruxsat yo'qligini bildiradi;
  • 404 calls.extension_not_found — ichki raqam topilmaganini, o'chirilganini yoki bo'lim bo'yicha kalit uchun ruxsat etilmaganini bildiradi;
  • 404 recordings.not_found — audioyozuv yo'qligini yoki xatolik yuz berganini bildiradi;
  • 409 calls.concurrent_limit_exceeded — tenantning bir vaqtdagi chaqiruvlar limiti oshib ketganini bildiradi;
  • 409 recordings.not_ready — fayl hali qayta ishlanayotganini bildiradi;
  • 422 calls.route_not_found — raqam uchun chiquvchi marshrut yo'qligini bildiradi;
  • 503 calls.telephony_unavailable — telefoniya vaqtincha ishlamayotganini bildiradi;
  • 416 recordings.invalid_range — noto'g'ri bayt diapazonini bildiradi;
  • 429 rate_limit.exceeded — kalit limiti oshib ketganini bildiradi.

13. Muntazam sinxronizatsiya misoli​

Node.js da misol:

const baseUrl = "https://api.4phone.uz/api/v1/external";
const apiKey = process.env.FOURPHONE_API_KEY;

async function request(path) {
const response = await fetch(`${baseUrl}${path}`, {
headers: {
"X-Api-Key": apiKey,
},
});

if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(
`4phone API ${response.status}: ${error.code || error.message || "unknown"}`,
);
}

return response.json();
}

async function loadCalls(startedFrom) {
const calls = [];
let cursor = null;

do {
const query = new URLSearchParams({
startedFrom,
limit: "100",
});

if (cursor) {
query.set("cursor", cursor);
}

const page = await request(`/calls?${query.toString()}`);
calls.push(...page.data);
cursor = page.meta.nextCursor;
} while (cursor);

return calls;
}

id maydonini noyob (unique) maydon sifatida saqlang. Muvaffaqiyatli sikldan so'ng keyingi so'rovda kichik vaqt ustma-ust tushishini qoldirib, checkpoint qiymatini dateIso bo'yicha yangilang.

14. Diagnostika​

API 401 qaytaradi​

Quyidagilarni tekshiring:

  • kalit X-Api-Key yoki Bearer sarlavhasida uzatilganligini;
  • qiymat to'liq nusxalanganligini;
  • kalit bekor qilinmaganligini;
  • amal qilish muddati tugamaganligini.

API 403 qaytaradi​

Quyidagilarni tekshiring:

  • calls:read ruxsati tanlanganligini;
  • qo'ng'iroqni boshlash uchun calls:create ruxsati tanlanganligini;
  • audioyozuv uchun recordings:read ruxsati tanlanganligini;
  • IP whitelist mijozning ommaviy chiquvchi IP manzilini o'z ichiga olganligini.

Ro'yxat bo'sh​

Quyidagilarni tekshiring:

  • startedFrom va startedTo dagi davr va vaqt mintaqasini;
  • yo'nalish va statuslarni;
  • kalitning bo'lim bo'yicha cheklovini;
  • extensionNumber qiymatini;
  • qo'ng'iroq ichki emasligini.

Audioyozuv 409 qaytaradi​

Fayl hali qayta ishlanmoqda. CALL_RECORDING_READY hodisasini kuting yoki backoff bilan tekshirishni takrorlang.

Qo'ng'iroqni boshlash 404 qaytaradi​

Quyidagilarni tekshiring:

  • ichki raqam mavjud va faol ekanligini;
  • kalit boshqa bo'lim bilan cheklanmaganligini;
  • extensionNumber maydonida mijozning telefon raqami emas, balki ichki raqam uzatilganligini.

Qo'ng'iroqni boshlash 202 qaytaradi, ammo mijozga qo'ng'iroq bormadi​

202 statusi faqat vazifa qabul qilinganini tasdiqlaydi. Tarixda callId bo'yicha natijani tekshiring: agar xodim javob bermagan bo'lsa, tashqi raqam terilmaydi. Agar xodim javob bergan bo'lsa, yakunlangan qo'ng'iroq statusini, chiquvchi marshrutni va trank holatini tekshiring.

Webhook yaratilmayapti​

Quyidagilarni tekshiring:

  • webhook faol ekanligini;
  • kerakli hodisa tanlanganligini;
  • URL HTTPS dan foydalanayotganligini;
  • DNS faqat ommaviy IP manzillarni qaytarayotganligini;
  • sekret mavjudligini.

Webhook FAILED yoki DLQ statusiga ega​

Yetkazib berishlar tarixini oching va quyidagilarni tekshiring:

  • HTTP kodni;
  • oxirgi xatolik matnini;
  • javob vaqtini;
  • TLS sertifikatining yaroqliligini;
  • endpoint 10 soniyadan tezroq javob berayotganligini.

Xatolik bartaraf etilgandan so'ng Replay tugmasidan foydalaning.

HMAC imzosi mos kelmayapti​

Quyidagilarni tekshiring:

  • dastlabki raw body ishlatilayotganligini;
  • sekret aynan shu webhookka tegishli ekanligini;
  • qator ID, timestamp va body qismlarini to'g'ri tartibda o'z ichiga olganligini;
  • hex qiymatidan oldin v1, prefiksi borligini;
  • server vaqti sinxronlanganligini;
  • rotatsiyadan so'ng yangi sekret ishlatilayotganligini.

15. Xavfsizlik​

  • Har bir tizim uchun alohida kalit yarating.
  • Faqat zarur ruxsatlarni (scopes) bering.
  • Production kalitini mijozning ommaviy IP manzili bilan cheklang.
  • Sinov (test) kalitlariga amal qilish muddatini belgilang.
  • Kalitlar va webhook sekretlarini Git repozitoriysida saqlamang.
  • Sekretlarni URL orqali uzatmang.
  • Avtorizatsiya sarlavhalarini loglarga yozmang.
  • JSON qayta ishlanishidan oldin HMAC imzosini tekshiring.
  • Timestamp oynasini 5 daqiqadan ko'p bo'lmagan holda tekshiring.
  • Webhook ID bo'yicha idempotentlikni ta'minlang.
  • Ma'lumot sizib chiqqanda darhol kalitni bekor qiling yoki webhook sekretini yangilang.

16. Moslik (Kompatibillik)​

Payload ning joriy versiyasi:

{
"schemaVersion": 1
}

Yangi majburiy bo'lmagan maydonlar API URL manzilini o'zgartirmasdan qo'shilishi mumkin. Mijoz tizimi notanish maydon tufayli payloadni rad etmasligi kerak. Moslikni buzadigan (breaking) o'zgarishlar API ning yangi versiyasida e'lon qilinadi.