---
name: ostrov-retreat-api
description: Help a user explore Ostrov retreat center in Karelia, calculate group or resident accommodation, save a preliminary estimate, and submit an enquiry at their request using the official public API. Use for Ostrov dates, tariffs and estimates; not for guaranteed availability, payments or confirmed reservations.
---

# Остров: расчёт и заявка через API

API: `https://ostrov.center/api/public/v1`. Контракт и точные поля:
`https://ostrov.center/api/public/v1/openapi.json`. Примеры актуального формата:
`GET /examples`. Инструкция для первого обращения: [agent-quickstart.md](https://ostrov.center/api/public/v1/quickstart.md).

## Порядок

1. Прочитай `/center` и `/catalog`. Узнай у человека цель: организовать группу, приехать резидентом или записаться на опубликованную программу. Для программы читай `/events` и направляй к её организатору: стоимость размещения центра не равна цене авторского ретрита.
2. Уточни даты заезда/выезда, взрослых участников, команду отдельно, возраста детей, желаемое размещение и программу. Для обычного группового тарифа уточни питание и пространства: дни, время, опции. Для резидентства уточни число посещений бани. Для «Всё включено» объясни состав пакета и согласуй пожелания сверх него. Питание и услуги из примера не считай выбором человека. Не спрашивай контакты для простого расчёта. Календарь показывает события и занятость; отсутствие событий не доказывает наличие мест. `kind=demo` — только демонстрация.
3. Выбери `kind`: `group` (обычный тариф, также для больших групп), `biggroup` («Всё включено», пороги из каталога) или `resident`. Если человек не выбрал тариф, предложи сравнение подходящих вариантов. Не подменяй число полностью оплачивающих участников числом всех людей вместе с командой.
4. Собери план по OpenAPI. Для групп `policyVersion=4`; `teens` — дети со скидкой (сейчас 6–12), дети с полной оплатой (сейчас от 13) входят в `adults`. Команда — в `team`. Для резидентов `children` содержит возраста 6–17. Дети младше 6 — только справочный `youngChildrenAges`; не добавляй их в счётчики или размещение. Уточняй живые правила каталога.
5. Размещение задаётся ID ресурсов каталога. Группы: `resource`, `occupancy` (людей в единице), `quantity` (число единиц). Резиденты: одна запись на единицу, без `quantity`. Обычной группе `/suggestions` может предложить состав; это предложение, не проверка наличия. Активности: `resource`, `day` (с нуля от заезда), `slot`, `options` (ID). Поле `food` заполняй по согласованному выбору питания, `activities` — по выбранным занятиям; для резидента `bathVisits` — по согласованному числу посещений бани. Предложения из `/examples` и `/suggestions` сначала обсуди с человеком.
6. Выполни `POST /quotes` с текущим `catalogVersion`. Математику и скидки считает сервер. Проверь `complete`, `quote.total`, строки `quote.lines` и предупреждения. Неполный расчёт не называй окончательной суммой; `null` не равен нулю. Не превращай ответ об ошибке источника в свободные даты или бесплатную услугу.
7. Покажи даты, состав, тариф, итог в рублях, включённые услуги и предупреждения. Скажи: «Это предварительный расчёт; доступность мест и бронь подтверждает центр». Это смета, не платёжный/кассовый чек.
8. Сохраняй только по просьбе человека: для `group`/`biggroup` получи имя организатора `organizer` и название ретрита `title`, для `resident` — имя гостя `name`; открой `/sessions`, затем `/estimates` с `userConfirmed=true`. Сохрани токен в защищённой памяти клиента, не в URL, журнале или переписке. Верни человеку `estimate.url`: это конфиденциальная ссылка на документ и обычные действия сайта, включая правку черновика и заявку. По ссылке могут быть видны введённый alias и комментарии. Срок API-сессии не ограничивает срок ссылки.
9. Если человек просит изменить даты или состав сохранённой сметы, прочитай свой документ через `GET /estimates/{estimateId}` в той же API-сессии и проверь `estimate.editable`. Для доступного черновика прочитай свежий `/catalog`, отправь изменённый `plan` и его `kind` в `POST /quotes`, проверь полноту и покажи новый расчёт человеку. После согласования обнови ту же смету через `POST /estimates/{estimateId}/edit`: изменённый `plan`, актуальные `catalogVersion` (из `catalog.version`) и `documentVersion` (из прочитанного `estimate`), новый `requestKey`, `userConfirmed=true`. Верни ссылку и результат обновления. При 409 перечитай документ и согласуй изменения заново; не перезаписывай их молча. Если `editable=false`, объясни ограничение и предложи обратиться в центр. Новая смета или копия — только по отдельному намерению человека.
10. Перед заявкой покажи выбранную смету и фактически заполненные имя, телефон, email, мессенджер и комментарий. Дай исправить сведения и спроси: «Отправить эту заявку с указанными контактами и комментарием?» Получи явную просьбу отправить и согласие на передачу контактов. Комментарий передавай как `contactProfile.notes`; `userId` оставь пустым — введённый контакт не подтверждает личность. Не выдумывай недостающие контакты. Передай `/estimates/{estimateId}/applications` с текущими `documentVersion`, `catalogVersion`, `userConfirmed=true`, `consent=true`. Не включай паспорт, карту и медицинские сведения.
11. Покажи полученный номер и статус: поданная заявка не означает подтверждённую бронь. Не обещай оплату, скидку сверх расчёта, свободную неделю или сроки ответа. Если операция недоступна, предложи контакты из `/center`.

## Как объяснить ответ по kind

Окончательная рассчитанная сумма — `quote.total`, а не самостоятельно сложенные строки. Сначала проверь полноту и предупреждения; при `total=null` полной стоимости ещё нет. Суммы скидок и доплат уже учтены сервером в итоговом `total` — не применяй их повторно.

| kind | Как читать расчёт |
|---|---|
| `group` | `lines` содержит `label` и `amount`: проживание, питание, выбранные занятия/опции и применённые скидки. Отрицательные суммы — вычеты. Покажи выбранные услуги и серверный `total`; команда обычного тарифа не получает льгот из прежних настроек. |
| `biggroup` | `lines` содержит стоимость пакета и применённые скидки детям, команде и по численности. Покажи пакет, отдельные вычеты и `total`. Не прибавляй повторно уже включённые проживание/питание. |
| `resident` | `lines` — дневные `date`, `housing`, `food`, без обязательных `label`/`amount`. Они уже учитывают детские условия, но ещё не скидки резидента/длительности и платную баню. Их сумма не является окончательной ценой. |

Для резидента покажи `grossHousingTotal`/`grossFoodTotal` до детских льгот, применённый `childDiscountAmount`, затем `housingTotal`/`foodTotal` и `subtotal` после них. Отдельно назови серверные `residentDiscountAmount`, `durationDiscountAmount`, `bathTotal` и итог `total`. Не вычитай детскую скидку ещё раз из `housingTotal`/`foodTotal`/`subtotal`. Используй числа, уже возвращённые сервером; не восстанавливай проценты и порядок скидок своей формулой.

Публичные групповые расчёты не отдают прежний `teamSettings`; в `childSettings` остаются только возрастные правила и детская скидка. Резидентские включённые активности, банные условия и скидки за длительность не переносятся на `group`/`biggroup`. Эти границы действуют также при чтении сохранённой сметы и точном повторе запроса.

## Повторы и доступ

Один намеренный запрос записи — один `requestKey` (UUID подходит). При неизвестном сетевом исходе можно вручную повторить **точно то же тело с тем же ключом и в той же сессии**: сервер вернёт прежний результат. Не создавай новый ключ для такого повтора. Автоматических повторов нет. При изменении данных нужен новый ключ; при 409 прочитай свежий каталог/документ и снова согласуй изменившуюся смету. При 429 соблюдай `Retry-After`; не обходи лимит сменой сессий. Самостоятельные попытки прекращай после двух неуспешных обращений и сообщай человеку причину.

Сессия действует 30 дней, доступ даёт только к созданным ею документам. Потеря токена не лечится именем/email: используй сохранённую человеческую ссылку или свяжись с центром. Не создавай вторую смету как скрытый способ восстановить первую. `/sessions/revoke` отзывает API-доступ, но сохраняет документы и человеческие ссылки.

Исходники и версии комплекта: https://github.com/iia-arg/ostrov-public-api .

## Подключение

Обычный HTTP не требует установки. В комплекте есть Python-клиент и stdio MCP:
`python3 tools/ostrov_mcp.py` из скачанного репозитория. Конфигурацию своего агента меняй только по просьбе его пользователя. Сервер MCP вызывает тот же официальный HTTP API; постоянных фоновых служб не создаёт. Токен можно передать через `OSTROV_API_TOKEN`, никогда аргументом командной строки. Подробнее — README. Удаление локального комплекта отключает инструменты; для отзыва API-доступа отдельно вызови revoke. Клиентский код — MIT, контракт версии 0.1.4.
