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. Ее можно импортировать в Postman, Swagger UI, генераторы клиентов и системы автоматического тестирования.
Открыть Swagger UI · Скачать openapi.json
User API работает только с собственными личными постами: владелец токена должен быть и автором поста, и владельцем страницы профиля, на которой этот пост опубликован.
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.
GET /user/posts/:idcurl -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/:idcurl -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-токена является владельцем этого сообщества.
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.
GET /communities/:community/posts/:idcurl -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/:idcurl -X DELETE "https://api.itprostore.ru/api/integrations/v1/communities/my-community/posts/123" \
-H "Authorization: Bearer itps_live.<publicId>.<secret>"API поддерживает только то форматирование, которое доступно пользователю в редакторе постов АйТиПростор. Все остальные HTML-теги и атрибуты удаляются сервером при сохранении.
| Возможность | Разрешенные теги | Комментарий |
|---|---|---|
| Жирный текст | <strong>, <b> | Оба варианта принимаются, потому что браузеры могут формировать разные теги. |
| Курсив | <i>, <em> | Оба варианта принимаются по той же причине. |
| Абзац | <p> | Используйте для отдельных абзацев. Пробельные переносы между абзацами сервер нормализует. |
| Перенос строки | <br> | Используется для обычного переноса строки в редакторе. |
| Ссылка | <a href="https://..."> | Разрешены только http и https. Сервер добавляет target="_blank" и rel="noopener noreferrer". |
Не используйте списки, заголовки, таблицы, изображения внутри HTML, inline-стили, классы, scripts, iframe и обработчики событий. Такие элементы будут удалены или превращены в обычный текст.
.jpg, .jpeg, .png, .gif..rar, .7z, .pdf, .doc, .docx, .txt, .xlsx, .xls. Для создания поста можно передавать заголовок 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-Reset | Unix-время, когда лимит будет сброшен. |
Retry-After | Возвращается при 429; показывает, через сколько секунд можно повторить запрос. |
В личном кабинете в разделе Интеграция у каждого токена доступен журнал последних запросов: метод, путь, статус, scope, время выполнения, код ошибки и request ID.
Журнал помогает быстро понять, какой запрос получил ошибку, но не содержит тело запроса, вложения, исходный IP и сам API-токен.
Ошибки возвращаются в едином формате:
{
"errorCode": "ScopeDenied",
"message": "У API-токена нет прав для этого действия."
} Подписчики тарифа Plus могут получать новые заявки прямо в свою CRM или любую другую систему. АйТиПростор отправляет POST-запрос с JSON на один HTTPS-адрес компании. Это исходящий вызов с нашей стороны: API-токен из разделов выше для него не нужен, а проверка подлинности выполняется подписью HMAC.
endpoint.test: оно содержит полный пример заявки в том же формате, что и реальные события. Ваш сервер должен ответить 2xx.Замена адреса выпускает новый секрет и выключает передачу до нового успешного теста. Уже поставленные в очередь события на новый адрес не переносятся. При окончании подписки Plus отправка останавливается, адрес и секрет сохраняются.
Событие создаётся в тот же момент, когда компании уходит письмо о заявке с контактами заказчика — то есть когда компания попала в подбор по заявке (регион, лицензии и другие требования) и получила к ней полный доступ. Заявки, по которым компании доступно только описание без контактов, в CRM не передаются.
| Тип события | Когда |
|---|---|
request.created | Компания впервые получила заявку с контактами: при публикации, а для запросов по 44-ФЗ — при публикации потребности. |
request.updated | Заказчик изменил заявку (описание, контакты, файлы) или опубликовал новую версию потребности. Приходят полные актуальные данные; обновляйте лид по request.id. |
endpoint.test | Тестовое событие по кнопке в настройках. Поле test равно true, request.id равен 0. |
Передаются все три типа заявок: быстрые заявки (quick), запросы ценовых предложений (price-offers) и запросы КП по 44-ФЗ (market-study).
| Заголовок | Значение |
|---|---|
Content-Type | application/json; charset=utf-8 |
X-ITProStore-Event-Id | UUID события. Совпадает с eventId в теле и не меняется при повторах. |
X-ITProStore-Timestamp | Unix-время отправки в секундах (UTC). |
X-ITProStore-Signature | sha256= + 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 присутствуют всегда.
| Поле | Тип | Описание |
|---|---|---|
version | number | Версия формата, сейчас 2. |
eventId | string (UUID) | Уникальный идентификатор события. При повторной доставке тот же. |
type | string | request.created, request.updated или endpoint.test. |
test | boolean | true только для тестового события. |
createdAtUtc | string (ISO 8601) | Время формирования события, UTC. |
companyId | number | ID вашей компании в АйТиПростор — получатель события. |
request | object | Заявка, см. ниже. |
access.fullAccess | boolean | Всегда true для реальных событий: в CRM уходят только заявки с полным доступом. |
access.reason | string | Основание допуска: quick_original_match, request_full, market_full, subscription. |
documentation | string | Ссылка на этот раздел. |
request| Поле | Тип | Описание |
|---|---|---|
id | number | ID заявки. Ключ для создания и обновления лида. |
requestType | string | quick — быстрая заявка, price-offers — запрос ценовых предложений, market-study — сбор КП и НМЦК по 44-ФЗ. |
requestTypeLabel | string | Название типа на русском. |
title | string | Заголовок заявки. |
description | string | null | Описание задачи. Обычный текст, переносы строк — \n. |
url | string | Ссылка на карточку заявки на сайте. |
createdAtUtc | string | null | Дата и время создания заявки. |
publishedAtUtc | string | null | Дата и время публикации. |
contactAccessEndsAtUtc | string | null | Для быстрых заявок: до какого момента открыты контакты (пять дней с публикации). После этого заявка уходит в архив. |
responsesDueAtUtc | string | null | Для запросов по 44-ФЗ: срок приёма коммерческих предложений. |
publicNumber | string | null | Для запросов по 44-ФЗ: публичный номер запроса. |
revisionId, revisionNumber | number | null | Для запросов по 44-ФЗ: версия опубликованной потребности. |
topic | object | null | Для быстрых заявок: направление работ — slug (ispdn, zp, spsi, asgt, vp) и name. |
regions | array | Регионы выполнения: { id, name }. Пустой массив — вся Россия. |
maxCost | number | null | Максимальная стоимость, если заказчик указал. |
lastDateWork | string | null | Желаемый срок выполнения (дата). |
requester | object | null | Заказчик: organization, name, phone, email. Любое поле может быть null, если заказчик его не указал. |
items | array | Для запросов по 44-ФЗ: позиции { number, name, description, expectedResult, quantity, unit }. Для остальных типов пустой массив. |
files | array | Файлы заявки: { 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"
}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 и исходным именем.
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.