IT CITY CRM — API Documentation

Повна документація REST API для інтеграції з CRM-системою IT CITY

Base URL
https://crm.its.te.ua/api
Автентифікація
API Key (Bearer) або Session Cookie
Формат
JSON (Content-Type: application/json)
Версія
v5.11.0

⚡ Тестування API

Введи URL свого CRM (наприклад https://yourtenant.crm.its.te.ua), API-ключ і ендпойнт — отримай реальну відповідь сервера. Запит йде з твого браузера, ключ нікуди не зберігається крім твого браузера (localStorage).

Швидкий старт — Заявки
Контакти / Об'єкти / Обладнання
Чати
Фінанси / Звіти
Інше

🔐 Автентифікація

Два способи авторизації: API ключ (рекомендовано для інтеграцій) або Session Cookie (браузер).

KEY API ключі (Bearer Token) — Рекомендований спосіб для Postman, скриптів, інтеграцій

Як отримати

Налаштування → API ключі → Створити ключ (тільки ADMIN)

Використання

GET /api/tickets
Authorization: Bearer itc_a1b2c3d4e5f6789...
Content-Type: application/json

Параметри ключа

ПолеОпис
НазваДовільна назва (Postman, Integration, Monitoring...)
Термін дії7д / 30д / 90д / 1 рік / безстроковий

API ендпоінти для управління ключами

МетодURLОпис
GET/api/api-keysСписок активних ключів
POST/api/api-keysСтворити новий ключ
DEL/api/api-keys?id=NВідкликати ключ

⚠️ Ключ показується тільки при створенні. Зберігається як SHA-256 хеш.

Реєстрація, відновлення пароля та управління сесіями. Ендпоінти мають підвищений rate limiting.

POST /api/auth/register — Реєстрація нового користувача Без авторизації

Тіло запиту

{
  "name": "Іван Петренко",
  "email": "ivan@example.com",
  "password": "securePassword123",
  "role": "TECH"
}

Параметри

ПолеТипОпис
namestring requiredПовне ім'я користувача
emailstring requiredEmail адреса
passwordstring requiredПароль (мінімум 8 символів)
roleenumADMIN | MANAGER | TECH (за замовчуванням TECH)

Відповідь (201)

{
  "id": "clx1abc...",
  "name": "Іван Петренко",
  "email": "ivan@example.com",
  "role": "TECH"
}
Rate Limit: 5 запитів на 15 хвилин з однієї IP-адреси
POST /api/auth/forgot-password — Запит на скидання пароля Без авторизації

Тіло запиту

{
  "email": "ivan@example.com"
}

Відповідь (200)

{
  "message": "Якщо email існує, лист з інструкціями відправлено"
}
Примітка: Відповідь завжди 200, незалежно від існування email (захист від перебору)
POST /api/auth/reset-password — Скидання пароля за токеном Без авторизації

Тіло запиту

{
  "token": "reset-token-from-email",
  "password": "newSecurePassword456"
}

Відповідь (200)

{
  "message": "Пароль успішно змінено"
}
Rate Limit: 3 запити на 15 хвилин з однієї IP-адреси. Токен діє 1 годину.

📋 Заявки (Tickets)

CRUD-операції із заявками, масові дії, обладнання, фото та коментарі.

GET /api/tickets — Список заявок з фільтрацією та пагінацією Потрібна авторизація

Query-параметри

ПараметрТипОпис
statusstringФільтр за статусом: NEW, IN_PROGRESS, COMPLETED, CANCELLED
assigneeIdstringID виконавця
storeIdstringID торгової точки
qstringПошук за заголовком, описом, номером
pagenumberНомер сторінки (за замовчуванням 1)
sortFieldstringПоле сортування: createdAt, updatedAt, status, number
sortDirstringНапрямок: asc | desc

Відповідь (200)

{
  "tickets": [
    {
      "id": "clx1abc...",
      "number": 1042,
      "title": "Не працює принтер",
      "status": "NEW",
      "store": { "id": "...", "name": "Магазин #5" },
      "assignee": { "id": "...", "name": "Олег Коваль" },
      "createdAt": "2026-03-28T10:00:00.000Z"
    }
  ],
  "total": 156,
  "page": 1,
  "totalPages": 16
}
POST /api/tickets — Створення нової заявки Потрібна авторизація

Тіло запиту

{
  "title": "Заміна картриджа",
  "description": "Потрібно замінити картридж у принтері HP LaserJet",
  "storeId": "clx1store...",
  "assigneeId": "clx1user...",
  "priority": "HIGH",
  "categoryId": "clx1cat...",
  "scheduledAt": "2026-04-05T10:00:00.000Z",
  "scheduledEndAt": "2026-04-05T12:00:00.000Z",
  "isPlanned": true
}
ПолеТипОпис
titlestring requiredЗаголовок заявки
descriptionstringДетальний опис
storeIdstring requiredID торгової точки
assigneeIdstringID виконавця
priorityenumLOW | MEDIUM | HIGH | CRITICAL
categoryIdstringID категорії заявки
scheduledAtdatetimeДата та час запланованого виїзду (ISO 8601)
scheduledEndAtdatetimeДата та час завершення (ISO 8601)
isPlannedbooleanПозначити як плановий виїзд

Відповідь (201)

{
  "id": "clx1new...",
  "number": 1043,
  "title": "Заміна картриджа",
  "status": "NEW",
  "createdAt": "2026-03-28T12:00:00.000Z"
}
Telegram: Автоматичне сповіщення виконавцю при призначенні
PATCH /api/tickets/[id] — Оновлення заявки, зміна статусу, GPS Потрібна авторизація

Тіло запиту

{
  "status": "COMPLETED",
  "completionNote": "Картридж замінено",
  "gpsLat": 49.5535,
  "gpsLng": 25.5948
}
ПолеТипОпис
statusenumНовий статус заявки
completionNotestringПримітка при закритті
gpsLatnumberGPS широта (при закритті)
gpsLngnumberGPS довгота (при закритті)
titlestringОновлений заголовок
assigneeIdstringНовий виконавець
scheduledAtdatetimeДата та час запланованого виїзду (ISO 8601)
scheduledEndAtdatetimeДата та час завершення (ISO 8601)
Аудит: Всі зміни статусу записуються в журнал аудиту
State Machine: Зміна статусу валідується через state machine — дозволені лише певні переходи (наприклад, NEW → IN_PROGRESS → COMPLETED). Невалідний перехід поверне 400 Bad Request з описом дозволених переходів.
POST /api/tickets/bulk — Масові операції з заявками Потрібна авторизація

Тіло запиту

{
  "action": "assign",
  "ticketIds": ["clx1a...", "clx1b...", "clx1c..."],
  "assigneeId": "clx1user..."
}

// Або зміна статусу:
{
  "action": "status",
  "ticketIds": ["clx1a...", "clx1b..."],
  "status": "COMPLETED"
}

// Або видалення:
{
  "action": "delete",
  "ticketIds": ["clx1a...", "clx1b..."]
}
ПолеТипОпис
actionenum requiredassign | status | delete
ticketIdsstring[] requiredМасив ID заявок
assigneeIdstringID виконавця (для action=assign)
statusenumСтатус (для action=status)

Відповідь (200)

{
  "updated": 3,
  "message": "Успішно оновлено 3 заявки"
}
GET POST /api/tickets/[id]/equipment — Обладнання заявки Потрібна авторизація

GET — Список обладнання прив'язаного до заявки

GET /api/tickets/clx1abc.../equipment

POST — Прив'язати обладнання до заявки

{
  "equipmentId": "clx1eq...",
  "action": "install"
}

Відповідь (200)

[
  {
    "id": "clx1eq...",
    "name": "HP LaserJet Pro",
    "serialNumber": "VNB3K12345",
    "type": "PRINTER"
  }
]
GET POST /api/tickets/[id]/photos — Фото заявки Потрібна авторизація

POST — Завантаження фото (multipart/form-data)

Content-Type: multipart/form-data

photo: [binary file]
description: "Фото пошкодженого принтера"

Відповідь (201)

{
  "id": "clx1ph...",
  "url": "/uploads/tickets/clx1abc.../photo1.jpg",
  "description": "Фото пошкодженого принтера",
  "createdAt": "2026-03-28T12:30:00.000Z"
}
GET POST DEL /api/tickets/[id]/comments — Коментарі до заявки Потрібна авторизація

POST — Додавання коментаря

Підтримує application/json та multipart/form-data (з файлами).

{
  "text": "Замовив новий картридж, доставка завтра"
}

DELETE /api/tickets/[id]/comments/[commentId] — Видалення коментаря

Автор може видалити свій коментар, ADMIN — будь-який. Створює запис в журналі змін заявки.

PATCH /api/tickets/[id]/comments/[commentId] — Редагування коментаря

Тільки автор, зберігає попередні версії в editHistory.

Відповідь (201)

{
  "id": 42,
  "text": "Замовив новий картридж, доставка завтра",
  "author": { "id": 1, "name": "Олег Коваль" },
  "files": [],
  "createdAt": "2026-03-28T13:00:00.000Z"
}
GET /api/tickets/[id]/calendar — Завантаження .ics календарного файлу Потрібна авторизація

Опис

Повертає файл у форматі iCalendar (.ics) з подією VEVENT для запланованого виїзду. Файл містить нагадування VALARM за 1 день до події. Сумісний з Google Calendar, Apple Calendar та Outlook.

Відповідь (200)

Content-Type: text/calendar

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//IT CITY CRM//Tickets//UK
BEGIN:VEVENT
UID:ticket-clx1abc@crm.its.te.ua
DTSTART:20260405T100000Z
DTEND:20260405T120000Z
SUMMARY:Заявка #1043 — Заміна картриджа
DESCRIPTION:Магазин #5\nПріоритет: HIGH\nhttps://crm.its.te.ua/tickets/clx1abc
LOCATION:вул. Центральна, 15
BEGIN:VALARM
TRIGGER:-P1D
ACTION:DISPLAY
DESCRIPTION:Нагадування: завтра плановий виїзд — Заявка #1043
END:VALARM
END:VEVENT
END:VCALENDAR
Примітка: Якщо заявка не має запланованої дати (scheduledAt), повертається 404. Кнопка "Додати в Google Calendar" генерує URL з параметрами для calendar.google.com.

🖨️ Обладнання (Equipment)

Управління обладнанням, серійними номерами та переміщеннями між торговими точками.

GET /api/equipment — Список обладнання Потрібна авторизація

Query-параметри

ПараметрТипОпис
typestringТип: PRINTER, SCANNER, PC, MONITOR, OTHER
storeIdstringФільтр за торговою точкою
qstringПошук за назвою, серійним номером
statusstringACTIVE | REPAIR | DECOMMISSIONED
pagenumberНомер сторінки

Відповідь (200)

{
  "equipment": [
    {
      "id": "clx1eq...",
      "name": "HP LaserJet Pro M404dn",
      "type": "PRINTER",
      "serialNumber": "VNB3K12345",
      "status": "ACTIVE",
      "store": { "id": "...", "name": "Магазин #5" }
    }
  ],
  "total": 84,
  "page": 1
}
POST /api/equipment — Створення обладнання Потрібна авторизація

Тіло запиту

{
  "name": "HP LaserJet Pro M404dn",
  "type": "PRINTER",
  "serialNumber": "VNB3K12345",
  "storeId": "clx1store...",
  "notes": "Нове обладнання, гарантія до 2027"
}

Відповідь (201)

{
  "id": "clx1new...",
  "name": "HP LaserJet Pro M404dn",
  "type": "PRINTER",
  "serialNumber": "VNB3K12345",
  "status": "ACTIVE"
}
PATCH /api/equipment/[id] — Оновлення обладнання Потрібна авторизація

Тіло запиту

{
  "name": "HP LaserJet Pro M404dn (оновлено)",
  "serialNumber": "VNB3K12345-NEW",
  "status": "REPAIR",
  "notes": "Відправлено на ремонт"
}
POST /api/equipment/[id]/move — Переміщення обладнання Потрібна авторизація

Тіло запиту

{
  "toStoreId": "clx1store2...",
  "reason": "Переміщення на іншу точку за запитом клієнта"
}

Відповідь (200)

{
  "id": "clx1eq...",
  "store": { "id": "clx1store2...", "name": "Магазин #12" },
  "movement": {
    "id": "clx1mv...",
    "fromStore": "Магазин #5",
    "toStore": "Магазин #12",
    "movedAt": "2026-03-28T14:00:00.000Z",
    "movedBy": "Олег Коваль"
  }
}
Аудит: Всі переміщення фіксуються в історії обладнання

💰 Фінанси (Finance)

Грошовий потік, регулярні платежі, закриття місяця, виплати та категорії.

GET POST /api/cash-flow — Грошовий потік з розрахунком податків Потрібна авторизація

GET — Query-параметри

ПараметрТипОпис
monthnumberМісяць (1-12)
yearnumberРік
typestringINCOME | EXPENSE
categoryIdstringID категорії

POST — Створення запису

{
  "type": "INCOME",
  "amount": 15000,
  "description": "Оплата за обслуговування - Березень",
  "categoryId": "clx1cat...",
  "date": "2026-03-28",
  "organizationId": "clx1org..."
}

Відповідь (200)

{
  "id": "clx1cf...",
  "type": "INCOME",
  "amount": 15000,
  "tax": 750,
  "netAmount": 14250,
  "description": "Оплата за обслуговування - Березень",
  "date": "2026-03-28T00:00:00.000Z"
}
Податки: Автоматичний розрахунок ЄП (5%) при створенні запису типу INCOME
GET /api/cash-flow/summary — Зведена інформація за місяць та квартал Потрібна авторизація

Query-параметри

ПараметрТипОпис
monthnumber requiredМісяць (1-12)
yearnumber requiredРік

Відповідь (200)

{
  "month": {
    "income": 85000,
    "expense": 42000,
    "tax": 4250,
    "profit": 38750
  },
  "quarter": {
    "income": 240000,
    "expense": 118000,
    "tax": 12000,
    "profit": 110000
  }
}
GET POST /api/recurring-items — Регулярні платежі Потрібна авторизація

POST — Створення регулярного платежу

{
  "name": "Оренда офісу",
  "amount": 8000,
  "type": "EXPENSE",
  "frequency": "MONTHLY",
  "categoryId": "clx1cat...",
  "dayOfMonth": 5
}

Відповідь (200)

{
  "items": [
    {
      "id": "clx1ri...",
      "name": "Оренда офісу",
      "amount": 8000,
      "type": "EXPENSE",
      "frequency": "MONTHLY",
      "nextDate": "2026-04-05",
      "isActive": true
    }
  ]
}
GET POST /api/month-close — Закриття/відкриття місяця Потрібна авторизація

POST — Закрити або відкрити місяць

{
  "month": 3,
  "year": 2026,
  "action": "close"
}
ПолеТипОпис
monthnumber requiredМісяць (1-12)
yearnumber requiredРік
actionenum requiredclose | reopen

Відповідь (200)

{
  "month": 3,
  "year": 2026,
  "isClosed": true,
  "closedAt": "2026-04-01T00:00:00.000Z",
  "closedBy": "Адмін"
}
Увага: Закриття місяця блокує редагування фінансових записів за цей період. Тільки ADMIN може закривати/відкривати.
GET /api/month-close/preview — Попередній перегляд перед закриттям Потрібна авторизація

Query-параметри

ПараметрТипОпис
monthnumber requiredМісяць (1-12)
yearnumber requiredРік

Відповідь (200)

{
  "month": 3,
  "year": 2026,
  "recurringItems": [
    {
      "id": "clx1ri...",
      "name": "Оренда офісу",
      "amount": 8000,
      "type": "EXPENSE",
      "category": "Оренда"
    }
  ],
  "totals": {
    "income": 85000,
    "expense": 42000,
    "recurringExpense": 18000,
    "recurringIncome": 5000
  }
}
Примітка: Використовуйте цей ендпоінт для відображення чекбокс-списку рекурентних платежів перед закриттям місяця
POST /api/payment-categories/reorder — Зміна порядку категорій Потрібна авторизація

Тіло запиту

{
  "orderedIds": ["clx1cat1...", "clx1cat2...", "clx1cat3..."]
}
ПолеТипОпис
orderedIdsstring[] requiredМасив ID категорій у новому порядку

Відповідь (200)

{
  "success": true,
  "message": "Порядок категорій оновлено"
}
GET POST /api/payments — Виплати (зарплати, бонуси) Потрібна авторизація

POST — Створення виплати

{
  "userId": "clx1user...",
  "amount": 25000,
  "type": "SALARY",
  "month": 3,
  "year": 2026,
  "note": "Зарплата за березень"
}

Відповідь (201)

{
  "id": "clx1pay...",
  "userId": "clx1user...",
  "amount": 25000,
  "type": "SALARY",
  "createdAt": "2026-04-01T00:00:00.000Z"
}
Telegram: Автоматичне сповіщення працівнику про нарахування зарплати
GET POST /api/payment-categories — Категорії платежів Потрібна авторизація

POST — Створення категорії

{
  "name": "Витратні матеріали",
  "type": "EXPENSE",
  "parentId": null
}

GET — Відповідь (200)

{
  "categories": [
    {
      "id": "clx1cat...",
      "name": "Витратні матеріали",
      "type": "EXPENSE",
      "parentId": null,
      "children": [
        { "id": "clx1cat2...", "name": "Картриджі" },
        { "id": "clx1cat3...", "name": "Папір" }
      ]
    }
  ]
}

📊 Звіти (Reports)

Щомісячна статистика, деталізовані звіти та експорт у Excel.

GET /api/reports — Щомісячна статистика Потрібна авторизація

Query-параметри

ПараметрТипОпис
monthnumberМісяць (1-12)
yearnumberРік

Відповідь (200)

{
  "tickets": {
    "total": 156,
    "new": 12,
    "inProgress": 28,
    "completed": 110,
    "cancelled": 6
  },
  "technicians": [
    { "name": "Олег Коваль", "completed": 45, "avgTime": "2.3 год" }
  ],
  "finance": {
    "income": 85000,
    "expense": 42000,
    "profit": 43000
  }
}
GET /api/reports/detailed — Деталізовані звіти за період Потрібна авторизація

Query-параметри

ПараметрТипОпис
fromstring requiredПочаткова дата (YYYY-MM-DD)
tostring requiredКінцева дата (YYYY-MM-DD)
typeenum requiredТип звіту (див. нижче)

Типи звітів

ТипОпис
summaryЗагальна зведена інформація
taxesРозрахунок податків за період
salariesЗарплати та виплати
incomeДеталізація доходів
categoriesРозбивка за категоріями
contractorsЗвіт по підрядниках
monthlyПомісячна розбивка

Приклад запиту

GET /api/reports/detailed?from=2026-01-01&to=2026-03-31&type=summary

Відповідь (200)

{
  "period": { "from": "2026-01-01", "to": "2026-03-31" },
  "type": "summary",
  "data": {
    "totalIncome": 240000,
    "totalExpense": 118000,
    "totalTax": 12000,
    "netProfit": 110000,
    "ticketsCompleted": 312,
    "avgTicketTime": "2.1 год"
  }
}
GET /api/reports/detailed/export — Експорт звіту у Excel (.xlsx) Потрібна авторизація

Query-параметри

Ті самі параметри, що й для /api/reports/detailed

Відповідь

Бінарний файл application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

Content-Disposition: attachment; filename="report-2026-Q1.xlsx"
Формат: Excel з форматованими таблицями, автофільтрами та підсумковими рядками
POST /api/reports/telegram/test — Тестова відправка звіту в Telegram Потрібна авторизація

Тіло запиту

{
  "type": "monthly",
  "month": 3,
  "year": 2026
}
ПолеТипОпис
typeenum requiredТип звіту: monthly | weekly
monthnumberМісяць (для monthly)
yearnumberРік (для monthly)

Відповідь (200)

{
  "success": true,
  "message": "Тестовий звіт відправлено в Telegram"
}
Примітка: Надсилає звіт у тестовий Telegram-чат, налаштований в системних параметрах
GET /api/settings/reports — Налаштування розкладу звітів Потрібна авторизація

Відповідь (200)

{
  "weeklyReport": {
    "enabled": true,
    "dayOfWeek": 1,
    "time": "09:00",
    "chatIds": ["-100123456789"]
  },
  "monthlyReport": {
    "enabled": true,
    "dayOfMonth": 1,
    "time": "10:00",
    "chatIds": ["-100123456789"]
  }
}
Cron: Звіти генеруються автоматично за розкладом та надсилаються у визначені Telegram-чати

🔗 Інтеграції (Integrations)

Вебхуки, Telegram-бот, Google Maps та магічні посилання.

POST /api/webhooks — Вебхук від Eddy Helpdesk Верифікація підпису

Заголовки

ЗаголовокОпис
X-Webhook-SignatureHMAC-SHA256 підпис тіла запиту
Content-Typeapplication/json

Тіло запиту (від Eddy)

{
  "event": "ticket.created",
  "data": {
    "id": 12345,
    "subject": "Не працює каса",
    "description": "Каса не включається після оновлення",
    "priority": "high",
    "store": {
      "name": "Магазин Електроніка #7",
      "address": "вул. Центральна, 15"
    },
    "contact": {
      "name": "Марія Коваленко",
      "phone": "+380501234567"
    }
  }
}

Маппінг полів Eddy → CRM

EddyCRM
data.subjecttitle
data.descriptiondescription
data.prioritypriority (high→HIGH, medium→MEDIUM, low→LOW)
data.store.nameПошук store за назвою
data.contact.nameКонтактна особа в описі

Відповідь (200)

{
  "success": true,
  "ticketId": "clx1new...",
  "ticketNumber": 1044
}
Безпека: Запити без валідного підпису повертають 401 Unauthorized
BOT Telegram Bot — Автоматичні сповіщення

Типи сповіщень

ПодіяОтримувачОпис
Нова заявкаВиконавецьПовідомлення з деталями заявки та посиланням
Зміна статусуАвтор / МенеджерОповіщення при зміні статусу заявки
Нарахування ЗППрацівникПовідомлення про нараховану зарплату
Щотижневий звітМенеджериЗведення по заявках за тиждень (понеділок)
Щомісячний звітАдміниФінансове зведення за місяць (1 числа)

Формат повідомлення (приклад)

🔔 Нова заявка #1044

📋 Не працює каса
🏪 Магазин Електроніка #7
⚡ Пріоритет: Високий

🔗 https://crm.its.te.ua/tickets/clx1new...
LINK /api/magic-link/[token] — Магічне посилання для підрядників Без авторизації (токен)

Опис

Одноразове посилання для закриття заявки зовнішнім підрядником без облікового запису в CRM.

Приклад URL

https://crm.its.te.ua/magic/abc123def456...

Процес

КрокОпис
1Менеджер генерує Magic Link для заявки
2Посилання надсилається підряднику (email/Telegram)
3Підрядник відкриває посилання, бачить форму закриття
4Заповнює результат роботи та закриває заявку
Безпека: Токен одноразовий, діє 72 години. Після використання або закінчення терміну — деактивується.
MAP Google Maps Integration — Карти та маршрути

Можливості

ФункціяОпис
Геолокація точокКоординати магазинів зберігаються при створенні (geocoding API)
Карта заявокВідображення всіх відкритих заявок на карті з маркерами
Побудова маршрутуОптимальний маршрут між кількома точками (Directions API)
GPS при закриттіФіксація GPS-координат техніка при закритті заявки

👤 Користувачі (Users)

Управління обліковими записами, ролями та статусами користувачів.

DELETE /api/users/[id] — Видалення користувача (заблоковано) Потрібна авторизація

Відповідь (403)

{
  "error": "Видалення користувачів заборонено. Використовуйте деактивацію.",
  "hint": "PATCH /api/users/[id] з { \"isActive\": false }"
}
Безпека: Видалення користувачів заблоковано для збереження цілісності аудит-логу та історії заявок. Замість видалення використовуйте деактивацію через PATCH.

📚 Тестування (Quizzes)

Створення, призначення та проходження тестів для перевірки знань техніків.

GET POST /api/quizzes — Список тестів / Створення тесту Потрібна авторизація

GET — Список тестів

Для техніка: тільки обов'язкові + призначені. Для адміна: всі опубліковані.

POST — Створення тесту (ADMIN)

{
  "title": "Основи мереж",
  "description": "Базові знання мережевих технологій",
  "level": "BEGINNER",
  "category": "networks",
  "passingScore": 80,
  "timeLimitMin": 15,
  "isRequired": false,
  "questions": [
    {
      "text": "Який порт використовує HTTPS?",
      "type": "single",
      "options": ["80", "443", "8080", "22"],
      "correctAnswer": [1],
      "explanation": "HTTPS працює на порті 443"
    }
  ]
}
GET PATCH DEL /api/quizzes/[id] — Деталі / Редагування / Видалення тесту

GET — повертає тест з питаннями (для техніка без правильних відповідей).

PATCH — оновлення тесту та питань (ADMIN). DELETE — видалення (ADMIN).

POST /api/quizzes/[id]/attempt — Відправити відповіді на тест
{
  "answers": {
    "1": [1],
    "2": [0, 2],
    "3": [0]
  }
}

Повертає результат: score, passed, детальний розбір кожного питання з правильними відповідями.

POST /api/quizzes/[id]/assign — Призначити тест працівникам (ADMIN)
{
  "userIds": [4, 5, 6],
  "deadline": "2026-04-15"
}

Надсилає Telegram та in-app сповіщення кожному призначеному користувачу.

POST /api/quizzes/seed — Створити готові шаблони тестів (ADMIN)

Створює 6 шаблонів: Мережі, Принтери, Windows, Сервери, Безпека, Hardware (54 питання).

GET /api/quizzes/results — Зведена таблиця результатів (ADMIN)

Повертає матрицю: користувачі × тести з найкращими балами та кількістю спроб.

🔔 Сповіщення (Notifications)

In-app сповіщення з дзвіночком, звуком та polling кожні 30 секунд.

GET PATCH /api/notifications — Список сповіщень / Позначити прочитаним Потрібна авторизація

GET

Параметр ?unread=1 — тільки непрочитані. Повертає { notifications, unreadCount }.

PATCH — Позначити прочитаним

// Одне сповіщення
{ "id": 42 }
// Все прочитано
{ "markAll": true }

Типи сповіщень

ТипОпис
TICKET_CREATEDНова заявка (адмінам/менеджерам)
TICKET_ASSIGNEDПризначено заявку
STATUS_CHANGEDЗміна статусу заявки
TICKET_COMMENTНовий коментар
QUIZ_ASSIGNEDПризначено тест
SLA_WARNINGSLA наближається/прострочено

📢 Розсилки (Broadcast)

Масові розсилки через Telegram та Viber з фільтрацією аудиторії.

POST /api/broadcast — Створення розсилки Потрібна авторизація

Тіло запиту

{
  "name": "Акція березень",
  "message": "Шановні клієнти! Знижка 20% на обслуговування до кінця місяця.",
  "channel": "telegram",
  "filters": {
    "organizationId": "clx1org...",
    "tags": ["active"]
  }
}
ПолеТипОпис
namestring requiredНазва розсилки
messagestring requiredТекст повідомлення
channelenum requiredtelegram | viber
filtersobjectФільтри аудиторії (організація, теги)

Відповідь (201)

{
  "id": "clx1br...",
  "name": "Акція березень",
  "status": "DRAFT",
  "recipientCount": 45,
  "createdAt": "2026-04-01T10:00:00.000Z"
}
GET /api/broadcast — Список розсилок Потрібна авторизація

Відповідь (200)

{
  "broadcasts": [
    {
      "id": "clx1br...",
      "name": "Акція березень",
      "status": "SENT",
      "channel": "telegram",
      "recipientCount": 45,
      "sentCount": 42,
      "failedCount": 3,
      "createdAt": "2026-04-01T10:00:00.000Z",
      "sentAt": "2026-04-01T10:05:00.000Z"
    }
  ]
}
POST /api/broadcast/:id/send — Відправити розсилку Потрібна авторизація

Опис

Запускає відправку розсилки всім отримувачам. Статус змінюється на SENDING, потім на SENT після завершення.

Відповідь (200)

{
  "id": "clx1br...",
  "status": "SENDING",
  "recipientCount": 45,
  "message": "Розсилка запущена"
}
Увага: Розсилку можна відправити лише один раз. Після відправки статус змінюється на SENT.

🛒 Замовлення покупців (Orders)

Замовлення/комерційні пропозиції: автонумерація, перерахунок сум/ПДВ на сервері, magic-link для погодження клієнтом, породження рахунків. Усі запити потребують заголовка Authorization: Bearer YOUR_API_KEY.

GET /api/orders — Список замовлень Потрібна авторизація

Список замовлень (макс. 200, найновіші). Фільтри: status, storeId, trash=1. Додає fulfilledPct і paidPct.

Приклад — список

GET /api/orders?status=sent&storeId=3
Authorization: Bearer YOUR_API_KEY
POST /api/orders — Створення замовлення/КП Потрібна авторизація

Створити замовлення/КП. Автогенерує docNumber (PREFIX-РІК-NNNNN), продавця та початковий стан. 201.

Приклад — створення

POST /api/orders
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "contactId": 128,
  "storeId": 3,
  "items": [
    { "name": "IP-камера Hikvision", "qty": 4, "price": 2500 }
  ]
}
GET /api/orders/[id] — Одне замовлення Потрібна авторизація

