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:
- Yangi hodisalarni webhooklar orqali qabul qilish.
- Qo'ng'iroqni o'z bazangizda
idmaydoni bo'yicha saqlash. CALL_RECORDING_READYhodisasidan keyin audioyozuvni yuklab olish.- 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:
Sozlamalarbo'limini oching.Integratsiyalarbo'limiga o'ting.API kalitlarisahifasini oching.Kalit yaratishtugmasini bosing.- Tushunarli nom kiriting, masalan
Bitrix exportyokiBI production. calls:readruxsatini (scope) tanlang.- Agar CRM tugma orqali qo'ng'iroqni boshlashi kerak bo'lsa,
calls:createruxsatini tanlang. - Agar mijoz tizimiga audioyozuv fayllari kerak bo'lsa,
recordings:readruxsatini tanlang. - Zarurat bo'lsa, kalitni bo'lim, IP manzillar va amal qilish muddati bo'yicha cheklang.
- 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:readyakunlangan qo'ng'iroqlar ro'yxati va kartochkasini olishga ruxsat beradi.calls:createCRM tizimidan chiquvchi qo'ng'iroqni boshlashga ruxsat beradi.recordings:readaudioyozuv 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:
ANSWEREDBUSYNO_ANSWERFAILEDCANCELLED
5.1. Filtrlar
Quyidagi parametrlar qo'llab-quvvatlanadi:
direction—INBOUNDyokiOUTBOUNDqiymati 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—trueyokifalseqiymati bilan;limit— 1 dan 100 gacha, standart qiymati 50;cursor— oldingi javobningmeta.nextCursormaydonidan 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—INBOUNDyokiOUTBOUNDqiymatini 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—dateuchun ishlatilgan vaqt mintaqasini ko'rsatadi.durationSeconds— sof suhbat vaqtini soniyalarda saqlaydi. Javob berilmagan qo'ng'iroq uchun qiymat0ga teng.extensionNumber— xodimning ichki raqamini yokinullqiymatini 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 Sharifqiymatini saqlaydi;- agar F.I.Sh. to'liq to'ldirilmagan bo'lsa,
fromtelefon 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:
CAPTUREDACCEPTEDUPLOADEDAVAILABLEFAILEDARCHIVED
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
Sozlamalarbo'limini oching.Integratsiyalarbo'limiga o'ting.Webhookssahifasini oching.Webhook qo'shishtugmasini bosing.- Nomini kiriting.
- Mijoz ishlov beruvchisining (handler) ommaviy HTTPS URL manzilini kiriting.
- Kiruvchi qo'ng'iroq kelgan paytda kontakt kartochkasini ko'rsatish kerak
bo'lsa,
CALL_STARThodisasini tanlang. CALL_COMPLETEDhodisasini tanlang.- Agar audioyozuv kerak bo'lsa,
CALL_RECORDING_READYhodisasini tanlang. - Xavfsiz avtomatik generatsiya uchun sekret maydonini bo'sh qoldiring.
- 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.frommijozning raqami,data.tomijoz tergan raqam,data.extensionNumberesa 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.callIdva turlidata.extensionNumberqiymatlariga 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.callIdvadata.extensionNumberjuftligi uchun bir marta yuboriladi. - Bu paytda qo'ng'iroq yozuvi tarixda hali yaratilmagan, shuning uchun
hodisada
data.id,durationSecondsvarecordingyo'q.CALL_COMPLETEDvaCALL_RECORDING_READYbilan bog'lash uchundata.callIddan foydalaning: u uchala hodisada ham bir xil. - Yetkazib berish qayta urinishlar bilan amalga oshiriladi, shuning uchun
hodisalar tartibi kafolatlanmaydi. Agar
CALL_STARTxuddi shudata.callIdbilanCALL_COMPLETEDdan 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 /callsmetodi 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-Keyyoki Bearer sarlavhasida uzatilganligini; - qiymat to'liq nusxalanganligini;
- kalit bekor qilinmaganligini;
- amal qilish muddati tugamaganligini.
API 403 qaytaradi
Quyidagilarni tekshiring:
calls:readruxsati tanlanganligini;- qo'ng'iroqni boshlash uchun
calls:createruxsati tanlanganligini; - audioyozuv uchun
recordings:readruxsati tanlanganligini; - IP whitelist mijozning ommaviy chiquvchi IP manzilini o'z ichiga olganligini.
Ro'yxat bo'sh
Quyidagilarni tekshiring:
startedFromvastartedTodagi davr va vaqt mintaqasini;- yo'nalish va statuslarni;
- kalitning bo'lim bo'yicha cheklovini;
extensionNumberqiymatini;- 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;
extensionNumbermaydonida 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.