# CallHub24 — Tashqi API hujjati (v1)

Ushbu hujjat, CallHub24'ning `/api/v1/*` tashqi API'sini, o'z tizimingizga (1C, boshqa CRM, ichki hisobot xizmati va h.k.) ulash uchun, TO'LIQ ma'lumot beradi.

**Asosiy manzil (base URL):**
```
https://app.callhub24.uz/api/v1
```

**API nima uchun mo'ljallangan:**
- Qo'ng'iroqlar tarixi va audio yozuvlarni, o'z tizimingizga (masalan, hisobot/BI tizimiga) avtomatik olib turish.
- Xodimlar ro'yxati va statistikani, tashqarida ko'rsatish/tahlil qilish.
- **Yangi:** o'z tizimingizdan (masalan, 1C'dagi qarzdorlar ro'yxatidan), mijozlarga avtomatik SMS yuborish — xodim telefonidan, mavjud SMS yuborish infratuzilmasi orqali.

> Bu — HTTP+JSON API. Barcha so'rov/javob tanasi (body) `application/json` formatida (SMS yuborish va boshqa `POST` so'rovlari uchun), audio yuklab olish esa xom (binary) audio oqimi qaytaradi.

---

## Mundarija

1. [Autentifikatsiya](#1-autentifikatsiya)
2. [Umumiy xato formati](#2-umumiy-xato-formati)
3. [Endpointlar](#3-endpointlar)
   - [GET /calls](#get-calls)
   - [GET /calls/{id}/audio](#get-callsidaudio)
   - [GET /employees](#get-employees)
   - [GET /stats](#get-stats)
   - [POST /sms/send](#post-smssend)
4. [SMS yuborish — batafsil](#4-sms-yuborish--batafsil)
5. [Amaliy misollar](#5-amaliy-misollar)
6. [Tez-tez uchraydigan xatolar (FAQ)](#6-tez-tez-uchraydigan-xatolar-faq)
7. [O'zgarishlar tarixi](#7-ozgarishlar-tarixi)

---

## 1. Autentifikatsiya

API kalitni **Boshqaruv paneli** (admin panel, `https://app.callhub24.uz/admin.html`) **→ Sozlamalar → API** bo'limidan yaratasiz:

1. "Kalit nomi" maydoniga, kalitni qayerda ishlatishingizni eslab qolish uchun nom yozing (masalan: `"1C integratsiyasi"`).
2. **"Yaratish"** tugmasini bosing.
3. Ochilgan oynada ko'rsatilgan, to'liq kalitni (`sk_live_...` bilan boshlanadi) **DARHOL nusxalab, xavfsiz joyda saqlang** — u faqat SHU BIR MARTA, to'liq holda ko'rsatiladi. Keyinroq, faqat kalitning boshi/oxiri (masalan `sk_live_aB3xY9...k7Qz`) ko'rinadi, to'liq qiymat qayta ko'rsatilmaydi.

> ℹ️ Agar "API" bo'limi ko'rinmasa yoki kalit yaratish tugmasi ishlamasa — tarifingizda tashqi API funksiyasi yoqilmagan bo'lishi mumkin. Administratoringiz yoki CallHub24 texnik yordamiga murojaat qiling.

### So'rovga qanday qo'shiladi

Har bir `/api/v1/*` so'rovida, `Authorization` sarlavhasida (header), `Bearer` sxemasi bilan yuboriladi:

```
Authorization: Bearer sk_live_aB3xY9cDeFgHiJkLmNoPqRsTuVwXyZ7Qz
```

### Autentifikatsiya xatolari

| Holat | HTTP kodi | Javob tanasi |
|---|---|---|
| `Authorization` sarlavhasi umuman yo'q, yoki `sk_live_` bilan boshlanmaydi | `401` | `{"error": "API kalit talab qilinadi (Authorization: Bearer sk_live_...)"}` |
| Kalit mavjud, lekin bazada topilmadi yoki bekor qilingan (revoked) | `401` | `{"error": "API kalit yaroqsiz yoki bekor qilingan"}` |

**Muhim:** bitta API kalit, faqat SHU kalitni yaratgan kompaniyaning ma'lumotlariga kirish huquqini beradi. Boshqa kompaniyaning ma'lumotlariga (masalan, boshqa `id`'li qo'ng'iroq yozuviga) hech qanday holatda kira olmaysiz — bunday urinish, "topilmadi" (404) xatosi bilan yopiladi (kompaniyalar orasidagi ma'lumot sizib chiqishining oldini olish uchun, "ruxsat yo'q" emas, aynan "topilmadi" qaytariladi).

---

## 2. Umumiy xato formati

Barcha xato javoblari (audio endpoint'idan tashqari), quyidagi shaklda, JSON sifatida qaytadi:

```json
{ "error": "Xato haqida o'qiladigan tavsif" }
```

Ba'zi endpointlar (masalan, SMS yuborish), qo'shimcha `code` maydonini ham qaytaradi — dasturingiz, xato TURINI aniq aniqlashi uchun (matn tarjimasiga bog'liq bo'lmasdan):

```json
{ "error": "Bu raqamga yaqinda allaqachon SMS yuborilgan — 60 soniyadan keyin qayta urinib ko'ring", "code": "DUPLICATE_PHONE" }
```

### Umumiy HTTP kodlar

| Kod | Ma'nosi |
|---|---|
| `200` | Muvaffaqiyatli |
| `400` | So'rov noto'g'ri (majburiy maydon yo'q, noto'g'ri format) |
| `401` | Autentifikatsiya xatosi (kalit yo'q/yaroqsiz) |
| `404` | Resurs topilmadi (yoki boshqa kompaniyaga tegishli) |
| `429` | Juda ko'p so'rov (tezlik chegarasi yoki takrorlanish himoyasi) |
| `500` | Server xatosi (bizning tomonimizdan; qayta urinib ko'ring, davom etsa — texnik yordamga yozing) |

---

## 3. Endpointlar

### GET /calls

Kompaniyangizning qo'ng'iroqlar ro'yxatini qaytaradi (eng yangisi birinchi, maksimal **1000 ta** yozuv).

**So'rov:**
```
GET https://app.callhub24.uz/api/v1/calls
Authorization: Bearer sk_live_...
```

**Ixtiyoriy so'rov parametrlari (query string):**

| Parametr | Turi | Tavsifi | Misol |
|---|---|---|---|
| `date_from` | ISO 8601 sana/vaqt | Shu sanadan (kiritilgan) BOSHLAB | `2026-09-01T00:00:00.000Z` |
| `date_to` | ISO 8601 sana/vaqt | Shu sanagacha (kiritilgan) | `2026-09-14T23:59:59.999Z` |
| `employee_id` | butun son | Faqat shu xodimning qo'ng'iroqlari | `42` |
| `call_type` | matn (enum) | `incoming` / `outgoing` / `missed` | `missed` |
| `search` | matn | Qo'ng'iroq qiluvchi raqami bo'yicha qisman moslik (ilike) | `90123` |

Barcha parametrlar birga qo'llanilishi mumkin (AND mantig'i bilan).

**Muvaffaqiyatli javob (`200`):**
```json
{
  "data": [
    {
      "id": 58231,
      "employee_id": 42,
      "employee_name": "Aliyev Vali",
      "caller_number": "+998901234567",
      "call_type": "incoming",
      "duration_seconds": 187,
      "recording_path": "recordings/12/58231.m4a",
      "recording_mimetype": "audio/mp4",
      "recording_size_bytes": 1498112,
      "is_encrypted": true,
      "quality_score": 4,
      "quality_note": "Mijoz mamnun qoldi",
      "is_sale": true,
      "sms_sent": true,
      "called_back": false,
      "called_back_at": null,
      "called_back_method": null,
      "sms_error": null,
      "gps_lat": 41.311081,
      "gps_lng": 69.240562,
      "sim_slot": 0,
      "location_enabled": true,
      "client_uid": "a1b2c3d4-...",
      "company_id": 1021,
      "created_at": "2026-09-14T09:12:33.000Z"
    }
  ]
}
```

> `recording_path` bo'lishi — audio yozuv MAVJUD degani emas, faqat SERVERDA saqlangan yo'lni bildiradi. Haqiqiy audio faylni olish uchun, quyidagi `GET /calls/{id}/audio` dan foydalaning (chunki fayl, kompaniyaning shifrlash kaliti bilan shifrlangan holda saqlanadi va faqat shu endpoint orqali, shifrdan ochilgan holda beriladi).

**Xato javoblari:** faqat umumiy autentifikatsiya (`401`) va server (`500`) xatolari — bu endpoint uchun boshqa maxsus xato yo'q (noto'g'ri `call_type` qiymati ham, shunchaki bo'sh natija qaytaradi, xato emas).

---

### GET /calls/{id}/audio

Bitta qo'ng'iroqning audio yozuvini, XOM (binary) audio oqim sifatida qaytaradi (JSON EMAS).

**So'rov:**
```
GET https://app.callhub24.uz/api/v1/calls/58231/audio
Authorization: Bearer sk_live_...
```

| Parametr | Turi | Tavsifi |
|---|---|---|
| `id` (URL yo'lida) | butun son, majburiy | `GET /calls` javobidagi `id` maydoni |

**Muvaffaqiyatli javob (`200`):** `Content-Type` sarlavhasi audio formatiga mos (`recording_mimetype`, masalan `audio/mp4` yoki `audio/mpeg`) qilib o'rnatiladi, javob tanasida esa xom audio baytlar keladi. Faylni to'g'ridan-to'g'ri diskka yozib saqlashingiz mumkin.

**Xato javoblari:**

| Holat | HTTP kodi | Javob |
|---|---|---|
| `id` mavjud emas, BOSHQA kompaniyaga tegishli, yoki yozuv yo'q (`recording_path` bo'sh) | `404` | `{"error": "Yozuv topilmadi"}` |
| Yozuv bor deb belgilangan, lekin fayl saqlash tizimida (MinIO) topilmadi | `404` | `{"error": "Fayl topilmadi"}` |

---

### GET /employees

Kompaniyangizdagi barcha xodimlar ro'yxatini qaytaradi (faol va nofaol, ikkalasi ham).

**So'rov:**
```
GET https://app.callhub24.uz/api/v1/employees
Authorization: Bearer sk_live_...
```

Parametrlar yo'q — har doim BARCHA xodimlar qaytadi.

**Muvaffaqiyatli javob (`200`):**
```json
{
  "data": [
    {
      "id": 42,
      "name": "Aliyev Vali",
      "company_id": 1021,
      "is_active": true,
      "department": "Sotuv",
      "crm_role": "agent",
      "created_at": "2026-01-15T08:00:00.000Z"
    }
  ]
}
```

| Maydon | Turi | Tavsifi |
|---|---|---|
| `id` | butun son | Xodim ID'si. `POST /sms/send`ning "fixed" rejimida tanlanadigan xodim, aynan shu qiymat |
| `name` | matn | Ism-familiya |
| `company_id` | butun son | Kompaniya ID'si (har doim, so'rov yuborgan API kalitning o'ziga tegishli) |
| `is_active` | mantiqiy (boolean) | Xodim faolmi (litsenziyasi yoqilganmi) |
| `department` | matn yoki `null` | Bo'lim/departament nomi (agar belgilangan bo'lsa) |
| `crm_role` | matn | CRM ichidagi roli (masalan `agent`, `manager`) |
| `created_at` | ISO 8601 sana/vaqt | Xodim qachon qo'shilgani |

> 🔒 **Xavfsizlik bo'yicha eslatma:** bu javob, ATAYLAB, FAQAT yuqoridagi 7 ta maydon bilan cheklangan. Xodimning ICHKI, nozik ma'lumotlari (PIN xeshi, qurilma identifikatori, litsenziya kaliti, push-bildirishnoma tokeni, maosh/bonus stavkasi, shaxsiy SIM raqami) — tashqi API orqali HECH QACHON qaytarilmaydi.

**Xato javoblari:** faqat umumiy autentifikatsiya (`401`) va server (`500`) xatolari.

---

### GET /stats

Berilgan sana oralig'idagi, umumlashtirilgan qo'ng'iroq statistikasini qaytaradi.

**So'rov:**
```
GET https://app.callhub24.uz/api/v1/stats?date_from=2026-09-01T00:00:00.000Z&date_to=2026-09-14T23:59:59.999Z
Authorization: Bearer sk_live_...
```

| Parametr | Turi | Majburiymi | Tavsifi |
|---|---|---|---|
| `date_from` | ISO 8601 sana/vaqt | Ixtiyoriy | Berilmasa — barcha vaqt bo'yicha |
| `date_to` | ISO 8601 sana/vaqt | Ixtiyoriy | Berilmasa — barcha vaqt bo'yicha |

**Muvaffaqiyatli javob (`200`):**
```json
{
  "data": {
    "total_calls": 342,
    "incoming_calls": 198,
    "outgoing_calls": 121,
    "missed_calls": 23,
    "answered_incoming": 175,
    "sms_sent": 40,
    "sms_effectiveness_percent": 35,
    "avg_duration_seconds": 96,
    "total_sales": 18
  }
}
```

| Maydon | Tavsifi |
|---|---|
| `total_calls` | Jami qo'ng'iroqlar soni |
| `incoming_calls` / `outgoing_calls` / `missed_calls` | Turi bo'yicha taqsimot |
| `answered_incoming` | Javob berilgan kiruvchi qo'ng'iroqlar (davomiyligi > 0) |
| `sms_sent` | Qo'ng'iroqdan keyin SMS yuborilgan holatlar soni |
| `sms_effectiveness_percent` | SMS yuborilganlardan, qancha foizi keyinchalik "qayta bog'landi" (`called_back`) holatiga o'tgani |
| `avg_duration_seconds` | O'tkazib yuborilmagan qo'ng'iroqlarning o'rtacha davomiyligi (soniyada) |
| `total_sales` | "Sotuv" deb belgilangan qo'ng'iroqlar soni |

**Xato javoblari:** faqat umumiy autentifikatsiya (`401`) va server (`500`) xatolari.

---

### POST /sms/send

Tashqi tizimingizdan (masalan, 1C), mijozga SMS yuborishni SO'RAYDI — real SMS DARHOL emas, navbatga qo'yiladi va xodim telefonidan yuboriladi. To'liq mexanizm uchun, [4-bo'limga](#4-sms-yuborish--batafsil) qarang.

**So'rov:**
```
POST https://app.callhub24.uz/api/v1/sms/send
Authorization: Bearer sk_live_...
Content-Type: application/json

{
  "phone": "+998901234567",
  "message": "Hurmatli mijoz, to'lov muddati o'tgan qarzingiz mavjud. Iltimos, tez orada to'lovni amalga oshiring."
}
```

**So'rov tanasi (JSON body) maydonlari:**

| Maydon | Turi | Majburiymi | Tavsifi | Misol |
|---|---|---|---|---|
| `phone` | matn | ✅ Ha | Qabul qiluvchi telefon raqami. Kamida 7 ta raqamdan iborat bo'lishi kerak (bo'sh joy/tire/qavslar avtomatik e'tiborga olinmaydi) | `"+998901234567"` |
| `message` | matn | ✅ Ha | SMS matni (bo'sh bo'lmasligi kerak) | `"Qarzingiz bor..."` |

**Muvaffaqiyatli javob (`200`):**
```json
{ "success": true }
```
> Diqqat: `200`/`success: true` — SMS "yuborildi" degani EMAS, "navbatga muvaffaqiyatli qo'yildi" degani. Haqiqiy yetkazilish, xodim qurilmasining onlayn holatiga bog'liq (pastga qarang).

**Xato javoblari:**

| Holat | HTTP kodi | Javob | `code` |
|---|---|---|---|
| `phone` yoki `message` yuborilmagan/bo'sh | `400` | `{"error": "phone va message majburiy"}` | — |
| `phone` yaroqsiz formatda (raqamlar soni yetarli emas) | `400` | `{"error": "Telefon raqami noto'g'ri formatda: \"123\""}` | — |
| Kompaniyada SMS yuboruvchi xodim sozlanmagan, yoki "fixed" xodim/hech qanday faol xodim yo'q | `400` | `{"error": "SMS yuboradigan xodim sozlanmagan yoki faol xodim yo'q (Sozlamalar → API)"}` | — |
| Shu `(kompaniya, telefon)` juftligiga, oxirgi 60 soniya ichida, allaqachon SMS navbatga qo'yilgan | `429` | `{"error": "Bu raqamga yaqinda allaqachon SMS yuborilgan — 60 soniyadan keyin qayta urinib ko'ring", "code": "DUPLICATE_PHONE"}` | `DUPLICATE_PHONE` |
| Kalit yo'q/yaroqsiz | `401` | [1-bo'limga qarang](#autentifikatsiya-xatolari) | — |
| Daqiqasiga 60 so'rovdan oshgan | `429` | `{"error": "Juda ko'p so'rov — bir daqiqa kuting"}` | — |

---

## 4. SMS yuborish — batafsil

### 4.1. Umumiy oqim

```
1C (yoki boshqa tizim)
   │  POST /api/v1/sms/send  {phone, message}
   ▼
CallHub24 server
   │  - dublikat tekshiruvi
   │  - "kim yuboradi" (xodim) ni aniqlaydi
   │  - navbatga ("sms_commands") qo'shadi, DARHOL 200 qaytaradi
   ▼
Xodimning Android qurilmasi (CallHub24 ilovasi)
   │  - navbatni davriy so'rab turadi
   │  - navbatdagi buyruqni oladi, O'Z SIM kartasidan HAQIQIY SMS yuboradi
   │  - natijani (muvaffaqiyatli/xato) serverga qaytaradi
```

Shuning uchun: **SMS, so'rov yuborilgandan bir necha soniya-daqiqa keyin yetadi**, DARHOL emas — bu, xodim qurilmasi navbatni tekshirish oralig'iga va quyidagi cheklovlarga bog'liq.

### 4.2. Kim nomidan yuboriladi — sozlash

Boshqaruv paneli → **Sozlamalar → API** bo'limida, "Tashqi API orqali SMS yuborish" kartochkasida, ikkita rejimdan birini tanlaysiz:

| Rejim | Tavsifi | Qachon mos |
|---|---|---|
| **"Har doim bitta xodimdan" (fixed)** | Barcha `/sms/send` so'rovlari, DOIMO bitta, admin belgilagan xodim telefonidan yuboriladi | Kichik hajm (kuniga bir necha o'nlab SMS) uchun mos |
| **"Aylanma tartibda" (round_robin)** | Har bir yangi so'rov, keyingi FAOL xodimga navbat bilan biriktiriladi (1-xodim, 2-xodim, 3-xodim, ..., yana 1-xodimdan) | Katta hajm uchun tavsiya etiladi — pastdagi 4.3-bandga qarang |

Agar bu sozlama umuman kiritilmagan bo'lsa (yoki "fixed" tanlangan, lekin xodim ko'rsatilmagan/faolsizlantirilgan bo'lsa), `POST /sms/send` **har doim** `400` xato bilan rad etiladi — "jim" muvaffaqiyatsizlik bo'lmaydi.

### 4.3. Tezlik — nega muhim

Har bir xodim TELEFONI (SIM karta operator tomonidan bloklanmasligi uchun), SMS'lar orasida **kamida 45 soniya** kutadi. Ya'ni:

- **"Fixed"** rejimda, BITTA xodimdan, soatiga taxminan **~80 ta** SMS yuborish mumkin (3600 / 45).
- **"Aylanma tartib"** rejimida, bu tezlik, FAOL xodimlar soniga ko'paytiriladi — masalan, 10 ta faol xodim bilan, soatiga taxminan **~800 ta**.

Agar kutilayotgan hajmingiz kattaroq bo'lsa (masalan, kuniga bir necha ming SMS), "aylanma tartib" rejimini, YETARLICHA ko'p faol xodim bilan ishlatishni tavsiya qilamiz.

### 4.4. Takrorlanishdan himoya (dublikat)

Tashqi tizim (masalan, xato yoki qayta-urinish tsikli tufayli), bir xil raqamga, ketma-ket bir necha marta so'rov yuborib yuborishi mumkin. Bundan himoyalanish uchun:

> Bitta **(kompaniya, telefon raqami)** juftligiga, oxirgi so'rov qabul qilingandan keyin, **kamida 60 soniya** o'tmaguncha, YANGI SMS navbatga QO'YILMAYDI — `429 DUPLICATE_PHONE` qaytadi.

Bu tekshiruv, SMS manbasidan (qo'lda, avtomatik bosqich-SMS, yoki shu tashqi API) qat'i nazar ishlaydi — ya'ni, agar shu mijozga, CallHub24 CRM ichidan ham, YAQINDA (60 soniya ichida) boshqa SMS yuborilgan bo'lsa, tashqi API so'rovi ham shu sababdan rad etilishi mumkin.

**Tavsiya:** agar `429 DUPLICATE_PHONE` olsangiz, so'rovni DARHOL qaytarmang — kamida 60 soniya kutib, keyin qayta urining (yoki umuman qayta urinmang, chunki ehtimol, o'sha SMS ALLAQACHON navbatga tushgan).

### 4.5. Tezlik chegarasi (rate limit) bilan o'zaro ta'siri

`POST /sms/send`, boshqa barcha `/api/v1/*` endpointlar bilan BIR XIL, umumiy chegaraga bo'ysunadi: **bitta API kalit uchun, daqiqasiga maksimal 60 so'rov**. Katta hajmdagi ro'yxatni (masalan, 500 ta qarzdor) yuborayotganda, buni hisobga oling — masalan, so'rovlar orasida ~1 soniyalik tanaffus qo'ying, yoki hajmni bir necha daqiqaga bo'lib yuboring.

---

## 5. Amaliy misollar

Quyidagi barcha misollarda, `sk_live_YOUR_API_KEY_HERE` o'rniga, o'zingizning haqiqiy API kalitingizni qo'ying.

### 5.1. cURL

**Qo'ng'iroqlar ro'yxatini olish:**
```bash
curl -s "https://app.callhub24.uz/api/v1/calls?date_from=2026-09-01T00:00:00.000Z&call_type=missed" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY_HERE"
```

**Audio yozuvni faylga yuklab olish:**
```bash
curl -s "https://app.callhub24.uz/api/v1/calls/58231/audio" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY_HERE" \
  -o call_58231.mp4
```

**SMS yuborish:**
```bash
curl -s -X POST "https://app.callhub24.uz/api/v1/sms/send" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+998901234567","message":"Hurmatli mijoz, qarzingiz muddati o'\''tdi."}'
```

### 5.2. JavaScript / Node.js

Qo'shimcha kutubxona shart emas — Node.js 18+ da o'rnatilgan `fetch` yetarli.

```js
const API_BASE = 'https://app.callhub24.uz/api/v1';
const API_KEY = 'sk_live_YOUR_API_KEY_HERE';

async function callHub24Request(path, options = {}) {
  const res = await fetch(`${API_BASE}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      ...(options.body ? { 'Content-Type': 'application/json' } : {}),
      ...options.headers
    }
  });
  const data = await res.json().catch(() => null);
  if (!res.ok) {
    throw new Error(`CallHub24 API xatosi (${res.status}): ${data?.error || 'Noma\'lum xato'}`);
  }
  return data;
}

// 1) So'nggi qarzdorlar ro'yxatini o'z tizimingizdan (1C, DB, va h.k.) oling
const debtors = [
  { phone: '+998901234567', message: "Hurmatli Aziz aka, qarzingiz muddati o'tdi. Iltimos, to'lovni amalga oshiring." },
  { phone: '+998907654321', message: "Hurmatli Dilnoza opa, qarzingiz muddati o'tdi. Iltimos, to'lovni amalga oshiring." }
];

// 2) Har biriga, TEZLIK CHEGARASINI hisobga olib (masalan, 1.5s tanaffus bilan), SMS yuboring
async function sendDebtorReminders(list) {
  for (const { phone, message } of list) {
    try {
      const result = await callHub24Request('/sms/send', {
        method: 'POST',
        body: JSON.stringify({ phone, message })
      });
      console.log(`OK: ${phone} navbatga qo'yildi`, result);
    } catch (err) {
      // #dublikat - agar 60s ichida qayta yuborilsa, bu KUTILGAN holat, xato emas
      console.error(`XATO: ${phone} -`, err.message);
    }
    await new Promise(r => setTimeout(r, 1500)); // tezlik chegarasi uchun tanaffus
  }
}

sendDebtorReminders(debtors);

// 3) Statistikani olish
callHub24Request('/stats?date_from=2026-09-01T00:00:00.000Z')
  .then(res => console.log('Statistika:', res.data));
```

### 5.3. Python

Qo'shimcha kutubxona kerak: `pip install requests`

```python
import time
import requests

API_BASE = "https://app.callhub24.uz/api/v1"
API_KEY = "sk_live_YOUR_API_KEY_HERE"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


def send_sms(phone: str, message: str) -> dict:
    response = requests.post(
        f"{API_BASE}/sms/send",
        headers=HEADERS,
        json={"phone": phone, "message": message},
        timeout=15,
    )
    data = response.json()
    if not response.ok:
        # 429 DUPLICATE_PHONE - shu raqamga yaqinda SMS yuborilgan, xato emas, kutilgan holat
        if data.get("code") == "DUPLICATE_PHONE":
            print(f"O'TKAZIB YUBORILDI (dublikat): {phone}")
            return data
        raise RuntimeError(f"CallHub24 API xatosi ({response.status_code}): {data.get('error')}")
    return data


def send_debtor_reminders(debtors: list[dict]):
    for debtor in debtors:
        try:
            result = send_sms(debtor["phone"], debtor["message"])
            print(f"OK: {debtor['phone']} navbatga qo'yildi -> {result}")
        except RuntimeError as err:
            print(f"XATO: {debtor['phone']} - {err}")
        time.sleep(1.5)  # tezlik chegarasi (60/daqiqa) uchun tanaffus


def get_stats(date_from: str, date_to: str) -> dict:
    response = requests.get(
        f"{API_BASE}/stats",
        headers=HEADERS,
        params={"date_from": date_from, "date_to": date_to},
        timeout=15,
    )
    response.raise_for_status()
    return response.json()["data"]


if __name__ == "__main__":
    debtors = [
        {"phone": "+998901234567", "message": "Hurmatli Aziz aka, qarzingiz muddati o'tdi."},
        {"phone": "+998907654321", "message": "Hurmatli Dilnoza opa, qarzingiz muddati o'tdi."},
    ]
    send_debtor_reminders(debtors)
    print(get_stats("2026-09-01T00:00:00.000Z", "2026-09-14T23:59:59.999Z"))
```

---

## 6. Tez-tez uchraydigan xatolar (FAQ)

**"401: API kalit talab qilinadi" — nima uchun, men kalitni yubordim-ku?**
`Authorization` sarlavhasi aniq shu formatda bo'lishi kerak: `Authorization: Bearer sk_live_...` (so'z boshida katta harf bilan `Bearer`, keyin BITTA bo'sh joy, keyin to'liq kalit). Ko'p uchraydigan xatolar: `Bearer` so'zini unutish, kalitni qo'shtirnoq bilan birga yuborish, yoki sarlavha nomini noto'g'ri yozish (`Authorisation`, `Api-Key` va h.k. — bular ISHLAMAYDI).

**"401: API kalit yaroqsiz yoki bekor qilingan" — kalitni to'g'ri nusxaladim shekilli?**
Kalit, faqat YARATILGAN paytda, TO'LIQ holda bir marta ko'rsatiladi. Agar uni to'liq nusxalamagan bo'lsangiz (masalan, faqat bir qismini), yoki admin panelda kalitni "Bekor qilish" bosilgan bo'lsa — yangi kalit yaratishga to'g'ri keladi.

**Nega `POST /sms/send`dan `200 {"success":true}` oldim, lekin mijozga SMS yetib bormadi?**
`200` javobi faqat "navbatga muvaffaqiyatli qo'yildi" degani — haqiqiy yetkazilish, tanlangan xodim(lar)ning Android qurilmasi ONLAYN va navbatni tekshirib turishiga bog'liq. Agar xodim qurilmasi uzoq vaqt oflayn bo'lsa, SMS, u qurilma qayta ulanguncha navbatda kutadi. Bu holatlar uchun, Boshqaruv panelidan, tegishli xodimning qurilma holatini tekshiring.

**Nega ba'zi so'rovlarim `429 DUPLICATE_PHONE` bilan qaytdi, garchi men birinchi marta yuborayotgan bo'lsam ham?**
Ehtimol, shu mijozga, oxirgi 60 soniya ichida, CallHub24 CRM'ning boshqa qismidan (masalan, avtomatik bosqich-SMS yoki qo'lda SMS) allaqachon SMS yuborilgan. Bu — xato emas, ikki marta ketma-ket SMS yuborilishining OLDINI OLISH mexanizmi.

**`GET /calls` javobida, `recording_path` bor, lekin audio yuklay olmayapman (`404 Fayl topilmadi`).**
Bu, kamdan-kam holatda, fayl saqlash tizimida (MinIO) texnik nosozlik yoki fayl hali to'liq yuklanib ulgurmagan bo'lishi mumkin. Bir necha daqiqadan keyin qayta urinib ko'ring; davom etsa, texnik yordamga yozing.

**`date_from`/`date_to` uchun qanday format ishlatishim kerak?**
ISO 8601 formatidagi to'liq sana-vaqt, masalan: `2026-09-14T00:00:00.000Z` (UTC). Faqat `2026-09-14` kabi qisqa formatlar ham ishlaydi, lekin ANIQ vaqt oralig'i kerak bo'lsa, to'liq formatni tavsiya qilamiz.

**Tezlik chegarasiga (429, umumiy) tez-tez tushib qolyapman — nima qilishim kerak?**
Kalitingiz, daqiqasiga 60 so'rov bilan cheklangan. Katta hajmdagi ma'lumot (masalan, yuzlab SMS) yuborayotgan bo'lsangiz, so'rovlar orasiga sun'iy tanaffus (masalan, 1–1.5 soniya) qo'shing — 5.2/5.3-bo'limdagi misollarda buning namunasi bor.

**Bir nechta xodim qo'shsam/o'chirsam, "aylanma tartib" avtomatik moslashadimi?**
Ha — "aylanma tartib" rejimi, HAR SAFAR so'rov kelganda, o'sha ondagi FAOL xodimlar ro'yxatini o'qiydi. Yangi xodim qo'shilsa, u navbatga avtomatik qo'shiladi; xodim faolsizlantirilsa, navbatdan avtomatik chiqadi — qo'shimcha sozlash shart emas.

---

## 7. O'zgarishlar tarixi

| Sana | O'zgarish |
|---|---|
| 2026-09-14 | **Xavfsizlik tuzatishi:** `GET /employees` javobi, endi FAQAT 7 ta xavfsiz maydonni qaytaradi (avval, tasodifan, ICHKI maydonlar — PIN xeshi, litsenziya kaliti va h.k. — ham ko'rinar edi). |
| 2026-09-14 | `POST /sms/send` qo'shildi (tashqi tizimlardan SMS yuborish). |
| — | `GET /calls`, `GET /calls/{id}/audio`, `GET /employees`, `GET /stats` — mavjud, dastlabki endpointlar. |

---

**Savollar bo'lsa:** [Telegram orqali texnik yordam](https://t.me/supp_callhub24)
