API АйТиПростор

API предназначен для интеграции внешних сервисов с АйТиПростор. Первая версия позволяет управлять личными постами пользователя и собственными постами в сообществах, где владелец токена является владельцем сообщества: получать список ID, создавать, получать, редактировать и удалять посты.

Авторизация

API использует бессрочные токены. Токен создается в личном кабинете в разделе Интеграция и показывается только один раз. Передавайте токен только в HTTP-заголовке:

Authorization: Bearer itps_live.<publicId>.<secret>

Не передавайте токен в query string и не размещайте его в публичном frontend-коде.

Рекомендуемая схема интеграции — запросы с backend внешнего сервиса. Публичные endpoints API принимают CORS-запросы с HTTPS-сайтов, но хранить API-токен в браузерном JavaScript небезопасно: пользователь или сторонний скрипт сможет увидеть этот токен.

Права токена

ScopeНазначение
user.posts.readПолучение списка ID и чтение личных постов.
user.posts.writeСоздание и редактирование личных постов.
user.posts.deleteУдаление личных постов.
community.posts.readПолучение списка ID и чтение постов сообществ, которыми владеет пользователь.
community.posts.writeСоздание и редактирование постов в сообществах, которыми владеет пользователь.
community.posts.deleteУдаление постов в сообществах, которыми владеет пользователь.

Токены, выпущенные ранее для user.posts.*, также принимаются для соответствующих операций с owned-сообществами. Это сделано для совместимости существующих интеграций.

Базовый адрес

https://api.itprostore.ru/api/integrations/v1

OpenAPI

Машиночитаемая спецификация доступна в формате OpenAPI. Ее можно импортировать в Postman, Swagger UI, генераторы клиентов и системы автоматического тестирования.

Открыть Swagger UI · Скачать openapi.json

Посты пользователя

User API работает только с собственными личными постами: владелец токена должен быть и автором поста, и владельцем страницы профиля, на которой этот пост опубликован.

Получить список ID постов

GET /user/posts/ids?skip=0&take=100

Максимальное значение take — 200. Возвращаются только личные посты владельца токена.

curl -X GET "https://api.itprostore.ru/api/integrations/v1/user/posts/ids?skip=0&take=100" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"

Создать пост

POST /user/posts
Content-Type: multipart/form-data

text=<b>Новый пост</b>
files=<file>
curl -X POST "https://api.itprostore.ru/api/integrations/v1/user/posts" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>" \
  -H "Idempotency-Key: 7f3b8616-0b8c-4a2b-bef1-31b542da0b21" \
  -F "text=<strong>Пост из интеграции</strong>" \
  -F "files=@/path/to/file.pdf"

Найти пост

GET /user/posts/search?text=часть%20текста&skip=0&take=20

Метод ищет личные посты владельца токена, в тексте которых есть указанная строка, и возвращает список ID от самых свежих к более старым. Параметр text обязателен: от 2 до 500 символов. skip и take используются для постраничной загрузки результатов, максимальное значение take — 100.

curl -X GET "https://api.itprostore.ru/api/integrations/v1/user/posts/search?text=%D0%9F%D0%BE%D1%81%D1%82%20%D0%B8%D0%B7%20%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D0%B8&skip=0&take=20" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"
{
  "found": true,
  "query": "Пост из интеграции",
  "ids": [123, 118, 91],
  "skip": 0,
  "take": 20,
  "hasMore": false
}

Если совпадений нет, API вернет 200, "found": false и пустой массив ids. Для GET-запроса передавайте text в query string, а не в multipart/form-data body.

Получить пост по ID

GET /user/posts/:id
curl -X GET "https://api.itprostore.ru/api/integrations/v1/user/posts/123" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"

Редактировать пост

PUT /user/posts/:id
Content-Type: multipart/form-data

text=Обновленный текст
keptAttachments=old-file.png
files=<new-file>
curl -X PUT "https://api.itprostore.ru/api/integrations/v1/user/posts/123" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>" \
  -F "text=Обновленный текст<br><a href="https://itprostore.ru">АйТиПростор</a>" \
  -F "keptAttachments=old-file.png" \
  -F "files=@/path/to/new-file.pdf"

Поле keptAttachments передается для вложений, которые нужно оставить. Все старые вложения, не переданные в keptAttachments, будут удалены.

Удалить пост

DELETE /user/posts/:id
curl -X DELETE "https://api.itprostore.ru/api/integrations/v1/user/posts/123" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"

Посты сообщества