Одне замовлення з точкою та організацією (404 якщо не знайдено).

PATCH /api/orders/[id] — Оновлення замовлення Потрібна авторизація

Оновити поля; перераховує subtotal/знижку/ПДВ/grandTotal на сервері.

DEL /api/orders/[id] — Видалення замовлення Потрібна авторизація

М'яке видалення в кошик; ?purge=1 — повне видалення (лише ADMIN).

POST /api/orders/[id]/send — Надсилання клієнту (magic-link) Потрібна авторизація

Згенерувати magic-link, статус 'sent', надіслати посилання клієнту на email.

POST /api/orders/[id]/close — Закриття замовлення Потрібна авторизація

Закрити: SUCCESS (→installed) або CANCELLED (→cancelled, потрібна причина).

POST /api/orders/[id]/spawn-invoice — Породження рахунку Потрібна авторизація

Створити чернетку рахунку з замовлення (копіює позиції, графік 7 днів). 201.

GET POST /api/orders/[id]/comments — Коментарі Потрібна авторизація

Коментарі (JSON або multipart з файлами); @-згадки та in-app сповіщення.

POST /api/orders/bulk — Масові дії Потрібна авторизація

Масові дії над ids[]: trash / restore / purge / status (purge — лише ADMIN).

📦 Склад (Warehouse)

