Перейти к содержанию

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. Отдельный пользователь: вход интеграции разлогинивает человека с тем же логином, и наоборот.