Community API управляет обычными постами-сообщениями в ленте сообщества. Статьи и репосты через этот API сейчас не создаются и не редактируются. API возвращает, редактирует и удаляет только те посты, где автором является владелец токена. Посты других участников сообщества через API недоступны, даже если токен принадлежит владельцу сообщества. В параметр {community} передайте slug из адреса /community/{slug} или числовой Id сообщества. Сервер всегда проверяет, что владелец API-токена является владельцем этого сообщества.

Получить список ID постов сообщества

GET /communities/:community/posts/ids?skip=0&take=100

Максимальное значение take — 200. Возвращаются только неудаленные обычные посты-сообщения, созданные владельцем токена.

curl -X GET "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts/ids?skip=0&take=100" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"

Создать пост в сообществе

POST /communities/:community/posts
Content-Type: multipart/form-data

text=<b>Новый пост сообщества</b>
files=<file>
curl -X POST "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>" \
  -H "Idempotency-Key: 2b5e4ab1-1b57-4a1e-b025-3b5b2b9d80e8" \
  -F "text=<strong>Пост сообщества из интеграции</strong>" \
  -F "files=@/path/to/file.pdf"

Импортировать пост сообщества с датой

POST /communities/:community/posts/import
Content-Type: multipart/form-data

text=<b>Старый пост сообщества</b>
createdAt=2026-02-15T10:30:00+03:00
files=<file>

Метод предназначен для переноса старых публикаций в АйТиПростор. Он создает обычный пост сообщества, но сохраняет указанную дату публикации и не отправляет уведомления: ни SignalR-события, ни push. Поэтому, чтобы увидеть импортированный пост на странице сообщества, обновите страницу после завершения импорта.

  • createdAt обязателен. Передавайте дату и время в ISO 8601, желательно с часовым поясом.
  • Дата не может быть в будущем.
  • Дата не может быть старше одного года от момента запроса.
  • В ленте сообщества пост будет отсортирован по указанному времени публикации.
curl -X POST "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts/import" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>" \
  -H "Idempotency-Key: 9c8f5f23-6f17-4f28-99e4-c9bbd32f5ac1" \
  -F "text=<strong>Пост из архива</strong>" \
  -F "createdAt=2026-02-15T10:30:00+03:00" \
  -F "files=@/path/to/archive-image.png"

Найти пост сообщества

GET /communities/:community/posts/search?text=часть%20текста&skip=0&take=20

Метод ищет обычные посты-сообщения в указанном сообществе, созданные владельцем токена, и возвращает список ID от самых свежих к более старым. Параметр text обязателен: от 2 до 500 символов. skip и take используются для постраничной загрузки результатов, максимальное значение take — 100.

curl -X GET "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts/search?text=%D0%9F%D0%BE%D1%81%D1%82%20%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B0&skip=0&take=20" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"
{
  "found": true,
  "query": "Пост сообщества",
  "communityId": 10,
  "communitySlug": "my-community",
  "ids": [123, 118, 91],
  "skip": 0,
  "take": 20,
  "hasMore": false
}

Если совпадений нет, API вернет 200, "found": false и пустой массив ids. Для GET-запроса передавайте text в query string, а не в multipart/form-data body.

Получить пост сообщества по ID

GET /communities/:community/posts/:id
curl -X GET "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts/123" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"

Редактировать пост сообщества

PUT /communities/:community/posts/:id
Content-Type: multipart/form-data

text=Обновленный текст
keptAttachments=old-file.png
files=<new-file>
curl -X PUT "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts/123" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>" \
  -F "text=Обновленный текст<br><a href="https://itprostore.ru">АйТиПростор</a>" \
  -F "keptAttachments=old-file.png" \
  -F "files=@/path/to/new-file.pdf"

Поле keptAttachments работает так же, как у личных постов: передайте имена вложений, которые нужно оставить. Остальные старые вложения будут удалены.

Удалить пост сообщества

DELETE /communities/:community/posts/:id
curl -X DELETE "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts/123" \
  -H "Authorization: Bearer itps_live.<publicId>.<secret>"

Форматирование HTML

API поддерживает только то форматирование, которое доступно пользователю в редакторе постов АйТиПростор. Все остальные HTML-теги и атрибуты удаляются сервером при сохранении.

ВозможностьРазрешенные тегиКомментарий
Жирный текст<strong>, <b>Оба варианта принимаются, потому что браузеры могут формировать разные теги.
Курсив<i>, <em>Оба варианта принимаются по той же причине.
Абзац<p>Используйте для отдельных абзацев. Пробельные переносы между абзацами сервер нормализует.
Перенос строки<br>Используется для обычного переноса строки в редакторе.
Ссылка<a href="https://...">Разрешены только http и https. Сервер добавляет target="_blank" и rel="noopener noreferrer".