Товари, залишки, склади, постачальники та складські документи (прибуткові, видаткові, інвентаризації). Кожен запит потребує Authorization: Bearer YOUR_API_KEY та відповідних прав модуля warehouse.

GET POST /api/warehouse/products — Товари Потрібна авторизація

GET: товари із залишками (totalStock/totalReserved). POST: створити товар.

Приклад — товари

GET /api/warehouse/products
Authorization: Bearer YOUR_API_KEY

Приклад — створення товару

POST /api/warehouse/products
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "name": "Комутатор TP-Link 8-port",
  "sku": "TL-SG108",
  "unit": "шт",
  "serialTracking": false
}
GET /api/warehouse/stocks — Залишки Потрібна авторизація

Залишки згруповані за товаром по всіх складах + розбивка по складах.

GET POST /api/warehouse/warehouses — Склади Потрібна авторизація

GET: список складів. POST: створити склад.

GET POST /api/warehouse/suppliers — Постачальники Потрібна авторизація

GET: постачальники (?trash=1). POST: створити постачальника.

GET PATCH DEL /api/warehouse/suppliers/[id] — Постачальник (деталі) Потрібна авторизація

Перегляд / оновлення / м'яке видалення постачальника.

GET POST /api/warehouse/supply — Прибуткові документи Потрібна авторизація

