API и вебхуки для вашей CRM
REST API отдаёт и принимает лиды, звонки, разборы и диалоги. Вебхуки сообщают о событиях, как только они происходят. Ключи и адреса вебхуков выдаёт команда Phonix.
# Новые лиды
curl "https://app.phonix.website/api/v1/leads?status=new&limit=50" \
-H "Authorization: Bearer $PHONIX_KEY"
# Отправить звонок менеджера на разбор
curl -X POST https://app.phonix.website/api/v1/calls \
-H "Authorization: Bearer $PHONIX_KEY" \
-F file=@call.mp3 -F client_number=79261234567 \
-F employee_extension=101 -F external_id=crm-call-8812 Основное
- Базовый адрес
- https://app.phonix.website/api/v1
- Авторизация
- Authorization: Bearer phx_…
- Права ключа
- чтение и запись или только чтение
- Лимит
- 600 запросов в минуту на ключ
- Формат
- JSON, даты в ISO 8601, списки страницами
- Спецификация
- OpenAPI 3.1, GET /api/v1/openapi.json
Ресурсы
| Адрес | Что можно |
|---|---|
| /leads | список с поиском и фильтрами, создание, правка, хронология, заметки |
| /calls | список, карточка с расшифровкой и оценкой, загрузка файла или ссылки, повторный разбор, скачивание записи |
| /qa-scripts, /employees | скрипты-чек-листы и сотрудники для речевой аналитики |
| /analytics/overview, /analytics/qa | сводка за период и выполнение скрипта по пунктам и сотрудникам |
| /voice-agents, /bots, /bots/{id}/knowledge | настройка агентов, ботов и базы знаний |
| /channels | каналы компании и код виджета |
| /conversations | диалоги всех каналов, ответ оператора, передача боту |
| /webhooks/event-types | какие события Phonix присылает на вебхуки |
Примеры запросов
const res = await fetch('https://app.phonix.website/api/v1/calls?passed=false&limit=20', {
headers: { Authorization: `Bearer ${process.env.PHONIX_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data } = await res.json();
for (const call of data) console.log(call.employee_name, call.score, call.summary);import os, requests
r = requests.get(
"https://app.phonix.website/api/v1/leads",
params={"status": "new", "limit": 50},
headers={"Authorization": f"Bearer {os.environ['PHONIX_KEY']}"},
timeout=10,
)
r.raise_for_status()
for lead in r.json()["data"]:
print(lead["name"], lead["phone"], lead["fields"])curl -X PATCH https://app.phonix.website/api/v1/leads/LEAD_ID \
-H "Authorization: Bearer $PHONIX_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "qualified"}' Вебхуки
Phonix отправляет POST на адрес вашей CRM. Тело: {"id", "type", "created_at", "data"}, где data содержит объект в том же формате, что и API.
| Событие | Когда приходит |
|---|---|
| lead.created | Новый лид: от агента, бота, звонка менеджера, API или вручную |
| lead.updated | Изменились статус, поля или ответственный |
| call.completed | Звонок завершён, запись сохранена |
| call.analyzed | Разбор готов: балл, вердикты по пунктам, итог |
| conversation.created | Клиент начал новый диалог в одном из каналов |
| conversation.message | Новое сообщение клиента, бота или оператора |
| conversation.handoff | Диалог передан оператору |
{
"id": "6f0c3a52-8d1e-4b07-9a51-2c4f5e7d9b10",
"type": "lead.created",
"created_at": "2026-10-01T08:18:44Z",
"data": {
"id": "a1d9e0f4-3c2b-4f6a-8e7d-5b4c3a2f1e0d",
"object": "lead",
"name": "Михаил",
"phone": "79161234512",
"status": "new",
"source": "voice",
"fields": {
"request": "Кухня на заказ, угловая 3,2 × 2 м",
"address": "Ленинский проспект, 42",
"visit": "Суббота, с 10:00 до 12:00"
}
}
} Заголовки запроса
- Phonix-Event
- тип события, например call.analyzed
- Phonix-Delivery
- id доставки: по нему удобно отбрасывать повторы
- Phonix-Signature
- t=<unix>,v1=<hex>, где v1 = HMAC-SHA256(secret, "<t>.<тело>")
Проверка подписи
Считайте HMAC от сырого тела запроса до разбора JSON и сравнивайте за постоянное время. Метку времени старше 5 минут лучше отклонять.
import crypto from 'node:crypto';
// rawBody: тело запроса строкой, до JSON.parse
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
const given = String(parts.v1 || '');
return given.length === expected.length && crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}import hashlib, hmac, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
signed = parts["t"].encode() + b"." + raw_body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", "")) Повторы при ошибке
Если ваш сервер ответил не 2xx или не ответил за 10 секунд, Phonix повторит отправку. После 50 неудач подряд адрес отключается, причина видна в панели.
- #1 сразу
- #2 1 мин
- #3 5 мин
- #4 30 мин
- #5 2 ч
- #6 6 ч
- #7 12 ч
Ошибки
Ошибка всегда приходит в одном формате: машинный code, сообщение для разработчика и подробности, если они есть.
{
"error": {
"code": "bad_request",
"message": "Invalid body",
"details": [
{
"path": "phone",
"message": "Invalid phone number",
"code": "custom"
}
]
}
} | Статус | code | Когда |
|---|---|---|
| 400 | bad_request | тело или параметры не прошли проверку, в details список полей |
| 401 | unauthorized | нет ключа или ключ отозван |
| 403 | forbidden | у ключа нет права на запись |
| 404 | not_found | объекта нет или он принадлежит другой компании |
| 409 | conflict | такой объект уже есть, например звонок с тем же external_id |
| 429 | rate_limited | больше 600 запросов в минуту на ключ |
Справочник и вебхуки в панели