Не используйте списки, заголовки, таблицы, изображения внутри HTML, inline-стили, классы, scripts, iframe и обработчики событий. Такие элементы будут удалены или превращены в обычный текст.

Вложения

  • Можно прикрепить максимум 5 файлов.
  • Размер одного файла — до 25 МБ, суммарно — до 50 МБ.
  • Изображения: .jpg, .jpeg, .png, .gif.
  • Файлы: .rar, .7z, .pdf, .doc, .docx, .txt, .xlsx, .xls.
  • Для личных постов API управляет только постами, где владелец токена является автором и владельцем страницы.
  • Для постов сообщества API доступен только владельцу сообщества и работает только с его собственными обычными постами-сообщениями, без статей и репостов.

Idempotency-Key

Для создания поста можно передавать заголовок Idempotency-Key. Это защищает от дублей, если внешний сервис повторил запрос из-за сетевой ошибки или таймаута.

ПравилоОписание
ДлинаОт 1 до 128 ASCII-символов без пробелов. Удобно использовать UUID.
Срок храненияКлюч хранится 24 часа для конкретного токена, метода, адреса и содержимого запроса.
ПовторПовтор такого же запроса возвращает сохраненный ответ и заголовок Idempotent-Replayed: true.
КонфликтЕсли ключ уже использован с другим содержимым, API вернет 409.

Используйте новый Idempotency-Key для каждой логической операции создания поста. Для чтения, редактирования и удаления этот заголовок сейчас не требуется.

Лимиты запросов

Публичный API ограничен по IP-адресу, чтобы защитить сервис от перегрузки. Текущий лимит: 120 запросов в минуту.

ЗаголовокЗначение
X-RateLimit-LimitМаксимальное число запросов в текущем окне.
X-RateLimit-RemainingСколько запросов осталось до конца окна.
X-RateLimit-ResetUnix-время, когда лимит будет сброшен.
Retry-AfterВозвращается при 429; показывает, через сколько секунд можно повторить запрос.

Журнал токена

В личном кабинете в разделе Интеграция у каждого токена доступен журнал последних запросов: метод, путь, статус, scope, время выполнения, код ошибки и request ID.

Журнал помогает быстро понять, какой запрос получил ошибку, но не содержит тело запроса, вложения, исходный IP и сам API-токен.

Ошибки

Ошибки возвращаются в едином формате:

{
  "errorCode": "ScopeDenied",
  "message": "У API-токена нет прав для этого действия."
}

Заявки в CRM (webhook)

Подписчики тарифа Plus могут получать новые заявки прямо в свою CRM или любую другую систему. АйТиПростор отправляет POST-запрос с JSON на один HTTPS-адрес компании. Это исходящий вызов с нашей стороны: API-токен из разделов выше для него не нужен, а проверка подлинности выполняется подписью HMAC.

Подключение

  1. Откройте Сервисы компании → Преимущества подписки → Передача заявок в CRM (пункт виден при действующей Plus).
  2. Укажите публичный HTTPS-адрес на порту 443 без логина и пароля в URL и без перенаправлений. Локальные и приватные адреса не принимаются.
  3. Сохраните адрес — сервис покажет секрет подписи один раз. Сохраните его в настройках вашей системы.
  4. Отправьте тестовое событие endpoint.test: оно содержит полный пример заявки в том же формате, что и реальные события. Ваш сервер должен ответить 2xx.
  5. Включите передачу. С этого момента новые заявки уходят автоматически.

Замена адреса выпускает новый секрет и выключает передачу до нового успешного теста. Уже поставленные в очередь события на новый адрес не переносятся. При окончании подписки Plus отправка останавливается, адрес и секрет сохраняются.

Когда приходит событие

Событие создаётся в тот же момент, когда компании уходит письмо о заявке с контактами заказчика — то есть когда компания попала в подбор по заявке (регион, лицензии и другие требования) и получила к ней полный доступ. Заявки, по которым компании доступно только описание без контактов, в CRM не передаются.

Тип событияКогда
request.createdКомпания впервые получила заявку с контактами: при публикации, а для запросов по 44-ФЗ — при публикации потребности.
request.updatedЗаказчик изменил заявку (описание, контакты, файлы) или опубликовал новую версию потребности. Приходят полные актуальные данные; обновляйте лид по request.id.
endpoint.testТестовое событие по кнопке в настройках. Поле test равно true, request.id равен 0.