Прибуткові документи. GET: список (?trash=1). POST: чернетка прибуття.

GET PATCH POST DEL /api/warehouse/supply/[id] — Прибутковий документ (деталі) Потрібна авторизація

Деталі/редагування/проведення (POST збільшує залишки)/видалення документа.

GET POST /api/warehouse/expense — Видаткові документи Потрібна авторизація

Видаткові документи / списання / переміщення. GET: список. POST: чернетка.

GET POST /api/warehouse/stock-inventory — Інвентаризації Потрібна авторизація

Інвентаризації (ІНВ-РРРР-#####). POST: чернетка зі знімком залишків.

🏷️ Номенклатура (Nomenclature)

Каталог товарів (BasNomenclature): пошук, категорії, типи цін, ціни, залишки та історія цін постачальників. Дані BAS (1С) — лише для читання; локальні позиції можна створювати/редагувати. Потрібен Authorization: Bearer YOUR_API_KEY.

GET /api/nomenclature — Пошук каталогу Потрібна авторизація

Пошук каталогу: q, category, type, source (BAS|LOCAL), active, page, limit (≤200).

Приклад — пошук каталогу

GET /api/nomenclature?q=камера&source=BAS&limit=50
Authorization: Bearer YOUR_API_KEY
POST /api/nomenclature — Створення LOCAL позиції Потрібна авторизація

Створити LOCAL позицію (ADMIN/MANAGER).

GET /api/nomenclature/[id] — Одна позиція Потрібна авторизація

Одна позиція за числовим id (404 якщо немає).

PATCH /api/nomenclature/[id] — Оновлення позиції Потрібна авторизація

Оновити поля позиції (потрібне право equipment:edit).

DEL /api/nomenclature/[id] — Видалення позиції Потрібна авторизація

Видалити позицію (потрібне право equipment:delete).

GET /api/nomenclature/categories — Категорії Потрібна авторизація

Категорії (BasCategory) з лічильниками активних позицій.

GET /api/nomenclature/price-types — Типи цін Потрібна авторизація

Типи цін (BasPriceType).

GET /api/nomenclature/[id]/prices — Ціни позиції Потрібна авторизація

Ціни позиції з фільтрацією видимості за роллю.

PUT /api/nomenclature/[id]/prices/upsert — Оновлення/додавання ціни Потрібна авторизація

Оновити/додати ціну (priceTypeId + amount + currency; ADMIN/MANAGER).

GET /api/nomenclature/[id]/balances — Залишки позиції Потрібна авторизація

Залишки позиції: баланс компанії + по працівниках + разом.

GET /api/nomenclature/[id]/supplier-prices — Ціни постачальників Потрібна авторизація

Історія цін постачальників (last/avg/min/max, нормалізовано в UAH).

🧾 Рахунки (Invoices)

Рахунки на оплату: автонумерація ІНФ-РРРР-NNNNN, розрахунок сум/ПДВ, графік оплат, реєстрація платежів і генерація в 1С/BAS. Потрібен Authorization: Bearer YOUR_API_KEY та права модуля invoices.

GET /api/invoices — Список рахунків Потрібна авторизація

Список рахунків з фільтрами (status, customerOrgId, sellerOrgId, baseDoc...). Макс. 200.

Приклад — список

GET /api/invoices?status=SENT&customerOrgId=42
Authorization: Bearer YOUR_API_KEY
POST /api/invoices — Створення рахунку Потрібна авторизація

Створити рахунок (ІНФ-РРРР-NNNNN), рахує суми/ПДВ, графік 7 днів. Старт DRAFT.

Приклад — створення

POST /api/invoices
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "sellerOrgId": 1,
  "customerOrgId": 42,
  "items": [
    { "name": "Обслуговування СКД", "qty": 1, "price": 12000, "vatRate": 20 }
  ]
}
GET /api/invoices/[id] — Один рахунок Потрібна авторизація

