#Бланк приёма

Этот endpoint реализует ваша МИС. Когда врач открывает приём, smartica.ai вызывает этот endpoint и запрашивает бланк и список полей.

#Когда этот endpoint нужен

Только в сценарии Launch и только если вы не передаёте бланк в SSO-запросе.

Ваша ситуация Нужен ли GET
Launch, бланк не передаётся в SSO Да
Launch, template и fields переданы в SSO Нет
Import Нет, никогда. Бланк передаётся при привязке

Если endpoint не нужен, откройте Запись протокола в карту.

#Адрес

Адрес выбираете вы. Согласуйте его при подключении. Рекомендуемый вид:

https://mis.example.ru/api/for-smartica/encounters/{encounter_id}

#Что присылает smartica.ai

GET /api/for-smartica/encounters/12345 HTTP/1.1
Host: mis.example.ru
Authorization: Bearer <токен>
Accept: application/json

Схему авторизации выбираете при подключении. По умолчанию схема — Bearer. Для совместимости возможен HTTP Basic. Подробности в статье Авторизация и ошибки.

12345 — encounter_id, который вы передали в SSO-запросе.

smartica.ai ждёт ответ не дольше 30 секунд. 30 секунд — верхний предел, а не ориентир. Читайте уже готовые данные приёма. Не запускайте здесь тяжёлые вычисления. Не вызывайте внешние сервисы.

#Что должна вернуть ваша МИС

Верните код 200, заголовок Content-Type: application/json; charset=utf-8 и JSON-объект:

{
  "encounter_id": "12345",
  "user_email": "doctor@clinic.ru",
  "template": "Кардиолог",
  "fields": [
    { "id": "complaints", "label": "Жалобы" },
    { "id": "anamnesis_life", "label": "Anamnesis vitae (анамнез жизни)" },
    { "id": "diagnosis_primary", "label": "Диагноз (основной)" }
  ]
}
Поле Тип Что в нём
encounter_id строка Должен совпадать с ID из адреса и из SSO-запроса
user_email строка Email врача, который ведёт этот приём
template строка Непустое стабильное название бланка или специальности
fields массив Непустой список полей протокола
fields[].id строка Непустой, уникальный, неизменный технический ключ
fields[].label строка Заголовок для заполнения. Если подпись зависит от раздела выше, опишите поле целиком
fields[].type строка Необязательно. Без type поле считается текстом. Остальные типы описаны в статье Типы полей бланка

smartica.ai примет ответ без encounter_id в теле и возьмёт ID из адреса. Ответ без user_email smartica.ai тоже примет. Пропуск этих полей оставлен для совместимости со старыми подключениями. В новой интеграции возвращайте оба поля. По этим полям smartica.ai вовремя замечает, что приём и врач не совпадают с ожидаемыми.

На этот запрос smartica.ai отвечает врачу, а не вам. Предупредить о дубликате в ответе некуда. Если в бланке есть поля с одинаковым id, smartica.ai возьмёт первое вхождение и молча пропустит остальные. Правило описано в статье Глоссарий.

#Пример обработчика

Код не привязан к фреймворку. repository — ваш слой доступа к данным. urlId приходит из маршрута. Считайте авторизацию уже проверенной.

$encounter = $repository->findByExternalId($urlId);

if ($encounter === null) {
    return jsonResponse(404, ['message' => 'Приём не найден']);
}

$fields = [];

foreach ($encounter->form->fields as $field) {
    $fields[] = [
        'id' => $field->key,      // стабильный и уникальный
        'label' => $field->title, // заголовок для заполнения smartica.ai
    ];
}

return jsonResponse(200, [
    'encounter_id' => (string) $encounter->externalId,
    'user_email' => $encounter->doctor->email,
    'template' => $encounter->form->name,
    'fields' => $fields,
]);
const encounter = await repository.findByExternalId(urlId);

if (!encounter) {
  return res.status(404).json({ message: 'Приём не найден' });
}

res.json({
  encounter_id: String(encounter.externalId),
  user_email: encounter.doctor.email,
  template: encounter.form.name,
  fields: encounter.form.fields.map((field) => ({
    id: field.key,      // стабильный и уникальный
    label: field.title, // заголовок для заполнения smartica.ai
  })),
});
encounter = repository.find_by_external_id(url_id)