Передаются все три типа заявок: быстрые заявки (quick), запросы ценовых предложений (price-offers) и запросы КП по 44-ФЗ (market-study).

Заголовки и проверка подписи

ЗаголовокЗначение
Content-Typeapplication/json; charset=utf-8
X-ITProStore-Event-IdUUID события. Совпадает с eventId в теле и не меняется при повторах.
X-ITProStore-TimestampUnix-время отправки в секундах (UTC).
X-ITProStore-Signaturesha256= + hex-строка HMAC-SHA256 в нижнем регистре.

Подпись считается от строки timestamp + "." + body, где body — исходные байты тела запроса без изменений, а ключ — секрет, декодированный из Base64:

signature = hex( HMAC_SHA256( base64_decode(secret), timestamp + "." + raw_body ) )

Пример проверки на Python:

import base64, hashlib, hmac, time

def verify(headers, raw_body: bytes, secret: str) -> bool:
    ts = headers["X-ITProStore-Timestamp"]
    if abs(time.time() - int(ts)) > 300:          # не старше 5 минут
        return False
    key = base64.b64decode(secret)
    expected = hmac.new(key, ts.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    received = headers["X-ITProStore-Signature"].removeprefix("sha256=")
    return hmac.compare_digest(expected, received)

Проверяйте подпись до разбора JSON и по исходным байтам тела, а не по пересобранной строке. Сравнивайте в постоянное время. Запросы с неверной подписью или устаревшей меткой времени отклоняйте.

Формат события

Текущая версия формата — version: 2. Новые поля добавляются без смены версии; существующие не переименовываются и не удаляются. Поля со значением null присутствуют всегда.

Корень

ПолеТипОписание
versionnumberВерсия формата, сейчас 2.
eventIdstring (UUID)Уникальный идентификатор события. При повторной доставке тот же.
typestringrequest.created, request.updated или endpoint.test.
testbooleantrue только для тестового события.
createdAtUtcstring (ISO 8601)Время формирования события, UTC.
companyIdnumberID вашей компании в АйТиПростор — получатель события.
requestobjectЗаявка, см. ниже.
access.fullAccessbooleanВсегда true для реальных событий: в CRM уходят только заявки с полным доступом.
access.reasonstringОснование допуска: quick_original_match, request_full, market_full, subscription.
documentationstringСсылка на этот раздел.

Объект request

ПолеТипОписание
idnumberID заявки. Ключ для создания и обновления лида.
requestTypestringquick — быстрая заявка, price-offers — запрос ценовых предложений, market-study — сбор КП и НМЦК по 44-ФЗ.
requestTypeLabelstringНазвание типа на русском.
titlestringЗаголовок заявки.
descriptionstring | nullОписание задачи. Обычный текст, переносы строк — \n.
urlstringСсылка на карточку заявки на сайте.
createdAtUtcstring | nullДата и время создания заявки.
publishedAtUtcstring | nullДата и время публикации.
contactAccessEndsAtUtcstring | nullДля быстрых заявок: до какого момента открыты контакты (пять дней с публикации). После этого заявка уходит в архив.
responsesDueAtUtcstring | nullДля запросов по 44-ФЗ: срок приёма коммерческих предложений.
publicNumberstring | nullДля запросов по 44-ФЗ: публичный номер запроса.
revisionId, revisionNumbernumber | nullДля запросов по 44-ФЗ: версия опубликованной потребности.
topicobject | nullДля быстрых заявок: направление работ — slug (ispdn, zp, spsi, asgt, vp) и name.
regionsarrayРегионы выполнения: { id, name }. Пустой массив — вся Россия.
maxCostnumber | nullМаксимальная стоимость, если заказчик указал.
lastDateWorkstring | nullЖелаемый срок выполнения (дата).
requesterobject | nullЗаказчик: organization, name, phone, email. Любое поле может быть null, если заказчик его не указал.
itemsarrayДля запросов по 44-ФЗ: позиции { number, name, description, expectedResult, quantity, unit }. Для остальных типов пустой массив.
filesarrayФайлы заявки: { id, name, size, downloadUrl, expiresAtUtc }. См. раздел «Файлы заявки».

Примеры

Быстрая заявка — request.created

{
  "version": 2,
  "eventId": "9d1e2c5a-6f3b-4a1e-9c7d-2b1f0e9a8c31",
  "type": "request.created",
  "test": false,
  "createdAtUtc": "2026-09-16T09:12:44.318Z",
  "companyId": 482,
  "request": {
    "id": 10457,
    "requestType": "quick",
    "requestTypeLabel": "Быстрая заявка",
    "title": "Заявка по теме: Аттестация ИСПДн",
    "description": "Нужна аттестация ИСПДн на 25 рабочих мест, срок — до конца квартала.",
    "url": "https://itprostore.ru/requestCost/10457",
    "createdAtUtc": "2026-09-16T09:12:40.105Z",
    "publishedAtUtc": "2026-09-16T09:12:40.105Z",
    "contactAccessEndsAtUtc": "2026-09-21T09:12:40.105Z",
    "responsesDueAtUtc": null,
    "publicNumber": null,
    "revisionId": null,
    "revisionNumber": null,
    "topic": { "slug": "ispdn", "name": "Аттестация ИСПДн" },
    "regions": [ { "id": 23, "name": "Краснодарский край" } ],
    "maxCost": null,
    "lastDateWork": null,
    "requester": {
      "organization": "ООО «Пример»",
      "name": "Иван Петров",
      "phone": "+79990000000",
      "email": "ivan@example.ru"
    },
    "items": [],
    "files": [
      {
        "id": 3921,
        "name": "ТЗ_на_аттестацию.pdf",
        "size": null,
        "downloadUrl": "https://itprostore.ru/api/company-subscription/webhook/files/CfDJ8…",
        "expiresAtUtc": "2026-10-16T09:12:44.318Z"
      }
    ]
  },
  "access": { "fullAccess": true, "reason": "quick_original_match" },
  "documentation": "https://itprostore.ru/api-docs#crm-webhook"
}

Запрос КП по 44-ФЗ — request.updated (фрагмент)

{
  "version": 2,
  "type": "request.updated",
  "request": {
    "id": 10502,
    "requestType": "market-study",
    "requestTypeLabel": "Сбор КП и НМЦК по 44-ФЗ",
    "title": "Поставка и настройка СЗИ для ГИС",
    "publicNumber": "З-2026-000318",
    "revisionId": 771,
    "revisionNumber": 2,
    "responsesDueAtUtc": "2026-09-30T12:00:00Z",
    "items": [
      { "number": 1, "name": "СЗИ от НСД", "description": "Сертифицированное, класс 2", "expectedResult": null, "quantity": 40, "unit": "шт" },
      { "number": 2, "name": "Настройка и ввод в эксплуатацию", "description": null, "expectedResult": "Акт", "quantity": 1, "unit": "усл." }
    ],
    "requester": { "organization": "ГБУ «Пример»", "name": "Мария Сидорова", "phone": "+79990000001", "email": "zakupki@example.ru" }
  }
}

Файлы заявки

Если в настройках включено «Передавать файлы заявки», для каждого файла передаётся временная ссылка downloadUrl. Скачивание по ней не требует авторизации: GET по адресу возвращает файл с заголовком Content-Disposition и исходным именем.

  • Ссылка действует 30 дней (expiresAtUtc) и только пока у компании сохраняется доступ к заявке и действует Plus. Скачивайте файлы сразу при получении события.
  • Ссылка привязана к вашей компании и конкретному файлу; передавать её третьим лицам не следует.
  • Ошибки: 404 — ссылка истекла или файл удалён, 403 — доступ к заявке или подписка прекращены.
  • Если настройка выключена, массив files пуст. Названия файлов в этом случае видны в карточке заявки на сайте.

Ответ, повторы, идемпотентность

ПравилоОписание
ПодтверждениеЛюбой ответ 2xx означает, что событие принято. Тело ответа не читается. Отвечайте быстро, обработку выполняйте после ответа.
Таймаут15 секунд на соединение и ответ. Перенаправления (3xx) не выполняются и считаются ошибкой.
ПовторыПри 408, 429, 5xx, таймауте и сетевой ошибке событие отправляется повторно с нарастающим интервалом (от 30 секунд до часа), до 8 попыток. Заголовок Retry-After учитывается.
Без повтораОстальные 4xx считаются окончательным отказом. Такое событие можно отправить снова вручную из журнала передач.
ИдемпотентностьПри повторе eventId и тело не меняются. Храните обработанные eventId и не создавайте второй лид по одному событию. Лид ищите по request.id.
ПорядокПорядок доставки событий не гарантируется. Если пришло request.updated раньше request.created, создайте лид по нему.
ОтменаЕсли до отправки заявка закрыта, доступ компании отозван или подписка Plus закончилась, событие отменяется и не отправляется.

Журнал передач с результатом каждой попытки и кнопкой повтора доступен в настройках интеграции: Сервисы компании → Преимущества подписки → Передача заявок в CRM.