Один рахунок з продавцем, клієнтом, договором і графіком оплат.

PATCH /api/invoices/[id] — Оновлення рахунку Потрібна авторизація

Оновити поля/позиції та статус (SENT/CANCELLED/PARTIAL_PAID/PAID).

DEL /api/invoices/[id] — Скасування рахунку Потрібна авторизація

М'яке скасування (→CANCELLED, фізично не видаляє).

POST /api/invoices/[id]/spawn-payment — Реєстрація платежу Потрібна авторизація

Зареєструвати вхідний платіж (CashFlowEntry), оновлює paidTotal і статус.

GET /api/invoices/[id]/related — Пов'язані документи Потрібна авторизація

Граф документів: джерельне замовлення + платежі CashFlow.

POST /api/invoices/bulk — Масові дії Потрібна авторизація

Масові дії: trash / restore / hardDelete (заблоковано якщо є оплати).

GET /api/invoices/tickets — Заявки для рахунку Потрібна авторизація

Виконані заявки (DONE) для orgId за період — джерело для рахунків.

POST /api/invoices/create-1c — Генерація в 1С/BAS Потрібна авторизація

Згенерувати СчетНаОплату в 1С/BAS з обраних заявок (OData).

📄 Акти виконаних робіт (Acts)

Акти виконаних робіт: автонумерація АКТ-РРРР-NNNNN, розрахунок сум/ПДВ, підпис через magic-link. Потрібен Authorization: Bearer YOUR_API_KEY та права модуля acts.