if encounter is None:
    return json_response(404, {"message": "Приём не найден"})

return json_response(200, {
    "encounter_id": str(encounter.external_id),
    "user_email": encounter.doctor.email,
    "template": encounter.form.name,
    "fields": [
        {
            "id": field.key,      # стабильный и уникальный
            "label": field.title, # заголовок для заполнения smartica.ai
        }
        for field in encounter.form.fields
    ],
})
var encounter = await repository.FindByExternalIdAsync(urlId);

if (encounter is null)
{
    return Results.Json(new { message = "Приём не найден" }, statusCode: 404);
}

var fields = encounter.Form.Fields
    .Select(field => new
    {
        id = field.Key,     // стабильный и уникальный
        label = field.Title // заголовок для заполнения smartica.ai
    })
    .ToArray();

return Results.Json(new
{
    encounter_id = encounter.ExternalId.ToString(),
    user_email = encounter.Doctor.Email,
    template = encounter.Form.Name,
    fields
});
Encounter encounter = repository.findByExternalId(urlId);

if (encounter == null) {
    return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(Map.of("message", "Приём не найден"));
}

List<Map<String, String>> fields = encounter.getForm().getFields().stream()
        .map(field -> Map.of(
                "id", field.getKey(),     // стабильный и уникальный
                "label", field.getTitle() // заголовок для заполнения smartica.ai
        ))
        .toList();

return ResponseEntity.ok(Map.of(
        "encounter_id", String.valueOf(encounter.getExternalId()),
        "user_email", encounter.getDoctor().getEmail(),
        "template", encounter.getForm().getName(),
        "fields", fields
));
Функция EncounterGET(Запрос)

    ИдентификаторИзURL = Запрос.ПараметрыURL["id"];
    Приём = Приёмы.НайтиПоВнешнемуИдентификатору(ИдентификаторИзURL);

    Если Приём = Неопределено Тогда
        Возврат ОтветСОшибкой(404, "Приём не найден");
    КонецЕсли;

    Поля = Новый Массив;
    Для Каждого Поле Из Бланки.ПолучитьПоля(Приём.Бланк) Цикл
        Элемент = Новый Структура("id, label", Поле.Ключ, Поле.Наименование);
        Поля.Добавить(Элемент);
    КонецЦикла;

    Результат = Новый Структура;
    Результат.Вставить("encounter_id", ИдентификаторИзURL);
    Результат.Вставить("user_email", Приём.Врач.Email);
    Результат.Вставить("template", Приём.Бланк.Наименование);
    Результат.Вставить("fields", Поля);

    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    ЗаписатьJSON(Запись, Результат);

    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    Ответ.УстановитьТелоИзСтроки(Запись.Закрыть());

    Возврат Ответ;

КонецФункции

Если в базе encounter_id хранится числом, приведите его к строке. Без преобразования в JSON уйдёт число 12345 вместо строки "12345".

#Правила encounter_id и user_email

  • Передавайте encounter_id в теле и в адресе одинаково, посимвольно.
  • Передавайте ID строкой, даже если в базе ID хранится числом.
  • Передавайте user_email врача, который вошёл через SSO.
  • smartica.ai не учитывает регистр email.
  • Если email не совпал, smartica.ai фиксирует предупреждение. В строгой конфигурации при несовпадении smartica.ai блокирует обработку.

Несовпадение email встречается часто. Оно возникает, когда в карточке приёма записан один врач, а кнопку нажал другой, например ординатор или дежурный. Решите на стороне МИС, чей email считать верным. Передавайте этот email одинаково в SSO и в GET.

#Правила template

template — название бланка или специальности. Передавайте его так, как в примерах ниже.

Хорошие примеры:

Значение Когда использовать
"Кардиолог" Один общий бланк кардиолога
"Первичный приём педиатра" Отдельный бланк первичного приёма
"Повторный приём педиатра" Другой набор или другой смысл полей
"УЗИ органов брюшной полости" Специализированный протокол исследования

Два правила:

  1. Для одного бланка всегда возвращайте одно и то же значение. Не меняйте регистр, язык и синонимы от приёма к приёму.
  2. Разделяйте разные бланки разными названиями. Если первичный и повторный приём отличаются составом полей, верните два разных значения template.

