Перейти к содержимому

Внешние интеграции

Руководство для разработчиков и интеграторов: как подключать ERP, 1C, Service Desk, BI и другие системы к Portal.

Старт разработки и карта разделов: Разработчикам. Практические гайды: узлы, списки.

См. также: REST API, кейсы кода, OpenAPI.

Свои маршруты вида /api/v1/my-erp/sync пакет не регистрирует. Платформа публикует фиксированный REST (/api/v1/*) и одну точку для пользовательской логики: POST /api/v1/web-services/call/{id} — пакет .portalapi. {id} берётся из manifest.json (vendor.name). Тело запроса — JSON, ответ — JSON в конверте { success, data }.

Вызов идёт от вошедшего пользователя. Списки внутри ручки читаются с его ACL. Лимит ожидания — query timeout в секундах (по умолчанию 30, максимум 600). Если время вышло, ответ 408 и error.code = TIMEOUT, без HTTP 500.

Внешняя система ──JWT + CRUD──► /api/v1 REST API
Внешняя система / WebPart ──JWT + JSON──► POST /api/v1/web-services/call/{id}
WebPart UI ──invoke/action──► /api/v1/webparts/invoke/{key}/…
Event Receiver / Timer Job ──HTTP из C#──► внешняя система

Важно: /api/v1/routes — разрешение URL-адресов страниц для браузера, а не API для интеграций.


Путь 1. Внешняя система вызывает Portal (основной сценарий)

Заголовок раздела «Путь 1. Внешняя система вызывает Portal (основной сценарий)»

Внешняя система — клиент встроенного REST API.

  1. Аутентификация — сервисная учётная запись, POST /api/v1/auth/login → JWT (аутентификация)
  2. Обнаружение ресурсов — GET /api/v1/nodes, GET /api/v1/lists/{id}/fields
  3. Чтение/запись данных — GET/POST/PATCH /api/v1/lists/{listId}/items
  4. Права — при необходимости GET/POST /api/v1/permissions (права)
  • Фильтрация — по internal_name поля (inn, status, …)
  • Запись — по UUID полей из GET .../fields (кешировать)

Пример (ERP → Portal, кейс 10):

GET /api/v1/lists/{listId}/fields
Authorization: Bearer …
GET /api/v1/lists/{listId}/items?filter={"logic":"and","conditions":[{"column":"inn","operator":"eq","value":"7707083893"}]}&limit=1
POST /api/v1/lists/{listId}/items
Content-Type: application/json
{
"fieldValues": {
"uuid-title": "ООО Ромашка",
"uuid-inn": "7707083893",
"uuid-status": "Активен"
}
}
PATCH /api/v1/lists/{listId}/items/42
Content-Type: application/json
{
"fieldValues": {
"uuid-status": "Архив"
}
}
МатериалОписание
REST APIОбзор всех маршрутов
OpenAPIПолная спецификация
Значения полейФормат fieldValues
PortalApiClient.csПример HTTP-клиента на C#

Путь 2. Portal вызывает внешнюю систему (исходящая интеграция)

Заголовок раздела «Путь 2. Portal вызывает внешнюю систему (исходящая интеграция)»

Новый HTTP-эндпоинт на Portal не создаётся. Логика исходящих вызовов пишется в C#-расширениях.

listItem.updated → event_receivers → portal_jobs → IEventReceiver.HandleAsync
ШагДействие
1Скачайте Extension SDK, затем dotnet new portal-eventreceiver
2Реализовать HandleAsync(...) — внутри вызвать внешний HTTP API
3Собрать .portalevent, загрузить: Админка → Event Receivers
4Привязать: POST /api/v1/event-receivers с eventName + config.listId
5Мониторинг: Админка → Задания

Документация: Event Receivers, привязка к событиям.

Пример привязки:

{
"eventName": "listItem.updated",
"jobType": "contoso.list-change-handler",
"config": { "listId": "uuid-списка" },
"isEnabled": true
}

Timer Job (.portaltimer) — периодическая синхронизация

Заголовок раздела «Timer Job (.portaltimer) — периодическая синхронизация»

Для nightly sync (ERP → Portal или Portal → ERP):

ШагДействие
1dotnet new portal-timerjob
2Реализовать ExecuteAsync с HTTP-вызовами
3Загрузить пакет, настроить расписание в Админка → Timer Jobs

Документация: Timer Jobs, интеграция с Worker.


Путь 3. Серверная логика через WebPart (UI + actions)

Заголовок раздела «Путь 3. Серверная логика через WebPart (UI + actions)»

WebPart не добавляет новые REST-маршруты, но даёт фиксированные invoke-эндпоинты:

МетодПутьНазначение
POST/api/v1/webparts/invoke/{key}/renderSSR HTML
POST/api/v1/webparts/invoke/{key}/actionСерверные действия

{key} — из manifest.json пакета .portalpart, не произвольный URL.

ШагДействие
1dotnet new portal-webpart -n my-widget
2RenderAsync + HandleActionAsync в IWebPart
3Сборка .portalpart, загрузка: Админка → WebPart
4Размещение на странице через zonesContent

Документация: сборка WebPart, UI и API, API каталога.


Путь 4. Функциональный модуль (.portalmod) — полное решение

Заголовок раздела «Путь 4. Функциональный модуль (.portalmod) — полное решение»

Если интеграция — часть готового решения (структура портала + расширения):

ШагДействие
1Описать module.json (узлы, списки, страницы, права)
2Положить .portalpart/.portalevent/.portaltimer в packages/
3Опционально — C# provisioner для начальных данных
4Установить: Админка → Модули или POST /api/v1/modules/install
5Получить resource_map: GET /api/v1/modules/{key}/resources

Документация: функциональные модули, API модулей, схема module.json.

В packages/ модуль также кладёт .portalapi, а стартовые настройки ручки — в webServices.


Когда внешней системе или WebPart нужна операция, которой нет в CRUD списков: расчёт, сборка ответа из нескольких списков, проверка перед записью.

ШагДействие
1dotnet new portal-webservice, класс IWebService
2В manifest.json задать id (vendor.name)
3Собрать ZIP: pack-portalapi.sh
4Админка → Веб-сервисы или пакет модуля type: web-service
5POST /api/v1/web-services/call/{id} с JWT пользователя и JSON-телом

Один пакет — один POST. Параметры вызова — тело. Id списка и прочие настройки администратора — config ручки, не тело. Query timeout — секунды ожидания (30 по умолчанию, до 600). Истечение лимита — HTTP 408 и { "success": false, "error": { "code": "TIMEOUT", "message": "…" } }.

Списки внутри обработчика читаются от вызвавшего пользователя. Анонимного вызова и API-ключа нет: у внешней системы должна быть учётная запись портала и JWT после POST /api/v1/auth/login.

Документация: веб-сервисы, SDK, выполнение.


КонтекстSDKКлючи при записиПрава
REST (внешняя система)HTTPUUID или internal_nameJWT сервисного пользователя
WebPartPortal.WebPart.SdkPortalListItem / internal_nameТекущий пользователь страницы
Event ReceiverPortal.EventReceiver.SdkPortalListItem / internal_nameПользователь события
Timer JobPortal.TimerJob.SdkPortalListItem / internal_nameсистемная учётка portal-system
Веб-сервисPortal.WebService.SdkPortalListItem / internal_nameПользователь, чей JWT на POST /web-services/call/{id}
ProvisionerPortal.Module.Sdkinternal_nameСистемные (установка модуля)

Подробнее: кейсы работы с сущностями.


  • Нет регистрации произвольного пути /api/v1/my-erp/sync из пакета. Своя логика — один адрес POST /api/v1/web-services/call/{id} (веб-сервисы)
  • Нет анонимных webhook. Внешняя система вызывает ручку или REST только с JWT пользователя портала
  • Нет API keys — только JWT через логин пользователя (local или LDAP)
  • Новый отдельный маршрут в платформе — изменение исходников Portal.Api (работа вендора). Пакету достаточно id в манифесте .portalapi

  1. REST API — обзор маршрутов
  2. Аутентификация — вход и JWT
  3. Значения полей — чтение/запись данных
  4. Кейсы кода — практические примеры (в т.ч. ERP)
  5. По типу расширения: web-services / event-receivers / timer-jobs / webparts / modules