GET /api/acts — Список актів Потрібна авторизація

Список актів з фільтрами (status, customerOrgId, sellerOrgId, baseDoc, пошук). Макс. 200.

POST /api/acts — Створення акту Потрібна авторизація

Створити акт (АКТ-РРРР-NNNNN), рахує subtotal/vatTotal/grandTotal. Старт DRAFT.

Приклад — створення

POST /api/acts
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "sellerOrgId": 1,
  "customerOrgId": 42,
  "items": [
    { "name": "Монтаж відеоспостереження", "qty": 1, "price": 8000 }
  ]
}
GET /api/acts/[id] — Один акт Потрібна авторизація

Один акт з продавцем, клієнтом, контактом і договором.

PATCH /api/acts/[id] — Оновлення акту Потрібна авторизація

Оновити нотатки/позиції та статус DRAFT/SIGNED/CANCELLED.

DEL /api/acts/[id] — Видалення акту Потрібна авторизація

Видалити акт (400 якщо підписаний або на нього посилається eDoc).

POST /api/acts/bulk — Масові дії Потрібна авторизація

Масові дії: trash / restore / hardDelete.

POST /api/acts/[id]/send-magic-link — Надсилання на підпис Потрібна авторизація

Надіслати клієнту посилання на підпис, статус DRAFT→SENT.

📥 Замовлення постачальникам (Purchase Orders)

Замовлення постачальникам (ЗП): автонумерація ЗП-РРРР-NNNNN, породження прибуткових накладних і платежів, повернення, зв'язок з Новою Поштою. Потрібен Authorization: Bearer YOUR_API_KEY та права модуля purchase.

GET /api/purchase-orders — Список ЗП Потрібна авторизація

Список ЗП з фільтрами (status, supplierId, sellerOrgId, trash), з receivedPct/paidPct.

POST /api/purchase-orders — Створення ЗП Потрібна авторизація

Створити ЗП (ЗП-РРРР-NNNNN). Потрібні supplierId, warehouseId, sellerOrgId. Старт DRAFT.

Приклад — створення

POST /api/purchase-orders
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "supplierId": 7,
  "warehouseId": 1,
  "sellerOrgId": 1,
  "lines": [
    { "name": "Кабель UTP cat5e", "qty": 305, "price": 8.5 }
  ]
}
GET /api/purchase-orders/[id] — Деталі ЗП Потрібна авторизація

Деталі ЗП: постачальник, склад, рядки, графік оплат, прибуття, ТТН Нової Пошти.

PATCH /api/purchase-orders/[id] — Оновлення ЗП Потрібна авторизація

Оновити шапку/рядки, статуси (SENT/PARTIAL/RECEIVED/CLOSED/CANCELLED) або відновити.

DEL /api/purchase-orders/[id] — Видалення ЗП Потрібна авторизація

М'яке видалення; ?permanent=true — повне (ADMIN, якщо немає прибуттів).

POST /api/purchase-orders/[id]/spawn-supply — Породження прибуття Потрібна авторизація

Чернетка прибуткової накладної на непоставлені рядки.

POST /api/purchase-orders/[id]/spawn-payment — Платіж постачальнику Потрібна авторизація

Платіж постачальнику (CashFlowEntry EXPENSE); автозакриття ЗП при повній оплаті.

POST /api/purchase-orders/[id]/spawn-return — Повернення постачальнику Потрібна авторизація

Повернення постачальнику з підтверджених прибуттів.

POST /api/purchase-orders/[id]/lines/bulk — Масові операції з рядками Потрібна авторизація

Масові операції з рядками: зміна ціни/ПДВ, розподіл суми, редагування, видалення.

POST /api/purchase-orders/bulk — Масові дії Потрібна авторизація

Масові дії над ЗП: trash / restore / hardDelete.

GET /api/purchase-orders/[id]/related — Пов'язані документи Потрібна авторизація

Граф документів: джерельне замовлення клієнта + прибуткові накладні.

🤝 Контрагенти (Contractors)

