Тема
Протоколы встреч
Семейство protocols.
norm_protocol_types
Типы встреч компании и подсказки к ним — весь справочник одним ответом, спрашивайте один раз за прогон. Тип распознавайте по aliases детерминированно: совпало написание в названии встречи — передавайте type_id и unit_id типа в запись и применяйте его подсказку. Не совпало — type_id не передавайте, подразделение определяйте по участникам, а подсказку берите у типа из fallback_type_id, если он указан. Режим replace — самостоятельная инструкция, не вкладывайте её в свой каркас. truncated: true у типа — подсказка обрезана ради предела размера ответа, НЕ применяйте её: отрезан конец, где обычно и лежат требования. Пустой массив — у компании нет типов, это не сбой. Доменные состояния: not_ready — типы не настроены; schema_unavailable — источник типов не синхронизирован.
Доступ: чтение · Списковый: нет · Версии контракта: 1
Аргументы
Аргументов нет.
Данные ответа (data)
| Поле | При успехе | Тип | Что это |
|---|---|---|---|
types | да | список MeetingType | |
error | нет | DomainError | Доменное состояние |
fallback_type_id | нет | string |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol-types",
"label": "Типы встреч"
}
],
"freshness": {
"as_of": "2026-09-22T09:30:00.000Z",
"ttl_sec": 3600,
"stale": false
},
"data": {
"types": [
{
"id": "mt-standup",
"name": "Планёрка",
"aliases": [
"планёрка",
"планерка",
"standup",
"дейли"
],
"unit_id": "u-sales",
"membership_kind": "unit",
"hint": {
"text": "В протоколе планёрки обязательны разделы «Решения» и «Поручения» с ответственным и сроком по каждому пункту.",
"mode": "insert"
},
"description": "Короткая встреча отдела по текущим задачам."
},
{
"id": "mt-client",
"name": "Встреча с клиентом",
"aliases": [
"клиент",
"встреча с клиентом",
"презентация"
],
"membership_kind": "pool",
"hint": {
"text": "Протокол встречи с клиентом оформляется письмом клиенту: обращение, договорённости, следующие шаги, подпись менеджера.",
"mode": "replace"
}
},
{
"id": "mt-retro",
"name": "Ретроспектива",
"aliases": [
"ретро",
"retro"
]
}
],
"fallback_type_id": "mt-standup"
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol-types"
}
],
"freshness": {
"as_of": "2026-09-22T09:30:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"error": {
"code": "not_ready",
"message": "Типы встреч не настроены: заведите их в кабинете.",
"retryable": false
}
}
}norm_protocols_list
Протоколы компании страницами, от свежих к старым по дате встречи. Фильтры: from и to — дни встречи включительно; status — одно из значений контракта; unit_id — подразделение по прямому совпадению, без спуска в дочерние; meeting_ids — до 200 идентификаторов встреч: протокол есть в ответе — значит существует, так один вызов заменяет пакетную проверку «обработано ли». Без include_deleted удалённые человеком протоколы не отдаются. Тело протокола в списке не едет — оно велико, берите norm_protocol_get. total — сколько подошло под фильтр до применения страницы. Для следующей страницы передайте page.next_cursor как cursor. Доменное состояние not_ready — протоколы у компании не настроены.
Доступ: чтение · Списковый: да · Версии контракта: 1
Аргументы
| Поле | Обязательно | Тип | Что это |
|---|---|---|---|
cursor | нет | string | |
from | нет | string (date) | |
include_deleted | нет | boolean | |
limit | нет | integer | |
meeting_ids | нет | список string | |
status | нет | ProtocolStatus | Статус протокола |
to | нет | string (date) | |
unit_id | нет | string |
Данные ответа (data)
| Поле | При успехе | Тип | Что это |
|---|---|---|---|
protocols | да | список Protocol | |
total | да | integer | |
error | нет | DomainError | Доменное состояние |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocols:2026-09",
"label": "Протоколы за сентябрь"
}
],
"freshness": {
"as_of": "2026-09-22T09:30:00.000Z",
"ttl_sec": 300,
"stale": false
},
"page": {
"has_more": true,
"next_cursor": "eyJvZmZzZXQiOjJ9"
},
"data": {
"protocols": [
{
"id": "prt-2031",
"meeting_id": "01K9F2QH7T8ZRC4M0X5B2VNJ3D",
"title": "Планёрка отдела продаж 2026-09-21",
"status": "done",
"participant_ids": [
"p-1042",
"p-1077"
],
"deleted": false,
"meeting_date": "2026-09-21",
"organizer_id": "p-1042",
"unit_id": "u-sales",
"type_id": "mt-standup",
"url": "https://records.example.com/prt-2031",
"updated_at": "2026-09-21T11:02:00.000Z"
},
{
"id": "prt-2028",
"meeting_id": "01K9EZZC2P4NM6S1VB8H3TQXWR",
"title": "Встреча с клиентом «Актив»",
"status": "draft",
"participant_ids": [
"p-1042"
],
"participant_emails": [
"s.ilin@example.com"
],
"deleted": false,
"meeting_date": "2026-09-19",
"url": "https://records.example.com/prt-2028"
}
],
"total": 7
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocols"
}
],
"freshness": {
"as_of": "2026-09-22T09:30:00.000Z",
"ttl_sec": 0,
"stale": false
},
"page": {
"has_more": false
},
"data": {
"error": {
"code": "not_ready",
"message": "База протоколов не подключена: настройте её в кабинете.",
"retryable": false
}
}
}norm_protocol_get
Протокол одной встречи по meeting_id целиком: ядро, тело, дополнительные поля, ссылка. Удалённый человеком протокол отдаётся с deleted: true — воссоздавать его нельзя. Тело реализация обрезает так, чтобы ответ уложился в предел размера, и тогда ставит body_truncated: true: обрезанное тело не принимайте за полное. Доменные состояния: no_data — протокола по этой встрече нет, можно создавать (повтор ничего не изменит); not_ready — протоколы не настроены.
Доступ: чтение · Списковый: нет · Версии контракта: 1
Аргументы
| Поле | Обязательно | Тип |
|---|---|---|
meeting_id | да | string |
Данные ответа (data)
| Поле | При успехе | Тип | Что это |
|---|---|---|---|
body_truncated | да | boolean | |
protocol | да | Protocol | Протокол встречи |
error | нет | DomainError | Доменное состояние |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol:01K9F2QH7T8ZRC4M0X5B2VNJ3D",
"label": "Карточка протокола"
}
],
"freshness": {
"as_of": "2026-09-22T09:30:00.000Z",
"ttl_sec": 300,
"stale": false
},
"data": {
"protocol": {
"id": "prt-2031",
"meeting_id": "01K9F2QH7T8ZRC4M0X5B2VNJ3D",
"title": "Планёрка отдела продаж 2026-09-21",
"status": "done",
"participant_ids": [
"p-1042",
"p-1077"
],
"deleted": false,
"meeting_date": "2026-09-21",
"source_url": "https://meet.example.com/rec/01K9F2QH7T8ZRC4M0X5B2VNJ3D",
"organizer_id": "p-1042",
"agenda": "1. Воронка недели. 2. Блокеры по «Активу».",
"unit_id": "u-sales",
"type_id": "mt-standup",
"body": "## Решения\n\n- Перенести демо для «Актива» на 25.09.\n\n## Поручения\n\n- Илин: подготовить смету до среды.",
"url": "https://records.example.com/prt-2031",
"updated_at": "2026-09-21T11:02:00.000Z",
"extra": {
"decision_owner": "p-1042"
}
},
"body_truncated": false
}
}Пример: случай «deleted»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol:01K9EZZC2P4NM6S1VB8H3TQXWR",
"label": "Карточка протокола"
}
],
"freshness": {
"as_of": "2026-09-22T09:30:00.000Z",
"ttl_sec": 300,
"stale": false
},
"data": {
"protocol": {
"id": "prt-2028",
"meeting_id": "01K9EZZC2P4NM6S1VB8H3TQXWR",
"title": "Встреча с клиентом «Актив»",
"status": "draft",
"participant_ids": [
"p-1042"
],
"deleted": true,
"meeting_date": "2026-09-19"
},
"body_truncated": false
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol:01K9G000000000000000000000"
}
],
"freshness": {
"as_of": "2026-09-22T09:30:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"error": {
"code": "no_data",
"message": "Протокола по этой встрече ещё нет: можно создавать.",
"retryable": false
}
}
}norm_protocol_upsert
Создать или переписать протокол встречи: ядро полей плюс тело в markdown. Состав полей задан контрактом — читать схему перед записью не нужно. Идемпотентно по meeting_id: повторный вызов переписывает ТУ ЖЕ карточку (created: false). Тело заменяется целиком, поля ядра объединяются: поля нет во входе — оно не трогается; переданный массив заменяет прежний набор; null у одиночного поля очищает его; внутри extra то же правило по каждому ключу. Статус, который человек поставил в системе компании вне значений контракта, не затирается — поле вернётся в kept_existing; реализация вправе защищать так и другие поля. Запись создаётся ДАЖЕ если обязательное для компании поле пустое — отражайте незавершённость статусом draft, а не отказом. Непринятое поле не отменяет операцию: оно приедет в rejected_fields успешного ответа, там же unresolved_people — почты участников и организатора без учётной записи в системе компании. Идентификаторы людей берите в norm_people_list; тип и подразделение — из norm_protocol_types. Доменные состояния: not_ready — запись протоколов не настроена; record_deleted — карточку удалил человек, воссоздавать нельзя; record_rejected — хранилище отвергло карточку целиком, повтор даст то же; unknown_field — компания не ведёт поле ядра; temporary и rate_limited — повторите позже. Реализация вправе разрешить запись только привилегированным ролям и отвечать unauthorized_scope.
Доступ: запись · Списковый: нет · Версии контракта: 1
Аргументы
| Поле | Обязательно | Тип | Что это |
|---|---|---|---|
body | да | string | |
meeting_id | да | string | |
agenda | нет | string | null | |
extra | нет | object | |
meeting_date | нет | string (date) | |
organizer_email | нет | string | |
organizer_id | нет | string | null | |
participant_emails | нет | список string | |
participant_ids | нет | список string | |
source_url | нет | string (uri) | |
status | нет | ProtocolStatus | Статус протокола |
title | нет | string | |
type_id | нет | string | null | |
unit_id | нет | string | null |
Данные ответа (data)
| Поле | При успехе | Тип | Что это |
|---|---|---|---|
created | да | boolean | |
id | да | string | |
kept_existing | да | список string | |
rejected_fields | да | список RejectedField | |
unresolved_people | да | список string | |
error | нет | DomainError | Доменное состояние |
note | нет | string | |
url | нет | string (uri) |
Пример: успешный ответ
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol:01K9F2QH7T8ZRC4M0X5B2VNJ3D",
"label": "Карточка протокола"
}
],
"freshness": {
"as_of": "2026-09-22T09:31:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"id": "prt-2031",
"created": false,
"url": "https://records.example.com/prt-2031",
"rejected_fields": [
{
"key": "extra.duration",
"reason": "вычисляемое свойство: значение задаёт хранилище"
}
],
"unresolved_people": [
"s.ilin@example.com"
],
"kept_existing": [
"status"
]
}
}Пример: случай «created»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol:01K9EZZC2P4NM6S1VB8H3TQXWR",
"label": "Карточка протокола"
}
],
"freshness": {
"as_of": "2026-09-22T09:31:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"id": "prt-2032",
"created": true,
"url": "https://records.example.com/prt-2032",
"rejected_fields": [],
"unresolved_people": [],
"kept_existing": []
}
}Пример: случай «domain_error»
json
{
"source_refs": [
{
"source": "company-data",
"ref": "protocol:01K9EZZC2P4NM6S1VB8H3TQXWR"
}
],
"freshness": {
"as_of": "2026-09-22T09:31:00.000Z",
"ttl_sec": 0,
"stale": false
},
"data": {
"error": {
"code": "record_deleted",
"message": "Протокол этой встречи удалил человек. Создавать его заново нельзя — это его решение.",
"retryable": false
}
}
}Объекты семейства
Объекты, из которых состоят аргументы и ответы инструментов этого семейства.
MeetingType
Тип встречи. Категория встречи, которую заводит компания: планёрка, ретро, встреча с клиентом. aliases — написания в названиях встреч для детерминированного распознавания. unit_id — подразделение за типом; membership_kind pool — тип объединяет людей из разных подразделений. Нет поля hint — подсказки нет. truncated: true — подсказка обрезана, применять её нельзя.
| Поле | Обязательно | Тип | Что это |
|---|---|---|---|
id | да | string | |
name | да | string | |
aliases | нет | список string | |
description | нет | string | |
hint | нет | MeetingTypeHint | Подсказка типа встречи |
membership_kind | нет | unit | pool | |
truncated | нет | boolean | |
unit_id | нет | string |
MeetingTypeHint
Подсказка типа встречи. Текст, который компания просит учесть в протоколе встречи этого типа. insert — вставка внутрь своего каркаса; replace — самостоятельная инструкция со своим форматом, вкладывать её внутрь каркаса нельзя.
| Поле | Обязательно | Тип |
|---|---|---|
mode | да | insert | replace |
text | да | string |
ProtocolStatus
Статус протокола. draft — черновик, есть незаполненное; done — готов; no_meeting — встречи не было. Значение, поставленное человеком вне этого списка, агент не меняет: сервер оставляет его и называет поле в kept_existing.
Значения: draft, done, no_meeting.
Protocol
Протокол встречи. Карточка итогов одной встречи. id — карточка в системе компании, meeting_id — встреча из norm_meetings_list и ключ идемпотентности. participant_ids — сотрудники из norm_people_list; participant_emails — почты тех, для кого сотрудника не нашлось. deleted — карточку удалил человек. body в списке не отдаётся, в чтении может быть обрезано (смотрите body_truncated). extra — поля, которые компания ведёт сама, та же форма во входе записи.
| Поле | Обязательно | Тип | Что это |
|---|---|---|---|
deleted | да | boolean | |
id | да | string | |
meeting_id | да | string | |
participant_ids | да | список string | |
status | да | ProtocolStatus | Статус протокола |
title | да | string | |
agenda | нет | string | |
body | нет | string | |
extra | нет | object | |
meeting_date | нет | string (date) | |
organizer_id | нет | string | |
participant_emails | нет | список string | |
source_url | нет | string (uri) | |
type_id | нет | string | |
unit_id | нет | string | |
updated_at | нет | string (date-time) | |
url | нет | string (uri) |
RejectedField
Непринятое поле. Поле, которое запись не приняла, и причина. Операция при этом выполнена.
| Поле | Обязательно | Тип |
|---|---|---|
key | да | string |
reason | да | string |