Перейти до змісту

API ERPJS

API (інтерфейс програмування застосунків) — набір інструментів для автоматизації роботи із системою ERPJS. Дозволяє створювати, читати, оновлювати та видаляти записи в будь-якому реєстрі, виконувати звіти, працювати з файлами та отримувати оновлення в реальному часі через WebSocket.

Адреса

Усі шляхи нижче відлічуються від адреси вашої системи — тієї, за якою ви відкриваєте ERPJS у браузері (вигляд https://s.erpjs.biz/ваша-система). Окремого префікса на кшталт /v1 немає.

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

Отримання токена

Для роботи з API потрібен JWT-токен. Його видає вхід у систему:

curl -X POST https://s.erpjs.biz/ваша-система/public/login \
     -H "Content-Type: application/json" \
     -d '{"login": "your_login", "password": "your_password"}'
Відповідь містить поле jwt — це і є токен для подальших запитів. Компанію в запиті не передають: сервер визначає її сам і записує в токен. Токен діє 8 годин.

Замість пароля можна входити MCP-токеном користувача (його створює пункт «Згенерувати MCP-токен» у картці користувача): POST /public/mcp-login з тілом {"token": "<MCP-токен>"} повертає такий самий jwt.

Кожен вхід завершує попередні сесії цього користувача. Інтеграція й людина під одним логіном вибивають одне одного — заведіть інтеграції окремого користувача. «Токен API» з кабінету erpjs.biz — для іншого сервісу, до /records/* системи він не підходить.

Передача токена

Токен передається в заголовку HTTP: Authorization: Bearer <токен>. Cookie сервер для перевірки токена не читає.

Приклад

export TOKEN="<ваш_токен>"
export BASE_URL="https://s.erpjs.biz/ваша-система"

curl -X POST $BASE_URL/records/list \
     -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"datadef": "Contacts", "query": {"limit": 10}}'

Робота з записами

Всі операції з записами виконуються через POST-запити до ендпоінтів /records/*.

Список записів

POST /records/list — отримати записи з реєстру з фільтрацією, сортуванням та пагінацією.

{
  "datadef": "Invoices",
  "query": {
    "where": { "fOKFlag": 1 },
    "order": [["fInvDate", "DESC"]],
    "limit": 50,
    "offset": 0,
    "search": "пошуковий текст"
  }
}

Відповідь — масив записів (без загальної кількості). У query допустимі лише ключі where, order, limit, offset, search. Понад 10 000 записів за один запит сервер не віддає — відповідь 400; беріть порціями через limit і offset.

POST /records/sqlList — розширений список з вибором конкретних полів та групуванням (query.groupBy). Перелік полів fields обов'язковий.

{
  "datadef": "Invoices",
  "fields": ["fSerNr", "fCustCode", "fSum4", "fInvDate"],
  "query": {
    "where": { "fOKFlag": 1, "fInvDate": { "$gte": "2026-01-01" } },
    "order": [["fInvDate", "DESC"]],
    "limit": 100,
    "offset": 0,
    "search": { "search": "Клієнт", "column": "fCustCode" }
  }
}

Відповідь: {"res": [...], "qty": "1234"} — масив записів та загальна кількість (qty приходить рядком).

Умову where задають об'єктом: значення порівнюються як є, оператори — з $ ($in, $gte, $like тощо); голі in, gt — помилка 400. Рядок SQL сервер поки теж приймає, але це застаріла форма: її можуть вимкнути, і вона має починатися зі слова WHERE.

Перегляд запису

POST /records/show — отримати повні дані запису, включаючи матриці, файли та зв'язки.

{
  "datadef": "Invoices",
  "id": 123
}

Відповідь містить: - Всі поля запису - кожну матрицю — окремим ключем зі своїм ім'ям, наприклад "InvoicesMatrix": {"headers": [...], "payload": [...]} (рядки товарів у рахунку-фактурі) - __files — кількість прикріплених файлів - __links — кількість зв'язаних документів - __lock — є, лише якщо запис заблокований: true — вашим блокуванням, логін — чужим - __lastUpdated — час останнього оновлення - а також __permissions (права на запис і поля) та __revision

Значення за замовчуванням

POST /records/defaults — отримати значення за замовчуванням для нового запису.

{
  "datadef": "Invoices"
}

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

POST /records/create — створити новий запис. Матриці передаються в тому ж запиті.

{
  "datadef": "Contacts",
  "data": {
    "fCode": "C-001",
    "fName": "Нова компанія",
    "fCUType": 1,
    "fPhone": "+380501234567"
  }
}

Приклад створення запису з матрицею (поля рядків матриці теж починаються з f):

{
  "datadef": "Invoices",
  "data": {
    "fCustCode": "C-001",
    "fInvDate": "2026-03-28",
    "fCurncyCode": "UAH",
    "InvoicesMatrix": {
      "payload": [
        {
          "fArtCode": "ITEM-001",
          "fQuant": 5,
          "fPrice": 100
        }
      ]
    }
  }
}

Оновлення запису

POST /records/update — оновити існуючий запис.

{
  "datadef": "Contacts",
  "id": 123,
  "data": {
    "fPhone": "+380509876543"
  }
}

Спочатку заблокуйте запис. update приймає лише запис, який ви відкрили на редагування викликом setLock (див. «Блокування записів»); без блокування відповідь — 423 «запис не відкрито для редагування», під чужим блокуванням — теж 423.

Надсилайте лише ті поля, які міняєте. Поле, якого немає в data, система вважає незайманим і зберігає таким, яким воно записане в документі; матриця, якої немає в data, теж не зачіпається. Надіслане поле пишеться як є і може затерти зміну, яку хтось зробив між вашим читанням і записом. Надіслана матриця замінює попередню цілком.

Дати

Дата з часом приходить у відповіді records/show з міткою Z (наприклад, 2026-09-15T07:05:00Z). Якщо ви надсилаєте її назад без змін, система впізнає незмінене значення і зберігає його як було (так ядро працює з 26.09.2026). Зсув можливий, лише якщо значення встиг змінити хтось інший між вашим читанням і записом, — тож головне правило те саме: не надсилайте дату, яку не міняли.

MCP-конектор ERPJS (інструмент update_record) теж впізнає дату, яку ви прочитали й надсилаєте назад без змін; у режимі applyWactions: false тіло йде в систему дослівно.

Нове значення:

  • у формі відповіді (2026-09-15T07:05:00Z) читається як справжній момент часу — для Києва це 10:05;
  • з явним поясом: 2026-09-16T08:45:00+03:00 запишеться як 08:45 за Києвом;
  • у форматі ДД/ММ/РРРР ("17/09/2026") або РРРР-ММ-ДД — як календарний день без зсуву; у поля «дата з часом» час стане 00:00. Час задають так: ДД/ММ/РРРР ГГ:хх або РРРР-ММ-ДД ГГ:хх:сс — це місцевий час сервера.

Поля «дата без часу» (ДД/ММ/РРРР у вікні, у відповіді show — теж ДД/ММ/РРРР) зсув не зачіпає.

Видалення запису

POST /records/delete — видалити запис.

{
  "datadef": "Contacts",
  "id": 123
}

Увага: запис з прикріпленими файлами не може бути видалений. Спочатку видаліть файли (softDeleteAttachment).


Метадані та модель даних

POST /system/model — отримати структуру (схему) реєстру: список полів, типи, валідації.

{
  "datadef": "Invoices"
}

POST /system/meta — отримати метадані запису: __lock, __files, __links, __actions, __lastUpdated, __revision, __permissions.

{
  "datadef": "Invoices",
  "id": 123
}

Звіти

POST /reports/<Звіт>/<вид> — виконати звіт з параметрами. Вид у більшості звітів — simple (наприклад, /reports/SalesReport/simple).

{
  "fFrom": "2026-01-01",
  "fTo": "2026-03-31",
  "fCustCode": "C-001",
  "_meta": {
    "htmlFast": true
  }
}

Параметр _meta задає спосіб відповіді: - htmlFast: true — відповідь одразу HTML-рядком; разом із getContext: true — дані звіту в JSON; - без htmlFast відповідь — лише ключ {key}: результат приходить подіями WebSocket, а файли забирають через GET /system/download-report; - disableHtml: true, disableXlsx: true — пропустити збирання HTML чи Excel-файлу в такому повному звіті.

Параметри звіту сервер перевіряє так само, як вікно звіту: період, у якому початок пізніше за кінець, код, якого немає в довіднику, номер документа не числом. Тоді звіт не будується, а відповідь — помилка валідації з кодом 400, ім'я поля — у data.field.


Файли

Завантаження файлу (upload)

POST /system/upload — завантажити файл і прикріпити до запису. Використовуйте multipart/form-data.

Поля форми: - file — файл - data — JSON з параметрами: Register, RecordId, FileRealName, FileSize, CHECKSUM (sha256 у hex)

Потрібне право на реєстр запису; розмір файлу — до 10 МБ.

Скачування файлу (download)

GET /system/download/<uuid> — скачати файл за його UUID.

Видалення файлу

POST /system/softDeleteAttachment — позначити файл як видалений. Тіло: {"datadef": "Attachments", "id": <id файлу>}; потрібне право редагування запису, до якого файл прикріплено.


Блокування записів

Система блокувань запобігає одночасному редагуванню запису кількома користувачами. Для records/update блокування обов'язкове.

  • POST /system/setLock — заблокувати запис для редагування
  • POST /system/checkLock — перевірити чи запис заблокований та ким
  • POST /system/removeLock — зняти блокування
  • GET /system/lockList — список усіх активних блокувань

Блокування живе 5 хвилин. Повторний setLock того самого користувача продовжує його ще на 5 хвилин — так робить вікно редагування (кожні 10 секунд). Якщо робота з записом триває довше, повторюйте setLock; не зняте вчасно блокування (інтеграція впала, вкладку закрили) минає само.


Права доступу

У тілі передається перелік імен — без нього відповідь 400.

  • POST /system/getPermissionsRegisters {"registers": [...]} — права на реєстри (list, read, create, edit, remove та ін.)
  • POST /system/getPermissionsModules {"modules": [...]} — права на модулі
  • POST /system/getPermissionsReports {"reports": [...]} — права на звіти
  • POST /system/getPermissionsMaintenances {"maintenances": [...]} — права на процедури обслуговування

WebSocket (реальний час)

ERPJS підтримує WebSocket-з'єднання через Socket.IO для отримання оновлень у реальному часі.

Підключення: Socket.IO за шляхом <адреса системи>/socket.io, токен — у рукостисканні: auth: {token: "<токен>"}.

Події від сервера: - system_version — версія сервера (при підключенні) - push:<login> — непрочитані сповіщення користувача (відповідь на :live:) - update-tasks — оновлення списку задач

Події від клієнта: - :live: — підтвердження активності й запит непрочитаних сповіщень - push:success — підтвердження отримання сповіщень (масив їхніх id) - get:activeUsers — запит списку активних користувачів (відповідь — через callback)


Процедури та обслуговування

POST /maintenances/<назва>/<задача> — виконати процедуру обслуговування (імпорт, експорт, масові операції); у більшості служб задача — first. Сервер перевіряє права ролі на службу.

POST /custom/<назва> — виконати серверну процедуру; маршрутами стають лише процедури, оголошені в системі.


Публічні ендпоінти (без токена)

Деякі ендпоінти доступні без автентифікації:

  • POST /public/login — вхід у систему
  • POST /public/mcp-login — вхід MCP-токеном
  • GET /public/qrDownloadFiles — завантаження файлів за QR-кодом
  • /openserver/<маршрут> (GET або POST) — відкриті API-ендпоінти

На все під /public і /openserver, включно із входом, діє обмеження частоти: 10 запитів за 30 секунд з однієї IP на один шлях, далі — відповідь 429.


Коди відповідей

Код Опис
200 Успішний запит
400 Помилка валідації (деталі в тілі відповіді: message, data)
401 Невалідний або відсутній токен, сесію замінено новим входом
403 Недостатньо прав доступу
404 Реєстр або запис не знайдено
423 Запис не заблоковано вами (немає setLock) або його тримає інший
429 Перевищено обмеження частоти запитів
500 Внутрішня помилка сервера

Поради з інтеграції

  1. Пагінація: використовуйте limit та offset для великих обсягів даних. Ендпоінт sqlList повертає qty — загальну кількість записів; list віддає не більше 10 000 записів за запит.

  2. Матриці: при створенні або оновленні документа з товарами (рахунок-фактура, замовлення) передавайте матрицю в полі з відповідною назвою (наприклад, InvoicesMatrix) у вигляді {"payload": [...]}.

  3. Валідація: сервер виконує бізнес-логіку валідації (recordCheck). Помилки валідації повертаються з кодом 400; ім'я поля з помилкою — у data.field.

  4. Блокування: перед оновленням запису встановіть блокування (setLock) — без нього update відповість 423, — а після зніміть його (removeLock).

  5. Транзакції: створення та оновлення записів виконуються в транзакціях. При помилці всі зміни в базі відкатуються автоматично.

  6. Окремий користувач: вхід інтеграції розлогінює людину з тим самим логіном, і навпаки.