Єдиний реєстр контрагентів — об'єднує контакти (фізосіб), організації та застарілі записи постачальників. Дедуплікація за телефоном/ЄДРПОУ. Потрібен Authorization: Bearer YOUR_API_KEY.

GET /api/contractors — Реєстр контрагентів Потрібна авторизація

Реєстр контрагентів. Фільтри: role=customer|supplier|all, type=person|org|all, search, trash=1.

Приклад — список

GET /api/contractors?role=customer&type=org
Authorization: Bearer YOUR_API_KEY
POST /api/contractors — Створення контрагента Потрібна авторизація

Створити контрагента (kind=PERSON|ORG). Дублікат телефону/ЄДРПОУ → 409 (обійти через force).

Приклад — створення

POST /api/contractors
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "kind": "ORG",
  "name": "ТОВ Приклад",
  "edrpou": "12345678",
  "isCustomer": true
}
POST /api/contractors/bulk — Масові дії Потрібна авторизація

Масові дії над [{kind,id}]: trash / restore / hardDelete (блокується при посиланнях).

POST /api/contractors/link-supplier — Зв'язати постачальника Потрібна авторизація

Зв'язати застарілого Supplier з Organization/Contact (або створити організацію).

POST /api/contractors/promote-chat — Промоція чат-контакту Потрібна авторизація

Перетворити чат-контакт (category='chat') у клієнта.

🚚 Нова Пошта (Nova Poshta)

Довідники та трекінг Нової Пошти через збережений API-ключ орендаря: автодоповнення міст і відділень, статус доставки за ТТН, список останніх відправлень. Потрібен Authorization: Bearer YOUR_API_KEY та право warehouse:view.

GET /api/nova-poshta/cities — Пошук міст Потрібна авторизація

Пошук міст за запитом (?q=Терн, мін. 2 символи) для автодоповнення.

GET /api/nova-poshta/warehouses — Відділення Потрібна авторизація

Відділення для обраного міста (?cityRef=...).

GET /api/nova-poshta/track/[ttn] — Трекінг ТТН Потрібна авторизація

Статус доставки за ТТН (кешується, лог подій при зміні статусу).

Приклад — трекінг ТТН

GET /api/nova-poshta/track/20450012345678
Authorization: Bearer YOUR_API_KEY
GET /api/nova-poshta/list — Останні відправлення Потрібна авторизація

Останні відправлення з акаунта НП (?days=90, 1–180).

🗺️ Плани монтажу (Site Plans): внутрішній візуальний редактор планів монтажу для дизайнерів і монтажників. Ендпоінти приймають сесію або API-ключ, але це не стабільний інтеграційний контракт (внутрішній JSON редактора — items/pages/cables) — не входить у публічний API інтеграцій.
🛰️ RMM (агенти): внутрішнє керування парком ПК і протокол агента ITCityAgent (керується з /rmm UI). Моніторингові дані доступні лише всередині системи, а операційні (деструктивні) дії над агентами — не інтеграційна поверхня. Не входить у публічний API інтеграцій.

🔧 Утиліти (Utilities)

Import/Export, шаблони заявок, планове ТО, підписки та логування помилок.

POST /api/import — CSV імпорт (контакти, обладнання, організації) Потрібна авторизація

Опис

Імпорт даних з CSV-файлу. Підтримує контакти, обладнання та організації. Формат: multipart/form-data.

Тіло запиту (multipart/form-data)

Content-Type: multipart/form-data

file: [CSV file]
type: "contacts"  // contacts | equipment | organizations
ПолеТипОпис
filefile requiredCSV-файл з даними
typeenum requiredcontacts | equipment | organizations

Відповідь (200)

{
  "imported": 42,
  "skipped": 3,
  "errors": [
    { "row": 5, "error": "Дублікат email" }
  ]
}
GET /api/export?type=contacts&format=csv — CSV експорт Потрібна авторизація

Query-параметри

ПараметрТипОпис
typeenum requiredcontacts | equipment | organizations
formatenumcsv (за замовчуванням)

Відповідь

Бінарний файл text/csv

Content-Disposition: attachment; filename="contacts-2026-04-01.csv"
GET /api/ticket-templates — Список шаблонів заявок Потрібна авторизація

Відповідь (200)

{
  "templates": [
    {
      "id": "clx1tmpl...",
      "name": "Заміна картриджа",
      "title": "Заміна картриджа — {printer}",
      "description": "Потрібна заміна картриджа",
      "priority": "MEDIUM",
      "categoryId": "clx1cat..."
    }
  ]
}
POST /api/ticket-templates — Створення шаблону заявки Потрібна авторизація

Тіло запиту

{
  "name": "Заміна картриджа",
  "title": "Заміна картриджа — {printer}",
  "description": "Потрібна заміна картриджа в принтері",
  "priority": "MEDIUM",
  "categoryId": "clx1cat..."
}

Відповідь (201)

{
  "id": "clx1tmpl...",
  "name": "Заміна картриджа",
  "createdAt": "2026-04-01T10:00:00.000Z"
}
GET /api/planned-maintenance — Список планового ТО Потрібна авторизація

Відповідь (200)

{
  "items": [
    {
      "id": "clx1pm...",
      "name": "Щомісячна перевірка принтерів",
      "frequency": "MONTHLY",
      "templateId": "clx1tmpl...",
      "storeId": "clx1store...",
      "nextRunAt": "2026-05-01T09:00:00.000Z",
      "isActive": true
    }
  ]
}
POST /api/planned-maintenance — Створення планового ТО Потрібна авторизація

Тіло запиту

{
  "name": "Щомісячна перевірка принтерів",
  "frequency": "MONTHLY",
  "dayOfMonth": 1,
  "templateId": "clx1tmpl...",
  "storeId": "clx1store...",
  "assigneeId": "clx1user..."
}
ПолеТипОпис
namestring requiredНазва планового ТО
frequencyenum requiredDAILY | WEEKLY | MONTHLY | QUARTERLY
templateIdstringID шаблону заявки
storeIdstringID об'єкта
assigneeIdstringID виконавця

Відповідь (201)

{
  "id": "clx1pm...",
  "name": "Щомісячна перевірка принтерів",
  "nextRunAt": "2026-05-01T09:00:00.000Z"
}
Автоматизація: Cron-задача автоматично створює заявки за розкладом на основі шаблону
POST /api/subscription/pay — Створення платежу (LiqPay/WayForPay) Потрібна авторизація

Тіло запиту

{
  "provider": "liqpay",
  "plan": "professional",
  "period": "monthly"
}
ПолеТипОпис
providerenum requiredliqpay | wayforpay
planenum requiredstarter | professional | enterprise
periodenummonthly | yearly

Відповідь (200)

{
  "paymentUrl": "https://www.liqpay.ua/checkout/...",
  "orderId": "ord_abc123"
}
POST /api/error-log — Клієнтське логування помилок Потрібна авторизація

Тіло запиту

{
  "message": "TypeError: Cannot read property 'id' of undefined",
  "stack": "at TicketList.render (tickets.js:42:15)...",
  "url": "/tickets",
  "userAgent": "Mozilla/5.0..."
}
ПолеТипОпис
messagestring requiredТекст помилки
stackstringStack trace
urlstringURL сторінки де виникла помилка
userAgentstringUser Agent браузера