#Правила fields

id нужен вашей МИС. label нужен smartica.ai.

id — технический ключ. По id вы разложите пришедшие значения обратно по своим полям. smartica.ai вернёт id без изменений.

label — заголовок для заполнения smartica.ai. По заголовку smartica.ai решает, какие факты из разговора записать в поле. Обычно заголовок совпадает с подписью поля на бланке. Если подпись понятна только вместе с разделом выше, опишите поле целиком. Плохой заголовок даёт плохое заполнение. Кроме label можно передать type, section и hint. Правила этих атрибутов описаны в статье Типы полей бланка.

Требования:

  1. Возвращайте минимум одно поле.
  2. Сделайте каждый id уникальным внутри ответа.
  3. После запуска интеграции не меняйте id существующего поля. Смена id ломает сопоставление.
  4. Передайте type, если поле хранит не свободный текст. Без type smartica.ai считает поле текстом. Правила типов описаны в статье Типы полей бланка.
  5. Сделайте label понятным без окружающего бланка. Если подпись зависит от раздела выше, включите раздел в label или передайте его в section.

Примеры:

Оценка id label Почему
Хорошо "complaints" "Жалобы" Назначение однозначно
Хорошо "objective_status" "Объективный статус (status praesens)" Есть медицинский контекст
Хорошо "diagnosis_primary" "Диагноз (основной)" Не спутать с сопутствующим
Плохо "field_3" "Статус" Ни ключ, ни название не объясняют смысл
Плохо "1" "Данные" Невозможно понять, что класть в поле
Плохо "norm" "Норма" Подпись понятна только внутри раздела «Объективный статус»

Если в бланке есть похожие поля, различайте их в названии явно. Не "Диагноз" и "Диагноз 2", а "Диагноз (основной)" и "Диагноз (сопутствующий)".

Максимум 80 полей в одном бланке. Остальные ограничения описаны в статье Лимиты.

#Не добавляйте демографические данные

Если отдельного согласования нет, не добавляйте в ответ ФИО пациента, номер карты, телефон, адрес, дату рождения и другие демографические поля.

smartica.ai работает с содержанием разговора. Привязка к пациенту остаётся у вас. Используйте для привязки свой encounter_id. Дополнительные персональные данные ничего не улучшат. Они увеличат объём передаваемых чувствительных данных.

Подробности в статье Защита данных.

#Ошибки

Возвращайте подходящий код и JSON с безопасным сообщением:

{
  "message": "Приём не найден"
}
Код Когда использовать
401 Учётные данные отсутствуют или неверны
403 Учётные данные верны, но доступ к этому ресурсу запрещён
404 Приём с таким ID не найден
409 Приём существует, но находится в состоянии, несовместимом с интеграцией
422 ID корректен по формату, но запрос нельзя обработать
5xx Временная ошибка на вашей стороне

Любой ответ не из диапазона 2xx, timeout, пустое тело или невалидный JSON означают, что подготовка приёма не удалась. Врач не сможет начать запись.

Автоматический повтор не гарантирован. Когда вы исправите endpoint, врачу достаточно открыть приём заново.

Не помещайте в message стектрейсы, SQL-запросы, внутренние пути и секреты. Текст ошибки может быть показан пользователю. Текст сохраняется для диагностики.

#Проверьте ответ через curl

curl --fail-with-body --silent --show-error \
  --header 'Authorization: Bearer ЗАМЕНИТЕ-НА-ТОКЕН' \
  --header 'Accept: application/json' \
  'https://mis.example.ru/api/for-smartica/encounters/12345'

Убедитесь, что ответ:

  • имеет код 200.
  • содержит Content-Type: application/json.
  • разбирается как JSON-объект.
  • содержит непустые template и fields.
  • не меняет id и названия полей между двумя одинаковыми запросами.

Если состав полей меняется от запроса к запросу, сопоставление результата сломается.

Проверяйте с внешней машины. Из внутренней сети проблему с доступностью или сертификатом можно не заметить.

#Связанные статьи

← Все статьи: Интеграция с МИС Поиск по базе знаний