Интеграция с Support по API (для разработчиков)
Для кого
Разработчики, которые встраивают TehProf Support как канал поддержки в своё приложение или сервис: чтобы сотрудники клиента подавали заявки на доработку прямо из вашего продукта, получали ответы и полноценно переписывались, не покидая приложение. Подходит и для приложений на Bitrix24 (например, наше приложение бронирования), и для внешних SaaS без Bitrix24.
Что вы получите
Двусторонний канал «ваш продукт → наша поддержка»: ваш сервер выдаёт каждому сотруднику персональный доступ к поддержке, сотрудник видит только свои заявки, создаёт новые, отвечает в переписке. Секретный ключ остаётся на вашем сервере и никогда не попадает в браузер.
Предварительные требования
- API-ключ Support с нужными правами (как получить — см. ниже «Как получить API-ключ»).
- Сервер на вашей стороне (Node.js, PHP, Python — любой), который держит ключ в секрете. Прямые вызовы из браузера запрещены.
- Понимание, кого вы идентифицируете: пара «домен портала + ID пользователя» (для Bitrix24) или ваш собственный ID пользователя (для внешнего SaaS).
Три способа интеграции — что выбрать
Support даёт три независимых входа. Выберите по сценарию:
| Способ | Кто вызывает | Аутентификация | Когда использовать |
|---|---|---|---|
| Серверный мост (ctoken) | Ваш сервер → затем браузер пользователя | API-ключ (Bearer) на сервере, потом клиентский токен у пользователя | Ваши сотрудники подают заявки в нашу поддержку из вашего приложения. Основной сценарий этого руководства. |
| Операторский API (Bearer) | Ваш сервер | API-ключ (Bearer) | Программное управление заявками со стороны поддержки: массовое создание, чтение, аналитика, боты. |
| Встраивание интерфейса (JWT) | Ваш сервер + iframe | JWT-токен | Вы хотите показать готовый интерфейс поддержки внутри своего приложения через iframe (полный кабинет, не своя вёрстка). |
| Входной вебхук + синхронизация компаний | Ваш сервер | API-ключ в заголовке X-Api-Key | Ваш продукт создаёт заявки от имени клиентов и передаёт их компанию/контакт по своим стабильным ключам — заявка автоматически привязывается к нужной компании. Идемпотентно. |
Дальше подробно разобран основной сценарий (серверный мост), затем кратко остальные.
Сценарий 1: серверный мост — заявки от ваших сотрудников
Это путь, по которому работает наше приложение бронирования. Логика канона Stripe Connect: платформенный ключ живёт только на сервере, пользователь получает узкий одноразовый токен.
Как это устроено
Ваш сервер (держит API-ключ)
│ 1. POST issue_client_token (Bearer = API-ключ)
▼
Support выдаёт персональный клиентский токен (ctoken) для одного сотрудника
│ 2. ctoken отдаётся в браузер сотрудника (или ваш сервер ходит сам)
▼
Браузер/сервер с ctoken вызывает client.php:
- создать заявку
- список своих заявок
- ответить в переписке
- проверить новые ответы
Шаг 1: получить персональный токен сотрудника
Ваш сервер (не браузер!) запрашивает у Support персональный токен для конкретного сотрудника. Публичный endpoint принимает запросы server-to-server по Bearer API-ключу; безопасность зависит от того, что ключ хранится только на вашем сервере и никогда не попадает в браузер.
POST https://support.tehprof.kz/api/mcp-internal.php
Authorization: Bearer sk_ваш_ключ
Content-Type: application/json
{
"action": "issue_client_token",
"b24_user_id": "12345",
"portal_domain": "client-portal.bitrix24.kz",
"name": "Иван Петров",
"email": "ivan@client.kz"
}
Ответ:
{
"ok": true,
"data": {
"ctoken": "ct_eyJ0Ijox...подпись",
"user_id": 2890,
"expires_in": 86400
}
}
Поля запроса:
b24_user_id(обязательно) — ID сотрудника в вашей системе (для Bitrix24 — его user ID на портале).portal_domain(обязательно) — домен портала/аккаунта сотрудника. Вместе сb24_user_idобразует уникальную личность.name(необязательно) — отображаемое имя. По умолчанию «Staff».email(необязательно) — email сотрудника. Желательно передавать: помогает связать личность.
Важно: этот метод не принимает компанию. Серверный мост идентифицирует только человека (по пареb24_user_id + portal_domain). Поля вродеcompany_name,company_id,company_external_idмолча игнорируются — заявка к компании по ним не привяжется. Если вам нужно, чтобы заявка попадала под нужную компанию клиента по вашему ID компании — используйте Сценарий 4 (входной вебхук) с полямиcompany_external_id/contact_external_id. Это частая причина «компанию передаю, а она не подтягивается».
Как формируется отображаемое имя. Имя контакта берётся из поляname, которое вы прислали. Повторный вызовissue_client_tokenсам по себе не перезаписывает имя уже существующего контакта. Поэтому сразу передавайте реальное ФИО конкретного пользователя, а исправлять ранее сохранённое имя нужно вручную в карточке контакта.
Важно про идемпотентность: для одной и той же пары b24_user_id + portal_domain всегда возвращается один и тот же user_id. Поэтому фильтр «только мои заявки» работает стабильно при повторных выдачах токена. ctoken живёт 24 часа (expires_in) — кешируйте его и перевыпускайте за несколько минут до истечения.
Шаг 2: работать от лица сотрудника по ctoken
Полученный ctoken передаётся в заголовке X-Client-Token при вызовах client.php.
Создать заявку:
POST https://support.tehprof.kz/api/client.php
X-Client-Token: ct_eyJ0Ijox...
Content-Type: application/json
{
"action": "create_ticket",
"subject": "Не открывается календарь брони",
"description": "При клике на дату ничего не происходит, консоль пустая",
"category": "other",
"priority": "normal"
}
Обязательно укажите валидную категорию. Если полеcategoryне передать, заявка получит категорию по умолчанию, которая может оказаться невалидной → ошибкаerr_input_required_fields. Безопасное значение —other. Список доступных категорий зависит от настроек принимающей компании (встроенные + кастомные).
Поля: subject (обязательно), description (обязательно), category (обязательно, рекомендуем other), priority (low/normal/high/urgent, по умолчанию normal; устаревший алиас critical нормализуется в urgent).
Список своих заявок (изоляция по сотруднику):
POST https://support.tehprof.kz/api/client.php
X-Client-Token: ct_eyJ0Ijox...
{ "action": "list_tickets", "own_only": 1 }
- С
own_only: 1сотрудник видит только свои заявки (созданные им или где он участник). - Без
own_only— заявки всей его компании (поведение клиентского кабинета по умолчанию).
Ответ: { "ok": true, "data": { "items": [...], "total": N, "page": 1, "limit": 20 } }. У каждой заявки есть unread — число непрочитанных ответов (для бейджа).
Ответить в заявку:
POST https://support.tehprof.kz/api/client.php
X-Client-Token: ct_eyJ0Ijox...
{ "action": "add_message", "ticket_id": 10094, "message": "Проблема повторяется и в другом браузере" }
Проверить новые ответы (для опроса/бейджа):
{ "action": "check_updates" }
Другие действия по X-Client-Token: get_ticket (заявка + переписка), update_ticket, reopen_ticket, cancel_ticket, sign_download_url (защищённая ссылка на файл), submit_feedback, get_changelog. Полный список — в машинной спецификации (см. «Связанные материалы»).
Шаг 3 (опционально): встроить готовый кабинет вместо своей вёрстки
Если не хотите рисовать свой список заявок, встройте готовый кабинет Support в iframe — он уже умеет всё (заявки, переписка, файлы, создание):
<iframe src="https://support.tehprof.kz/embed.html?ctoken=ct_eyJ0Ijox...&lang=ru"
style="width:100%;height:100%;border:0"></iframe>
embed.html принимает ctoken и lang (ru/en/kk). Кабинет работает в рамках одного сотрудника, поэтому iframe можно показывать прямо в вашем интерфейсе.
Сценарий 2: операторский API (Bearer)
Если нужно управлять заявками программно со стороны поддержки (боты, массовые операции, аналитика), используйте API-ключ напрямую как Bearer — без ctoken.
POST https://support.tehprof.kz/api/mcp-internal.php
Authorization: Bearer sk_ваш_ключ
Content-Type: application/json
{ "action": "get_tickets", "status": "new", "limit": 20 }
Доступные действия: get_tickets, get_ticket, create_ticket, reply_ticket, update_ticket, analytics_dashboard, analytics_sla, analytics_operators, list_operators, list_channels, get_settings, list_automation_rules, и др.
Права (scope) важны. Каждое действие требует определённого права у ключа:
- чтение (get_tickets,analytics_,list_) → нужен scope read;
- запись (create_ticket,reply_ticket,update_ticket) → scope write;
- выдача клиентских токенов (issue_client_token) → scope write + clients.Ключ только сwrite + clients(как у серверного моста) не сможет читать заявки операторскимget_tickets— вернётся 403. Это сделано намеренно: ключ моста не предназначен для операторского доступа. Если нужны оба сценария — запросите ключ с правамиread + write + clientsили заведите два ключа.
Подключение через MCP (без программирования)
Для AI-ассистентов (Claude Desktop, Claude Code) есть MCP-сервер Support — он оборачивает операторский API в набор инструментов. Это даёт управление поддержкой на естественном языке без написания кода. Адрес и набор инструментов уточняйте у нас — MCP отдаёт tickets_create/get/reply/update/list, аналитику, базу знаний и онбординг-гайды.
Сценарий 3: встраивание интерфейса (JWT) — для внешних SaaS без Bitrix24
Если у вас собственная система идентификации (не Bitrix24), используйте Token API: ваш сервер обменивает API-ключ на JWT для конкретного пользователя, JWT передаётся во встраиваемый интерфейс.
POST https://support.tehprof.kz/api/install-generic.php
X-Api-Key: tps_ваш_ключ
Content-Type: application/json
{ "action": "issue_token", "sub": "user_42", "name": "Иван Петров",
"email": "ivan@company.com", "role": "employee", "exp": 3600 }
Ответ: { "ok": true, "token": "eyJ...", "expires_in": 3600 }. Дальше токен передаётся в embed-sdk.js / iframe. Полное описание Token API, самоподписанного JWT (PHP/Node.js/Python), embed SDK и веб-хуков — в машинной спецификации llms-embed.txt.
Сценарий 4: входной вебхук + синхронизация компаний и контактов
Подходит, когда ваш продукт создаёт заявки от имени своих клиентов и хочет, чтобы каждая заявка попадала под нужную компанию клиента. Сопоставление идемпотентно по вашим стабильным ключам (канон Zendesk/Intercom: external_id): справочник пополняется по мере заявок. Если же нужно заранее связать весь свой справочник с нашими карточками (в том числе тех, кто писал ещё до интеграции) — есть отдельная синхронизация без создания заявок, см. Сценарий 5.
Ключ создаётся в админке: Настройки → Автоматизация → Входящие вебхуки. Передаётся только в заголовке X-Api-Key (query-параметр ?key= не принимается).
POST https://support.tehprof.kz/api/webhook-in.php
X-Api-Key: tps_ваш_ключ
Content-Type: application/json
{
"subject": "Ошибка входа в кабинет",
"description": "Не проходит авторизация.",
"client_name": "Иванов Артём",
"client_phone": "+77001234567",
"client_email": "ivanov@company.kz",
"company_external_id": "ORG-42", // ваш стабильный ID компании (главный ключ)
"company_bin": "123456789012", // БИН/ИИН — запасной ключ для юрлиц
"company_name": "ТОО Ромашка", // имя при создании новой компании
"contact_external_id": "USER-999", // ваш стабильный ID пользователя
"external_ref": "TICKET-2026-0042", // ключ идемпотентности заявки
"category": "other"
}
Порядок на нашей стороне: проверка external_ref (повтор → возврат той же заявки, deduplicated: true) → найти/создать компанию по company_external_id/company_bin → найти/создать контакт по contact_external_id/телефону/почте → связать контакт с компанией → создать заявку, уже привязанную к компании.
Ответ при создании (HTTP 201): { "ok": true, "ticket_id": 4522, "status": "new", "company_id": 1611, "contact_id": 9270 }.
Ответ при повторе (HTTP 200): { "ok": true, "ticket_id": 4522, "status": "new", "deduplicated": true }.
Категория — из списка crm · telephony · whatsapp · tasks · automation · setup · bugfix · other (или задайте категорию по умолчанию при создании вебхука). Лимит: 60 запросов в час с одного IP. Полное описание — в статье «Входящие вебхуки».
Сценарий 5: синхронизация справочника контактов и компаний (без создания заявки)
Подходит, когда у вас уже есть собственный справочник клиентов и вы хотите заранее связать его с нашими карточками по своим стабильным ID (external_id), не дожидаясь, пока человек напишет. После синхронизации, когда клиент обратится, мы сразу узнаем его и его компанию по вашему ID — и в наших карточках будет проставлен ваш идентификатор.
Авторизация — Bearer-ключ с правами clients + write (как в Сценарии 2). Тенант определяется по ключу.
Одна запись — `upsert_contact`
POST https://support.tehprof.kz/api/mcp-internal.php
Authorization: Bearer tps_ваш_ключ
Content-Type: application/json
{
"action": "upsert_contact",
"contact_external_id": "USER-999", // ваш стабильный ID контакта (сильнейший ключ)
"name": "Иванов Артём",
"phone": "+77001234567",
"email": "ivanov@company.kz",
"company_external_id": "ORG-42", // ваш стабильный ID компании
"company_name": "ТОО Ромашка" // имя при создании новой компании
}
Ответ: { "ok": true, "data": { "contact_id": 9270, "company_id": 1611, "status": "created" } } (status: created / updated / skipped).
Много записей за один вызов — `upsert_contacts_bulk` (рекомендуется для большого справочника)
Чтобы не слать тысячи отдельных запросов, отправляйте записи пачками до 500 за вызов:
POST https://support.tehprof.kz/api/mcp-internal.php
Authorization: Bearer tps_ваш_ключ
Content-Type: application/json
{
"action": "upsert_contacts_bulk",
"records": [
{ "contact_external_id": "USER-1", "name": "Иван Петров", "phone": "+77011112233", "company_external_id": "ORG-1", "company_name": "ТОО Альфа" },
{ "contact_external_id": "USER-2", "name": "Анна Сидорова", "email": "anna@beta.kz", "company_external_id": "ORG-2", "company_name": "ТОО Бета" }
]
}
Ответ — построчный отчёт:
{
"ok": true,
"data": {
"processed": 2,
"created": 2, "updated": 0, "skipped": 0,
"errors": [],
"results": [
{ "index": 0, "external_id": "USER-1", "status": "created", "contact_id": 9270, "company_id": 1611 },
{ "index": 1, "external_id": "USER-2", "status": "created", "contact_id": 9271, "company_id": 1612 }
]
}
}
Поведение (оба метода):
- Идемпотентно по вашему
external_id— повторный вызов с тем же ID не создаёт дубль, а обновляет ту же карточку (status: updated). - Сопоставление с уже существующими у нас контактами: ваш
external_id→ телефон → email. Совпавшему контакту просто дописывается ваш ID (включая тех, кто писал до интеграции). - Минимум одно из
contact_external_id / phone / emailобязательно; иначе запись помечаетсяskipped. - В bulk одна плохая запись не отменяет весь пакет — она попадёт в
errors[]/skipped, остальные обработаются. - Заявка не создаётся — это чистая синхронизация справочника (в отличие от Сценария 4).
- Поля-синонимы принимаются:
external_id,client_name,client_phone,client_email,company_bin.
Рекомендованный паттерн для большого справочника: первичная заливка — upsert_contacts_bulk пачками по 200–500 (например, 10 000 компаний = ~20–50 вызовов); дальше — точечный upsert_contact только на изменившиеся записи (не пересылать весь справочник каждый раз).
Как получить API-ключ
API-ключи выдаются только после регистрации и только в настройках принимающей компании в Support:
- Войдите в кабинет Support принимающего тенанта (того, кто будет вести заявки).
- Откройте Настройки → API (раздел управления ключами).
- Создайте ключ, указав нужные права (scope):
read/write/tickets/clients/webhooks.
- Для серверного моста (Сценарий 1) нужны права write + clients.
- Скопируйте ключ сразу — он показывается один раз. Храните в защищённом хранилище (Vault, секреты окружения), никогда не в коде и не в браузере.
Если вы — внешний интегратор и не знаете, в каком тенанте создавать ключ, обратитесь к нам: support.tehprof.kz.
Безопасность (обязательно к соблюдению)
- API-ключ — только на сервере.
mcp-internal.phpпублично доступен для server-to-server интеграций и проверяет Bearer-ключ, его scopes и tenant. Ключ в браузере = компрометация всей поддержки тенанта. - Браузеру отдавайте только пользовательский ctoken/JWT, а для готового виджета используйте сгенерированный код встройки. Не записывайте Bearer API-ключ в URL, HTML или JavaScript.
- Кешируйте ctoken на стороне сервера по ключу «сотрудник» и перевыпускайте за 5 минут до истечения, при ошибке 401 — перевыпуск и повтор.
- Передавайте email при выдаче токена — это помогает корректно связать личность и избежать дублей.
Частые вопросы
Почему `create_ticket` возвращает `err_input_required_fields`, хотя я передал тему и описание?
Скорее всего не передана валидная category. Категория по умолчанию может быть невалидной для принимающей компании. Передавайте category: "other" явно.
Сотрудник видит чужие заявки — почему?
Вы не передали own_only: 1 в list_tickets. Без этого флага возвращаются заявки всей компании сотрудника (так задуман клиентский кабинет). Для персональной изоляции всегда передавайте own_only: 1.
Мой ключ читает заявки оператора — 403. Что не так?
У ключа нет права read. Ключ серверного моста обычно имеет только write + clients. Запросите ключ с read либо отдельный ключ для операторского доступа.
Можно ли вызывать `mcp-internal.php` из браузера?
Нет. Хотя endpoint доступен по публичному HTTPS, Bearer API-ключ является серверным секретом. Все вызовы выполняйте server-to-server со своего бэкенда.
Передаю название и ID компании, но компания не привязывается к заявке
Проверьте, на какой эндпоинт вы шлёте. Серверный мост (issue_client_token) и операторский create_ticket поля компании не принимают — они идентифицируют только человека. Для привязки заявки к компании по вашему стабильному ID используйте Сценарий 4 (входной вебхук webhook-in.php) с полями company_external_id / company_bin / contact_external_id.
В заявке показывается не то имя (например, «Администратор» или «Client»)
Support показывает ровно то имя, которое прислал ваш бэкенд (name / client_name / fullName) — он ничего не выдумывает. Две частые причины:
- Вы шлёте имя служебного админ-аккаунта вашей системы вместо ФИО реального пользователя. Решение — слать настоящее имя того, кто подаёт заявку.
- Имя не перезаписывается у уже существующего контакта. Если первая заявка пришла с «Администратор», контакт останется «Администратор», даже если потом прислать другое имя. Имя у такого контакта правится вручную в карточке контакта в Support, либо заведите отдельные внешние ID (
contact_external_id) для разных людей.
Заранее заводить клиента как «Контакт» не нужно — контакт и компания создаются автоматически при первой заявке.
Связанные материалы
- Подключение Bitrix24 — установка приложения и OAuth для операторов
- Настройка виджета на сайте — простая кнопка чата без разработки
- Машинная спецификация для AI-агентов:
https://support.tehprof.kz/llms-embed.txt - Документация Embed API (человекочитаемая):
https://support.tehprof.kz/embed-docs.html