Відповідь (201)

{
  "id": "clx1err...",
  "message": "Помилку зафіксовано"
}
Моніторинг: Помилки зберігаються в системному логу та доступні в розділі Налаштування

🔧 Система (System)

Службові ендпоінти для моніторингу стану системи.

GET /api/health — Перевірка стану системи Без авторизації

Відповідь (200)

{
  "status": "ok",
  "version": "4.0.0",
  "uptime": 1234567,
  "database": "connected",
  "timestamp": "2026-04-01T12:00:00.000Z"
}
Моніторинг: Використовується для uptime-моніторингу та health checks. Повертає 503 якщо з'єднання з базою даних відсутнє.

📖 Гайд з інтеграції

Покрокові інструкції для підключення зовнішніх систем до IT CITY CRM.

1. Автентифікація API

  1. Авторизуйтесь через POST /api/auth/callback/credentials
  2. Отримайте session cookie (next-auth.session-token)
  3. Передавайте cookie в кожному запиті
  4. Або використовуйте Bearer-токен у заголовку Authorization
// Приклад з Bearer токеном
fetch('https://crm.its.te.ua/api/tickets', {
  headers: {
    'Authorization': 'Bearer your-session-token',
    'Content-Type': 'application/json'
  }
})

2. Налаштування вебхуку

  1. Отримайте секретний ключ від адміністратора CRM
  2. Налаштуйте URL вебхуку: https://crm.its.te.ua/api/webhooks
  3. Підписуйте тіло запиту HMAC-SHA256
  4. Надсилайте підпис у заголовку X-Webhook-Signature
// Генерація підпису
const crypto = require('crypto');
const signature = crypto
  .createHmac('sha256', WEBHOOK_SECRET)
  .update(JSON.stringify(body))
  .digest('hex');

3. Формат вебхук-payload

  1. Використовуйте Content-Type: application/json
  2. Обов'язкові поля: event, data
  3. Підтримувані події: ticket.created, ticket.updated
  4. Відповідь 200 = успішно оброблено
{
  "event": "ticket.created",
  "data": {
    "id": 12345,
    "subject": "Тема заявки",
    "description": "Опис проблеми",
    "priority": "high",
    "store": { "name": "..." },
    "contact": { "name": "...", "phone": "..." }
  }
}

4. Rate Limits

  • Загальні ендпоінти: 100 запитів / хвилину
  • Auth ендпоінти: 5 запитів / 15 хвилин
  • Webhooks: 30 запитів / хвилину
  • Експорт: 5 запитів / хвилину

При перевищенні ліміту повертається статус 429 Too Many Requests з заголовком Retry-After.

// Відповідь при перевищенні ліміту
HTTP/1.1 429 Too Many Requests
Retry-After: 60

{
  "error": "Too many requests",
  "retryAfter": 60
}
Підтримка: З питань інтеграції звертайтесь до адміністратора CRM. Для тестування використовуйте staging-середовище.

💬 Chat Inbox API (v5.0)

Омніканальний чат з Telegram та Viber ботами, AI-агентом, базою знань, автопризначенням та SLA.

POST /api/chat/telegram Telegram webhook Public

Приймає повідомлення від Telegram Bot API. Обробляє текст, фото, відео, файли, контакт (request_contact), callback_query (рейтинг).

Логіка

Створює/знаходить ChatSession → зберігає повідомлення → ідентифікує клієнта → Zabbix-перевірка → AI-відповідь (якщо немає оператора) → автопризначення → сповіщення.

POST /api/chat/viber Viber webhook Public

Приймає повідомлення від Viber Bot. Повна паритетність з Telegram: кнопки (Viber Keyboard), рейтинг, Zabbix, AI.

GET /api/chat/sessions Список заявок чату Auth

Query параметри

statusstringФільтр статусу: _all_open, open, closed, deleted або кастомний ID
contactIdnumberФільтр по контакту
storeIdnumberФільтр по об'єкту
operatorIdnumberФільтр по оператору

Відповідь

Масив ChatSession з вкладеними contact, store, operator, останнє повідомлення, _count.messages. Плюс об'єкт counts з кількістю по кожному статусу.

GET /api/chat/sessions/:id Деталі заявки + повідомлення Auth

Повна інформація: всі повідомлення з replyTo, контакт (customFields, stores), оператор, канал, рейтинг.

PATCH /api/chat/sessions/:id Оновлення заявки Auth

Body параметри

statusstringНовий статус. При closed — надсилає запит рейтингу в Telegram/Viber
subjectstringТема заявки
operatorIdnumber|nullПризначити/зняти оператора
contactIdnumberПрив'язати контакт
storeIdnumberПрив'язати об'єкт
POST /api/chat/sessions/:id/message Відправка повідомлення Auth

FormData: text, file (attachment), isComment (внутрішній коментар), replyToId (цитування).

Коментарі не надсилаються клієнту. Звичайні повідомлення надсилаються через Telegram/Viber API.

GET /api/chat/stats Статистика чатів Auth

KPI: всього заявок, закрито, середній час відповіді, середній рейтинг. Графіки по статусах, каналах, операторах. Список відгуків з фільтрацією.

Query

fromdateПочаток періоду (ISO)
todateКінець періоду (ISO)
GET /api/chat/search Пошук: база знань, шаблони, непрочитані Auth

Query параметри

typestringkb — пошук статей, templates — шаблони відповідей, unread — кількість непрочитаних
qstringРядок пошуку (для type=kb)
GET /api/chat/sla-check Перевірка SLA (cron) Cron

Авторизація через x-cron-secret header. Знаходить заявки де останнє повідомлення від клієнта старше SLA, надсилає сповіщення через Telegram та in-app.

📡 Zabbix API

Інтеграція з Zabbix для моніторингу мережевого обладнання на об'єктах.

GET /api/zabbix Статус хоста / проблеми / звіт Auth

Query параметри

actionstringstatus — статус хоста, equipment-report — звіт обладнання
storeIdnumberID об'єкта (для action=status)

Повертає: проблеми (severity: High), inventory роутера (модель, прошивка, S/N), тривалість простою.

📚 База знань API

CRUD статей бази знань з публічним доступом через окремий сервер (порт 3099).

GET /api/knowledge Список статей Auth

Повертає всі статті з title, content, tags, isPublic, slug. Фільтрація по тегах та пошук по заголовку.

POST /api/knowledge Створення статті Auth
titlestringrequired Заголовок
contentstringHTML-контент (rich text)
tagsstring[]Теги для категоризації
isPublicbooleanПублічна доступність (через kb-server)
GET /kb Публічний список статей Public

Окремий сервер (порт 3099). Список публічних статей з пошуком та фільтрацією по тегах. Без авторизації.

GET /kb/:slug Публічна стаття Public

HTML-сторінка статті з повним контентом. Slug генерується транслітерацією з кирилиці.