Документация для разработчиков
REST-API для интеграций: история звонков и записи разговоров через защищённый HTTPS. Только чтение, доступ ограничен клиентом и IP-адресом. АТС наружу не открывается.
Введение
Partner API отдаёт данные телефонии клиента напрямую вашему сервису — без доступа к самой АТС.
Все запросы идут на базовый адрес по HTTPS. Ответы — в формате JSON (кроме аудиофайлов записей). Методы — только GET (интеграция на чтение).
Базовый URL
Каждый ключ привязан к одному клиенту (tenant) и работает только с согласованного IP-адреса. Ключ и whitelist выдаёт оператор SipCloud.
- Read-only. Изменить что-либо через API нельзя.
- Изоляция по клиенту. Ключ видит только данные своего клиента.
- Whitelist по IP. Запросы принимаются только с указанных адресов.
https://sipcloud.uz/partner/v1
curl https://sipcloud.uz/partner/v1/ping \
-H "Authorization: Bearer $KEY"
{
"ok": true,
"tenant": "ChoCo",
"scopes": ["calls:read", "recordings:read"]
}
Аутентификация
API использует Bearer-токен. Передавайте ключ в заголовке Authorization с каждым запросом:
Формат ключа
Ключ имеет вид sck_…. Он read-only, привязан к клиенту и разрешён только с согласованного IP. Альтернативно можно передавать ключ в заголовке X-Api-Key.
Authorization: Bearer sck_your_key_here
{
"ok": false,
"error": "missing api key (Authorization: Bearer …)"
}
Ошибки и коды
Успех — HTTP 200. Ошибки возвращаются с соответствующим кодом и телом { "ok": false, "error": "…" }.
| Код | Значение |
|---|---|
200 | Успех. |
400 | Некорректные параметры (например, формат даты). |
401 | Нет / неверный / отозванный ключ. |
403 | IP не в whitelist или не хватает scope. |
404 | Объект не найден / запись ещё не готова. |
5xx | Временная ошибка — повторите с экспоненциальной задержкой. |
{
"ok": false,
"error": "ip not allowed",
"your_ip": "203.0.113.7"
}
{
"ok": false,
"error": "scope required: recordings:read"
}
Звонки v2 — один внешний звонок = одна запись
Рекомендуемый метод. Технические участки АТС (очередь, обзвон сотрудников, переводы) собраны в одну внешнюю сессию. Счётчики совпадают с кабинетом и Excel. Параметры from, to, limit, cursor — как в v1. В ответе: schema_version, unit=external_call, tz, filters, as_of.
| Поле | Описание |
|---|---|
normalized_call_id | ID внешнего звонка в SipCloud — первичный ключ на вашей стороне. |
source_ids.linkedid | Корневой идентификатор звонка на АТС. |
direction | in · out · internal |
outcome | Входящий: answered (контакт с сотрудником) · missed · failed. Исходящий: answered · noanswer · busy · failed. |
reason | Причина пропуска: no_answer · queue_abandon · ivr. |
client, line, queue | Номер клиента (только цифры, 998…), номер компании, очередь. |
operator, offered, offers | Кто ответил (или звонил); кому предлагался звонок; число предложений. |
wait_sec, talk_sec | Ожидание до ответа сотрудника; разговор без двойного счёта параллельных участков. |
revision | Растёт, если звонок пересчитан (поздний участок, поздний ответ). |
curl "https://sipcloud.uz/partner/v2/calls?from=2026-10-01&to=2026-10-01" \
-H "Authorization: Bearer $KEY"
{ "ok": true, "schema_version": 2, "unit": "external_call",
"tz": "Asia/Tashkent", "count": 1, "next_cursor": null,
"calls": [{ "normalized_call_id": 1574,
"source_ids": {"linkedid": "mikopbx-1790742279.34094"},
"direction": "in", "outcome": "answered", "reason": null,
"client": "998903268886", "queue": "2200106", "operator": "101",
"offered": ["100","101","102","103"], "offers": 4,
"wait_sec": 16, "talk_sec": 139, "revision": 1,
"recording_url": "https://sipcloud.uz/partner/v1/recording?uid=…" }] }
История звонков
Возвращает список звонков клиента за период, отсортированный по времени. Поддерживает постраничную выборку по курсору.
Query-параметры
| Параметр | Тип | Описание |
|---|---|---|
from | date | Начало периода YYYY-MM-DD. По умолчанию — вчера. TZ Asia/Tashkent. |
to | date | Конец периода YYYY-MM-DD. По умолчанию — сегодня. |
limit | int | 1–1000. По умолчанию 200. |
cursor | string | Курсор из next_cursor предыдущего ответа. |
Поля звонка
| Поле | Описание |
|---|---|
uniqueid | Уникальный ID звонка (первичный ключ на вашей стороне). |
calldate | Время начала, ISO 8601 со смещением. |
direction | in · out · internal. |
src / dst | Номер вызывающего / вызываемого. |
operator | Внутренний номер оператора. |
disposition | ANSWERED · NOANSWER · BUSY · FAILED. |
billsec / duration | Секунды разговора / всего. |
has_recording | true, если доступна запись. |
recording_url | Ссылка на аудио (или null). |
curl -G https://sipcloud.uz/partner/v1/calls \
-H "Authorization: Bearer $KEY" \
--data-urlencode "from=2026-09-18" \
--data-urlencode "to=2026-09-18" \
--data-urlencode "limit=500"$ch = curl_init("https://sipcloud.uz/partner/v1/calls?from=2026-09-18&to=2026-09-18");
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$KEY}"],
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);import requests
r = requests.get(
"https://sipcloud.uz/partner/v1/calls",
headers={"Authorization": f"Bearer {KEY}"},
params={"from": "2026-09-18", "to": "2026-09-18", "limit": 500},
)
data = r.json()const res = await fetch(
"https://sipcloud.uz/partner/v1/calls?from=2026-09-18&to=2026-09-18",
{ headers: { Authorization: `Bearer ${KEY}` } }
);
const data = await res.json();{
"ok": true,
"count": 200,
"next_cursor": "eyJjZCI6Ii4uLiJ9",
"calls": [
{
"uniqueid": "mikopbx-1789234256.63825_1b15st",
"calldate": "2026-09-18T17:30:56+05",
"direction": "in",
"src": "781295555",
"dst": "100",
"operator": "100",
"did": "555157500",
"trunk": "",
"disposition": "ANSWERED",
"billsec": 42,
"duration": 55,
"has_recording": true,
"recording_url": "https://sipcloud.uz/partner/v1/recording?uid=mikopbx-1789234256.63825_1b15st"
}
]
}
Запись разговора
Отдаёт аудиофайл записи (audio/mpeg или audio/wav). Поддерживается заголовок Range — можно докачивать и перематывать.
Query-параметры
| Параметр | Тип | Описание |
|---|---|---|
uidобязателен | string | uniqueid звонка из ответа /calls. |
has_recording: true. Если запись ещё загружается на портал, вернётся 404 recording not available yet (обычно готова через несколько минут после звонка; хранение 14 дней).curl -G https://sipcloud.uz/partner/v1/recording \
-H "Authorization: Bearer $KEY" \
--data-urlencode "uid=$UID" \
-o call.mp3
# бинарный аудиопоток; сохраняется в call.mp3
# заголовки: Content-Type, Accept-Ranges: bytes
Проверка доступа
Проверяет ключ и возвращает клиента и доступные scope. Удобно для healthcheck интеграции.
curl https://sipcloud.uz/partner/v1/ping \
-H "Authorization: Bearer $KEY"
{ "ok": true, "tenant": "ChoCo",
"scopes": ["calls:read", "recordings:read"] }
Вебхуки
SipCloud отправляет POST с JSON на ваш URL. События: call.ended — один раз на завершённый внешний звонок (примерно через 90 с после окончания, когда собраны все участки); call.updated — если звонок пересчитан позже (растёт revision); recording.ready — запись загружена (session_id, recording_uid).
Заголовки и подпись
X-Event-Id | ID события. Повторная доставка приходит с тем же ID — обрабатывайте идемпотентно. |
X-Timestamp | Время подписи (unix). Отклоняйте запросы старше 5 минут — защита от повторов. |
X-Signature | HMAC-SHA256(secret, X-Timestamp + "." + тело) в hex. |
X-Attempt | Номер попытки. Ответ не 2xx — до 5 попыток с паузой 1 мин, 5 мин, 30 мин, 2 ч. |
{ "event_id": 812345, "type": "call.ended",
"tenant_id": "…", "session_id": 1574, "revision": 1,
"schema_version": 2, "occurred_at": "2026-10-01T12:00:00+00",
"data": { "direction": "in", "outcome": "answered",
"client": "998903268886", "operator": "101",
"wait_sec": 16, "talk_sec": 139, "…": "…" } }
Инкрементальная выгрузка
Чтобы регулярно забирать новые звонки без дублей:
- Запросите
/callsза нужный период. - Внутри периода листайте по
cursor, передаваяnext_cursorиз ответа, пока он не станетnull. - Сохраняйте максимальный обработанный
calldateиuniqueid— дедуплицируйте поuniqueid. - Для звонков с
has_recording: trueскачивайте аудио поrecording_url.
cursor, seen = None, set()
while True:
r = requests.get(BASE + "/calls",
headers={"Authorization": f"Bearer {KEY}"},
params={"from": DAY, "to": DAY, "limit": 1000, "cursor": cursor}).json()
for c in r["calls"]:
if c["uniqueid"] in seen: # дедуп
continue
seen.add(c["uniqueid"])
process(c)
cursor = r["next_cursor"]
if not cursor: # данные закончились
break
Быстрый старт
Получите ключ
Оператор SipCloud выдаёт read-only ключ и добавляет IP вашего сервера в whitelist.
Проверьте доступ
Вызовите /ping с заголовком Authorization: Bearer — убедитесь, что клиент и scope верны.
Забирайте данные
Периодически тяните /calls с курсором и скачивайте записи по recording_url.