Открытый APIверсия 26.11.2
Документация · Bounty API — пользователи
Открытый API гостя: поиск и карта, карточки объектов пяти категорий, афиша раздела «События», бронирование, долгосрочная аренда, чат, отзывы, профиль.
178 эндпоинтов26 разделовhttps://api.bounty.travel/v1
Разделы и поиск · 26
Как пользоваться
Вход не нужен для каталога, карты, афиши и карточек: их обязан видеть любой посетитель. Регистрация требуется там, где появляется он сам — бронирование, переписка, избранное, документы.
Этим же API пользуются веб-клиент, Android, iOS и Telegram-бот: у них один контракт и один набор строк локализации.
Общие правила
Версия — в пути. Все эндпоинты начинаются с /v1. Ломающие изменения выходят новой версией пути, а не правкой текущей.
Аутентификация — Authorization: Bearer <access>. Токен выдаёт POST /v1/auth/login; он живёт 15 минут, обновляется по refresh-токену через POST /v1/auth/refresh. Обмен отдаёт свежий access и тот же refresh, а срок сессии сдвигается: сессия держится, пока ей пользуются. Выход и «выйти везде» закрывают сессию сразу.
Токен одного API никогда не принимается другим. У каждой аудитории свой секрет подписи, а не только claim aud: чужой токен не проходит проверку подписи, а не проверку прав.
Ответы и ошибки
Успех — тело эндпоинта как есть. Ошибка — всегда один и тот же конверт:
{
"error": {
"code": "validation_error",
"message": "Дата выезда должна быть позже даты заезда",
"details": {"field": "date_to"},
"request_id": "0f1c…"
}
}
code — машинный, по нему и нужно ветвиться. message — для человека, он может меняться. request_id есть в каждом ответе и в заголовке X-Request-Id: с ним обращение в поддержку находит запрос в журнале за секунды.
Коды: 400 validation_error, 401 unauthorized, 403 forbidden, 404 not_found, 409 conflict, 410 gone, 422 unprocessable (данные верны, но действие сейчас невозможно — например, объект не готов к публикации), 429 rate_limited (с заголовком Retry-After), 500 internal_error, 502 upstream_unavailable (не ответил внешний сервис — повторите позже). Ошибка разбора тела или параметров — всегда 400 validation_error с полями в details.fields, а не 422.
Списки
Пагинация курсорная, OFFSET не используется нигде:
{"items": [...], "next_cursor": "eyJ…", "has_more": true}
next_cursor непрозрачен — собирать его руками нельзя, его форма не часть контракта. Нет next_cursor — страница последняя.
Повторы и идемпотентность
Создающие запросы принимают заголовок Idempotency-Key. Повтор с тем же ключом возвращает тот же результат, а не заводит вторую запись. Ключ живёт 24 часа.
Частота
Лимиты считаются по адресу и по актёру. Превышение — 429 с Retry-After в секундах. Клиент обязан ждать указанное время, а не повторять сразу.
Время, деньги и языки
- Время объекта — в его часовом поясе и в UTC не переводится никогда. Календарные даты (заезд, выезд, день события) — это
dateв поясе объекта. Моменты —timestamptzв UTC. - Деньги — в минорных единицах (
price_minor) вместе с кодом валюты. Суммы никогда не приходят от клиента: их считает сервер. - Язык ответа — заголовок
Accept-Languageили параметрlang. Языки:en(по умолчанию),ru,th,zh-Hans. Непереведённая строка отдаётся по-английски, а переведённый контент помечается пометкой о переводе.
Особенности этого API
- Поиск по месту — строкой, а не фильтром. Параметра
place_idнет: район и город приходят вqи сверяются с названием, описанием и местом объекта на всех языках сразу, по словам. - Realtime — WebSocket
/v1/ws: переписка, уведомления, Bounty AI. Вход, кадры и события — раздел «Сокет/v1/ws» ниже. - Фотографии — до трёх размеров (
thumb480,medium1600,large2560).largeсуществует не всегда; клиент обязан пережить его отсутствие и показатьmedium.
Сокет /v1/ws
Swagger сокетов не показывает, поэтому всё о нём — здесь. Адрес: wss://api.bounty.travel/v1/ws?token=… или …?ticket=…. Заголовок Authorization браузерному WebSocket не поставить, поэтому вход — параметром адреса:
token— токен доступа (приложения и боты).ticket— одноразовый билет изPOST /v1/auth/ws-ticketдля веб-страницы, у которой токена нет (он в cookieHttpOnly): живёт минуту и открывает один сокет.
Почта должна быть подтверждена — иначе соединение закрывается так же, как с плохим токеном.
Отказ во входе — закрытие с кодом 1008: обновите токен или возьмите новый билет, а не переподключайтесь по кругу.
Кадр — JSON в обе стороны: {"event": "…", "payload": {…}, "ts": "…"}. ts ставит сервер. Время внутри payload может прийти и как 2026-10-14 11:18:22.300148+00:00 (через пробел) — читайте оба вида.
События сервера
| Событие | Когда | payload |
|---|---|---|
message.new | новое сообщение в переписке, в том числе служебное и своё с другого устройства | сообщение, как в GET /v1/dialogs/{id}/messages |
message.read | собеседник прочитал | {dialog_id, up_to_id} |
message.translated | готов перевод сообщения на язык получателя | {dialog_id, message_id, lang, text} |
message.deleted | сообщение убрано из переписки | {dialog_id, message_id} |
typing | собеседник печатает | {dialog_id} |
notification.new | новое уведомление в ленте | уведомление, как в GET /v1/notifications |
assistant.message | сообщение Bounty AI появилось или изменилось: готов ответ, расшифровка голосового | сообщение помощника, как в GET /v1/assistant/messages |
assistant.status | стадия ответа помощника | {message_id, stage}: transcribing, thinking, searching, writing |
pong | ответ на ping | {} |
Команды клиента
| Событие | Что делает | payload |
|---|---|---|
message.send | отправить сообщение | dialog_id, text или upload_id, reply_to_id?, listing_id? (карточка объекта) |
message.read | пометить прочитанным | {dialog_id, up_to_id?} — без up_to_id всё |
typing | «печатает», в базе не хранится | {dialog_id} |
ping | держать соединение | раз в 30 секунд, иначе прокси рвёт простаивающее соединение |
Правила
- Права и лимиты у команд — те же, что у REST. Отказ (нет прав, чужой диалог, лимит, закрытая переписка) кадром не приходит и соединение не рвёт: команда просто не выполняется. Отправленное видно по
message.new; нужен ответ с кодом ошибки — шлитеPOST /v1/dialogs/{id}/messages. - Неизвестная команда пропускается молча.
- Файлы по сокету не летят: сначала
POST /v1/uploads, затемmessage.sendсupload_id. - Доставка не гарантируется. После переподключения или если сокет не открывается вовсе догоняйте пропущенное
GET /v1/dialogs/{id}/messages?after_id=…. - Разрыв — повтор с паузой 1 → 2 → 4 → 8 секунд, не дольше 30.
Ничего не нашлось — попробуйте путь (/v1/bookings) или метод (POST)
Аутентификация
16 эндпоинтовРегистрация, вход, подтверждение почты, восстановление пароля, обновление пары токенов и билет на сокет. Вход: POST /v1/auth/login → access (15 минут) и refresh (при обмене остаётся тем же). На стенде входят только почты из списка стенда. Капча — по требованию сервиса (captcha_required): ползунок-пазл модуля captcha, в теле — captcha_id и captcha_answer.
POST/v1/auth/form-pass
Нужен ли ползунок — при открытии формы входа, регистрации, восстановления
Без входа
То же решение, что сайт принимает при отрисовке своей формы: чистому клиенту — пропуск на полчаса (стоит очко подозрения, живой renew возвращается бесплатно), под подозрением — null, и приложение показывает ползунок сразу, а не после первого «Войти». Пропуск уходит с формой заголовком X-Form-Pass; метка доверенного устройства — X-Device-Trust. Счётчик недоступен — null: ползунок, а не дверь без замка.
Тело запросаFormPassRequest или null · application/json
Ответы
200Успешный ответ · FormPassResponse
Поля ответа · 1
form_pass
string или null
обязательно
Пропуск на полчаса — ползунок не нужен, пропуск уходит заголовком X-Form-Pass с формой. null — показать ползунок сразу
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/form-pass' \
-H 'Content-Type: application/json' \
-d '{"renew": ""}'
GET/v1/auth/email-availability
Свободен ли адрес — подсказка прямо в форме регистрации
Без входа
Под жёстким лимитом: без него это готовая проверялка «есть ли у вас аккаунт на Bounty» для чужих списков адресов.
Параметры
email
запрос · string
обязательно
Адрес почты
Ответы
200Успешный ответ · EmailAvailabilityResponse
Поля ответа · 1
available
boolean
обязательно
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/auth/email-availability'
POST/v1/auth/register
Регистрация: имя, фамилия, почта, пароль
Без входа
Тело запросаRegisterRequest · application/json
captcha_id
string
по умолчанию ""
Номер задачи капчи — ползунка-пазла, который выдаёт модуль капчи
captcha_answer
string
по умолчанию ""
Ответ на задачу капчи
first_name
string
обязательно
last_name
string
обязательно
email
string (email)
обязательно
Адрес почты
password
string
обязательно
Пароль
accept_terms
boolean
обязательно
Согласие с условиями — без него регистрации нет
marketing_opt_in
boolean
по умолчанию false
Согласие на рассылки. По умолчанию выключено
Ответы
201Успешный ответ · TokenPairResponse
Поля ответа · 6
access_token
string
обязательно
Короткий токен для заголовка Authorization: Bearer …
refresh_token
string
обязательно
Долгий токен обмена: POST /v1/auth/refresh даёт по нему новый access
token_type
string
по умолчанию "Bearer"
expires_in
integer
обязательно
Сколько секунд живёт access-токен
session_id
string (uuid)
обязательно
Идентификатор сессии (UUID)
device_trust
string или null
Метка доверенного устройства на 90 дней — только в ответах входа и регистрации. Приложение хранит её и присылает заголовком X-Device-Trust к формам входа: с ней пороги капчи вдвое выше. Сайт ставит свою cookie сам
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/register' \
-H 'Content-Type: application/json' \
-d '{"first_name": "…", "last_name": "…", "email": "anna@example.com", "password": "…", "accept_terms": false}'
POST/v1/auth/confirm-email
Подтверждение адреса по ссылке из письма
Без входа
Тело запросаConfirmEmailRequest · application/json
token
string
обязательно
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/confirm-email' \
-H 'Content-Type: application/json' \
-d '{"token": "…"}'
POST/v1/auth/resend-confirmation
Выслать письмо с подтверждением заново
Нужен вход
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/resend-confirmation' \
-H 'Authorization: Bearer <access>'
POST/v1/auth/login
Вход по почте и паролю
Без входа
Тело запросаLoginRequest · application/json
captcha_id
string
по умолчанию ""
Номер задачи капчи — ползунка-пазла, который выдаёт модуль капчи
captcha_answer
string
по умолчанию ""
Ответ на задачу капчи
email
string (email)
обязательно
Адрес почты
password
string
обязательно
Пароль
Ответы
200Успешный ответ · TokenPairResponse
Поля ответа · 6
access_token
string
обязательно
Короткий токен для заголовка Authorization: Bearer …
refresh_token
string
обязательно
Долгий токен обмена: POST /v1/auth/refresh даёт по нему новый access
token_type
string
по умолчанию "Bearer"
expires_in
integer
обязательно
Сколько секунд живёт access-токен
session_id
string (uuid)
обязательно
Идентификатор сессии (UUID)
device_trust
string или null
Метка доверенного устройства на 90 дней — только в ответах входа и регистрации. Приложение хранит её и присылает заголовком X-Device-Trust к формам входа: с ней пороги капчи вдвое выше. Сайт ставит свою cookie сам
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/login' \
-H 'Content-Type: application/json' \
-d '{"email": "anna@example.com", "password": "…"}'
POST/v1/auth/refresh
Обмен refresh-токена на новую пару
Без входа
Капчи здесь нет намеренно: обновление происходит в фоне, без участия человека, и показать ему картинку в этот момент невозможно.
Тело запросаRefreshRequest · application/json
refresh_token
string
обязательно
Долгий токен обмена: POST /v1/auth/refresh даёт по нему новый access
Ответы
200Успешный ответ · TokenPairResponse
Поля ответа · 6
access_token
string
обязательно
Короткий токен для заголовка Authorization: Bearer …
refresh_token
string
обязательно
Долгий токен обмена: POST /v1/auth/refresh даёт по нему новый access
token_type
string
по умолчанию "Bearer"
expires_in
integer
обязательно
Сколько секунд живёт access-токен
session_id
string (uuid)
обязательно
Идентификатор сессии (UUID)
device_trust
string или null
Метка доверенного устройства на 90 дней — только в ответах входа и регистрации. Приложение хранит её и присылает заголовком X-Device-Trust к формам входа: с ней пороги капчи вдвое выше. Сайт ставит свою cookie сам
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/refresh' \
-H 'Content-Type: application/json' \
-d '{"refresh_token": "…"}'
POST/v1/auth/ws-ticket
Одноразовый билет для подключения к /v1/ws
Нужен вход
Почта подтверждена
Нужен веб-клиенту: у страницы токена нет вовсе — он в cookie HttpOnly, и заголовок Authorization браузерному WebSocket не поставить. Билет живёт минуту, гасится при первом использовании и не открывает ничего, кроме сокета.
Приложениям он не нужен: у них есть токен, и они шлют его параметром.
Билет требует подтверждённой почты: сокет ведёт в переписку и уведомления, а они закрыты до подтверждения. Сам сокет проверяет это ещё раз — приложение приходит туда с токеном, минуя билет.
Ответы
200Успешный ответ · WsTicketResponse
Поля ответа · 2
ticket
string
обязательно
expires_in
integer
обязательно
Сколько секунд билет действителен
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/ws-ticket' \
-H 'Authorization: Bearer <access>'
POST/v1/auth/logout
Выход: текущая сессия завершается
Нужен вход
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/logout' \
-H 'Authorization: Bearer <access>'
POST/v1/auth/logout-all
Выход на всех устройствах, кроме текущего
Нужен вход
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/logout-all' \
-H 'Authorization: Bearer <access>'
GET/v1/auth/sessions
Список устройств, с которых выполнен вход
Нужен вход
Ответы
200Успешный ответ · массив SessionResponse
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/auth/sessions' \
-H 'Authorization: Bearer <access>'
POST/v1/auth/password-reset/request
Запрос ссылки на смену пароля
Без входа
Всегда 202, независимо от того, есть такой аккаунт или нет: разные ответы превратили бы форму в проверялку списков адресов.
Тело запросаPasswordResetRequest · application/json
captcha_id
string
по умолчанию ""
Номер задачи капчи — ползунка-пазла, который выдаёт модуль капчи
captcha_answer
string
по умолчанию ""
Ответ на задачу капчи
email
string (email)
обязательно
Адрес почты
Ответы
202Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/password-reset/request' \
-H 'Content-Type: application/json' \
-d '{"email": "anna@example.com"}'
POST/v1/auth/password-reset/confirm
Установка нового пароля по ссылке из письма
Без входа
Все сессии завершаются: пароль меняют, когда подозревают утечку.
Тело запросаPasswordResetConfirm · application/json
token
string
обязательно
password
string
обязательно
Пароль
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/password-reset/confirm' \
-H 'Content-Type: application/json' \
-d '{"token": "…", "password": "…"}'
POST/v1/auth/password/change
Смена пароля изнутри аккаунта. Текущая сессия остаётся жить
Нужен вход
Тело запросаPasswordChangeRequest · application/json
current_password
string
обязательно
new_password
string
обязательно
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/password/change' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"current_password": "…", "new_password": "…"}'
POST/v1/auth/delete-request
Запрос на удаление аккаунта — подтверждается письмом
Нужен вход
Код с картинки — по подозрению, как у входа и сброса пароля: тело необязательное, пустая пара проходит, пока клиент не похож на робота. Похож — captcha_required, и форма показывает картинку.
Тело запросаDeleteRequest или null · application/json
Ответы
202Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/delete-request' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"captcha_id": "", "captcha_answer": ""}'
POST/v1/auth/delete-confirm
Подтверждение удаления аккаунта по ссылке из письма
Без входа
Тело запросаConfirmEmailRequest · application/json
token
string
обязательно
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/auth/delete-confirm' \
-H 'Content-Type: application/json' \
-d '{"token": "…"}'
Профиль
15 эндпоинтовСвой профиль, аватар, сессии, сохранённые фильтры поиска, настройки писем и пушей, «Транзакции» (оплаты и возвраты) и счётчики непрочитанного для шапки и нижнего меню (/v1/me/badges). Нужен вход.
GET/v1/me
Свой профиль целиком — вместе с действующими ограничениями
Нужен вход
Ответы
200Успешный ответ · ProfileResponse
Поля ответа · 27
id
string (uuid)
обязательно
Идентификатор записи (UUID)
email
string или null
обязательно
Адрес почты
email_confirmed
boolean
обязательно
status
string
обязательно
first_name
string
обязательно
last_name
string
обязательно
avatar_url
string или null
обязательно
birth_date
string (date) или null
обязательно
Дата рождения, YYYY-MM-DD
gender
string или null
обязательно
phone
string или null
обязательно
Телефон в международном виде, +66…
phone_confirmed
boolean
обязательно
citizenship
string или null
обязательно
Гражданство, код страны ISO 3166-1 alpha-2
residence_country
string или null
обязательно
billing_address
string или null
обязательно
emergency_contact
string или null
обязательно
language
string или null
обязательно
Язык: en, ru, th или zh-Hans
currency
string или null
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
verification_status
string
обязательно
verified_at
string (date-time) или null
обязательно
Момент в UTC, ISO 8601
notify_push
boolean
обязательно
notify_email
boolean
обязательно
notify_marketing
boolean
обязательно
bookings_count
integer
обязательно
Количество
rating_avg
number или null
обязательно
Средняя оценка, от 1 до 5
rating_count
integer
обязательно
Сколько оценок
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
restrictions
массив OwnRestriction
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me' \
-H 'Authorization: Bearer <access>'
PATCH/v1/me
Правка профиля
Нужен вход
Меняются только переданные поля: model_fields_set отличает «не передали» от «передали пусто», иначе форма с одним полем стирала бы остальные.
Тело запросаProfileUpdateRequest · application/json
first_name
string или null
last_name
string или null
birth_date
string (date) или null
Дата рождения, YYYY-MM-DD
gender
string или null
phone
string или null
Телефон в международном виде, +66…
citizenship
string или null
Гражданство, код страны ISO 3166-1 alpha-2
residence_country
string или null
billing_address
string или null
emergency_contact
string или null
language
string или null
Язык: en, ru, th или zh-Hans
currency
string или null
Код валюты ISO 4217 (THB, RUB, USD…)
notify_push
boolean или null
notify_email
boolean или null
notify_marketing
boolean или null
Ответы
200Успешный ответ · ProfileResponse
Поля ответа · 27
id
string (uuid)
обязательно
Идентификатор записи (UUID)
email
string или null
обязательно
Адрес почты
email_confirmed
boolean
обязательно
status
string
обязательно
first_name
string
обязательно
last_name
string
обязательно
avatar_url
string или null
обязательно
birth_date
string (date) или null
обязательно
Дата рождения, YYYY-MM-DD
gender
string или null
обязательно
phone
string или null
обязательно
Телефон в международном виде, +66…
phone_confirmed
boolean
обязательно
citizenship
string или null
обязательно
Гражданство, код страны ISO 3166-1 alpha-2
residence_country
string или null
обязательно
billing_address
string или null
обязательно
emergency_contact
string или null
обязательно
language
string или null
обязательно
Язык: en, ru, th или zh-Hans
currency
string или null
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
verification_status
string
обязательно
verified_at
string (date-time) или null
обязательно
Момент в UTC, ISO 8601
notify_push
boolean
обязательно
notify_email
boolean
обязательно
notify_marketing
boolean
обязательно
bookings_count
integer
обязательно
Количество
rating_avg
number или null
обязательно
Средняя оценка, от 1 до 5
rating_count
integer
обязательно
Сколько оценок
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
restrictions
массив OwnRestriction
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/me' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"first_name": "…", "last_name": "…"}'
GET/v1/me/badges
Счётчики непрочитанного: уведомления, сообщения, Bounty AI
Нужен вход
Три числа для обвязки клиента одним запросом.
notifications— непрочитанные уведомления (число у колокольчика); гаснут послеPOST /v1/notifications/read;messages— непрочитанные сообщения во всех переписках гостя (число у значка сообщений и точка у вкладки «Профиль»); гаснут послеPOST /v1/chats/dialogs/{id}/read;assistant— сообщения Bounty AI, которых гость ещё не видел (точка у вкладки «Bounty»); гаснут послеPOST /v1/assistant/read.
Запрос лёгкий — три счёта по индексам, — но дёргать его на каждом экране незачем: сайт помнит ответ минуту, приложения обновляют его по событиям сокета /v1/ws и при возврате на экран.
Ответы
200Успешный ответ · BadgesResponse
Поля ответа · 3
notifications
integer
обязательно
Непрочитанные уведомления — число у колокольчика
messages
integer
обязательно
Непрочитанные сообщения во всех переписках гостя — число у значка сообщений
assistant
integer
обязательно
Ответы и сообщения Bounty AI, которых гость ещё не видел — точка у вкладки «Bounty»
401Нет входа или токен истёк — unauthorized
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/badges' \
-H 'Authorization: Bearer <access>'
PUT/v1/me/avatar
Загрузка аватара. Изображение перекодируется, метаданные вырезаются
Нужен вход
Почта подтверждена
Тело запросаBody_set_avatar_v1_me_avatar_put · multipart/form-data
file
string
обязательно
Изображение: JPEG, PNG, HEIC или WebP
Ответы
200Успешный ответ · AvatarResponse
Поля ответа · 1
avatar_url
string
обязательно
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PUT 'https://api.bounty.travel/v1/me/avatar' \
-H 'Authorization: Bearer <access>' \
-F 'file=@photo.jpg'
DELETE/v1/me/avatar
Убрать аватар
Нужен вход
Почта подтверждена
Ответы
204Успешный ответ
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/me/avatar' \
-H 'Authorization: Bearer <access>'
GET/v1/me/sessions
Список устройств
Нужен вход
Дублирует /v1/auth/sessions: в интерфейсе этот список живёт в настройках профиля, а не на экране входа.
Ответы
200Успешный ответ · массив SessionResponse
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/sessions' \
-H 'Authorization: Bearer <access>'
DELETE/v1/me/sessions/<span class="text-brand-ink">{session_id}</span>
Завершить сессию на выбранном устройстве
Нужен вход
Параметры
session_id
путь · string (uuid)
обязательно
Идентификатор сессии (UUID)
Ответы
200Успешный ответ · MessageResponse
Поля ответа · 2
ok
boolean
по умолчанию true
Успешно ли
message
string или null
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/me/sessions/{session_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/me/search-filters
Сохранённые фильтры по разделам и последняя область карты
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · SearchFiltersResponse
Поля ответа · 4
stay
object
experience
object
service
object
map_view
object
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/search-filters' \
-H 'Authorization: Bearer <access>'
PUT/v1/me/search-filters
Сохранение фильтров. Разделы, которых нет в теле, не трогаются
Нужен вход
Почта подтверждена
Тело запросаSearchFiltersRequest · application/json
stay
object или null
experience
object или null
service
object или null
map_view
object или null
Ответы
200Успешный ответ · SearchFiltersResponse
Поля ответа · 4
stay
object
experience
object
service
object
map_view
object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PUT 'https://api.bounty.travel/v1/me/search-filters' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"stay": {}, "experience": {}}'
GET/v1/me/email-prefs
Галочки писем по группам. Чего человек не трогал — по умолчанию из реестра
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · EmailPrefsBody
Поля ответа · 1
groups
массив EmailPrefGroup
обязательно
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/email-prefs' \
-H 'Authorization: Bearer <access>'
PUT/v1/me/email-prefs
Включить или выключить письма: {"prefs": {"booking.reminder": false}}
Нужен вход
Почта подтверждена
Выключить можно всё, кроме ответов на действие самого человека (подтверждение почты, сброс пароля): их в настройках нет вовсе. Незнакомый код — 400 email_pref_unknown.
Тело запросаEmailPrefsUpdate · application/json
prefs
object
Ответы
200Успешный ответ · EmailPrefsBody
Поля ответа · 1
groups
массив EmailPrefGroup
обязательно
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PUT 'https://api.bounty.travel/v1/me/email-prefs' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"prefs": {}}'
GET/v1/me/push-prefs
Общий выключатель пушей и галочки по группам
Нужен вход
Почта подтверждена
Это настройки аккаунта. Разрешение пушей даёт каждое устройство само (POST /v1/devices): включённые здесь пуши приходят только на те устройства, где они разрешены и где человек сейчас вошёл.
Ответы
200Успешный ответ · PushPrefsBody
Поля ответа · 3
enabled
boolean
обязательно
Общий выключатель: выключен — не уходит ни один пуш
quiet
QuietHours
обязательно
Свои тихие часы: срочные пуши приходят всегда, остальные — после
groups
массив PushPrefGroup
обязательно
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/push-prefs' \
-H 'Authorization: Bearer <access>'
PUT/v1/me/push-prefs
Выключатель, тихие часы и/или галочки: {"enabled": true, "quiet": {"enabled": true, "start": 0, "end": 6}, "prefs": {"message.new": false}}
Нужен вход
Почта подтверждена
Тихие часы — свои у каждого: не срочные пуши в эти часы ждут утра.
Выключить можно любой пуш. Незнакомый код — 400 push_pref_unknown.
Тело запросаPushPrefsUpdate · application/json
enabled
boolean или null
Включено ли
quiet
QuietHoursUpdate или null
prefs
object
Ответы
200Успешный ответ · PushPrefsBody
Поля ответа · 3
enabled
boolean
обязательно
Общий выключатель: выключен — не уходит ни один пуш
quiet
QuietHours
обязательно
Свои тихие часы: срочные пуши приходят всегда, остальные — после
groups
массив PushPrefGroup
обязательно
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PUT 'https://api.bounty.travel/v1/me/push-prefs' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"enabled": false, "quiet": {"enabled": false, "start": 0}}'
GET/v1/me/transactions
«Транзакции»: оплаты и возвраты, новые сверху, как в выписке банка
Нужен вход
Почта подтверждена
У операции — вид (booking_payment, booking_refund), состояние (paid, failed, pending), сумма платежа, сумма заказа и курс, способ, номер операции банка, время с поясом места и «За что» (target). summary — итог нынешнего месяца: paid и refunded — общая сумма в валюте currency по курсу дня каждой операции и что в неё вошло по валютам (согласовано 28.10.2026).
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
type
запрос · string
all · payments · refunds
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
limit
запрос · integer или null
Сколько записей на странице
currency
запрос · string или null
Валюта, в которой человеку показаны цены; по умолчанию — из профиля, иначе RUB
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/transactions' \
-H 'Authorization: Bearer <access>'
GET/v1/me/transactions/<span class="text-brand-ink">{tx_id}</span>
Одна операция — по номеру из выписки (pay_…, ref_…)
Нужен вход
Почта подтверждена
Параметры
tx_id
путь · string
обязательно
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/transactions/{tx_id}' \
-H 'Authorization: Bearer <access>'
Токены API
3 эндпоинтаСвои токены bnt_user_… для скриптов и помощников: выпуск с паролем, список, отзыв. Токен показывается один раз. Права — read, bookings, chat, assistant; вход и сессии, свои токены, устройства и прочие записи токену закрыты (403 api_key_forbidden). Смена пароля отзывает все токены.
GET/v1/me/api-tokens
Свои токены — новые сверху; отозванные и истёкшие остаются в списке
Нужен вход
Ответы
200Успешный ответ · массив ApiTokenResponse
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/me/api-tokens' \
-H 'Authorization: Bearer <access>'
POST/v1/me/api-tokens
Выпускает токен. Токен в ответе один раз — дальше только начало
Нужен вход
Нужен текущий пароль: неверный — 401 invalid_credentials, и попытка считается, как на входе. Права — хотя бы одно из read, bookings, chat, assistant. Срок — 30, 90, 365 дней или null. Действующих токенов — не больше 10. На почту уходит письмо «Выпущен токен API». Принимая токен, гость принимает «Условия использования API».
Тело запросаApiTokenCreate · application/json
name
string
обязательно
Для чего токен: «Скрипт поиска вилл»
password
string
обязательно
Текущий пароль аккаунта
scopes
массив string
обязательно
read / bookings / chat / assistant — хотя бы одно
expires_in_days
integer или null
по умолчанию 365
30 / 90 / 365 или null — без срока
Ответы
201Успешный ответ · ApiTokenCreated
Поля ответа · 13
id
string
обязательно
Идентификатор записи (UUID)
name
string
обязательно
prefix
string
обязательно
Видимое начало: bnt_user_9a2c
status
string
обязательно
active / expiring (меньше 14 дней) / revoked / expired
scopes
массив string
обязательно
Права по разделам
expires_at
string (date-time) или null
обязательно
Момент в UTC, ISO 8601
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
last_used_at
string (date-time) или null
обязательно
Последний запрос — с точностью до минуты
last_used_ip
string или null
обязательно
requests_today
integer
обязательно
revoked_at
string (date-time) или null
обязательно
Момент в UTC, ISO 8601
revoked_reason
string или null
обязательно
manual — отозвал сам, password — смена пароля
token
string
обязательно
Токен целиком — один раз. Потерян — отзовите и выпустите новый
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/me/api-tokens' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"name": "…", "password": "…", "scopes": ["…"]}'
DELETE/v1/me/api-tokens/<span class="text-brand-ink">{token_id}</span>
Отзывает свой токен сразу. Чужой и несуществующий — одинаковый 404
Нужен вход
Параметры
token_id
путь · string (uuid)
обязательно
Ответы
200Успешный ответ · ApiTokenResponse
Поля ответа · 12
id
string
обязательно
Идентификатор записи (UUID)
name
string
обязательно
prefix
string
обязательно
Видимое начало: bnt_user_9a2c
status
string
обязательно
active / expiring (меньше 14 дней) / revoked / expired
scopes
массив string
обязательно
Права по разделам
expires_at
string (date-time) или null
обязательно
Момент в UTC, ISO 8601
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
last_used_at
string (date-time) или null
обязательно
Последний запрос — с точностью до минуты
last_used_ip
string или null
обязательно
requests_today
integer
обязательно
revoked_at
string (date-time) или null
обязательно
Момент в UTC, ISO 8601
revoked_reason
string или null
обязательно
manual — отозвал сам, password — смена пароля
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/me/api-tokens/{token_id}' \
-H 'Authorization: Bearer <access>'
Справочники
9 эндпоинтовОткрытая конфигурация клиента (/v1/config: карта, языки, валюты, регион афиши, включён ли Bounty AI), курсы валют для примерной цены, места, категории, удобства, ближайший сервер (/v1/nodes). Вход не нужен.
GET/v1/places
Иерархия мест на языке запроса
Без входа
Параметры
parent_id
запрос · integer или null
Только дети этого места
level
запрос · string или null
country / region / district / area
with_totals
запрос · boolean
Считать объекты вместе со вложенными местами
Ответы
200Успешный ответ · массив PlaceResponse
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/places'
GET/v1/places/popular
Популярные направления для главной — по числу опубликованных объектов
Без входа
Ответы
200Успешный ответ · массив PlaceResponse
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/places/popular'
GET/v1/places/<span class="text-brand-ink">{slug}</span>
Страница направления: место, путь сверху, что внутри, сколько чего
Без входа
Объявлен после /v1/places/popular: маршрут с параметром, стоящий раньше, перехватил бы слово popular как адрес места и всегда отвечал бы «направление не найдено».
Параметры
slug
путь · string
обязательно
Короткое имя для адреса: латиница, цифры, дефис
Ответы
200Успешный ответ · PlaceCardResponse
Поля ответа · 14
id
integer
обязательно
Идентификатор записи (UUID)
parent_id
integer или null
Идентификатор родительской записи (UUID)
level
string
обязательно
slug
string
обязательно
Короткое имя для адреса: латиница, цифры, дефис
name
string
обязательно
listings_count
integer
обязательно
Объектов, привязанных к самому месту
listings_total
integer или null
Объектов вместе со всем, что внутри. Заполняется только при with_totals=true: у региона собственных объявлений обычно нет, и без этого числа список регионов выглядит пустым
name_full
string или null
timezone
string или null
Часовой пояс IANA, например Asia/Bangkok; календарные даты объекта — в нём
currency
string или null
Код валюты ISO 4217 (THB, RUB, USD…)
center
PlacePoint или null
path
массив PlaceResponse
по умолчанию []
children
массив PlaceResponse
по умолчанию []
counts
object
по умолчанию {}
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/places/{slug}'
GET/v1/amenities
Удобства группами. С kind — только применимые к этой категории
Без входа
Параметры
kind
запрос · string или null
stay / experience / service
Ответы
200Успешный ответ · массив AmenityResponse
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/amenities'
GET/v1/categories
Категории впечатлений, услуг, транспорта или еды
Без входа
С with_counts=true у каждой — число опубликованных объектов: чипы над лентой раздела пишут его рядом с названием. Граница та же, что у ленты; остальные фильтры на число не влияют.
Параметры
kind
запрос · string
обязательно
experience, service, transport или food
with_counts
запрос · boolean
Добавить listings_count — сколько опубликованных объектов в категории (чипы)
Ответы
200Успешный ответ · массив app__schemas__catalog__CategoryResponse
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/categories'
GET/v1/currencies
Валюты отображения
Без входа
Ответы
200Успешный ответ · массив CurrencyResponse
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/currencies'
GET/v1/fx/rates
Курсы валют ЦБ РФ для примерной цены
Без входа
Открыт без токена: пересчёт нужен и гостю, который ещё не завёл учётную запись, — именно он чаще всего и смотрит цены впервые.
Это подсказка, а не цена. Платит человек в валюте объявления, банк пересчитывает по своему курсу, и клиент обязан пометить пересчёт как примерный.
Ответы
200Успешный ответ · FxRatesResponse
Поля ответа · 5
base
string
обязательно
date
string (date) или null
Календарный день в поясе объекта, без времени и пояса (YYYY-MM-DD)
fetched_at
string (date-time) или null
Момент в UTC, ISO 8601
source
string или null
rates
object
по умолчанию {}
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/fx/rates'
GET/v1/config
Публичная конфигурация: карта, языки, валюты, лимиты, регион афиши
Без входа
Ответы
200Успешный ответ · ConfigResponse
Поля ответа · 12
map
MapConfig
обязательно
Карта: стиль, тайлы и стартовый вид. Стиль и тайлы приходят с сервера, а не зашиты в приложение: адрес поставщика меняется, а обновление в магазине идёт две недели.
languages
массив string
default_language
string
обязательно
currencies
массив string
base_currency
string
обязательно
search
SearchLimits
обязательно
online_payments_enabled
boolean
обязательно
Приём платежей включён: хотя бы один рубильник — payments_terminal (Т-Банк) или payments_stripe (Stripe) — не в off
service_fee_percent
number
обязательно
max_upload_mb
integer
обязательно
review_window_days
integer
по умолчанию 14
Сколько дней после поездки открыто окно отзыва
assistant_enabled
boolean
по умолчанию false
Работает ли Bounty AI: показывать ли пункт меню вошедшему гостю
region
RegionInfo или null
Регион афиши: место уровня region у стартовой точки карты
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/config'
GET/v1/nodes
Серверы для выбора по пингу
Без входа
origin — главный сервер, есть всегда, даже когда узлов ноль: клиенту не нужно знать его адрес из своей сборки. В nodes — только узлы в состоянии active. Узел — это API и кеш файлов на одном сервере: у каждого — пара адресов, и выбираются они вместе.
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/nodes'
Локализация
2 эндпоинтаСтроки клиентов на четырёх языках (en, ru, th, zh-Hans) — тот же набор, что у сайта и приложений. Вход не нужен.
GET/v1/i18n
Набор строк целиком, уже с подстановкой недостающего из английского
Без входа
Клиент получает полный словарь, а не набор дыр, которые ему нечем закрыть: непереведённый ключ приходит по-английски, и это лучше пустой кнопки.
Язык берётся из параметра, иначе из Accept-Language; неизвестный — английский. Если version совпадает с текущей, отвечаем 304: набор строк весит килобайты, но телефон в тайском 3G считает и их.
Параметры
lang
запрос · string или null
Язык: en, ru, th или zh-Hans
version
запрос · string или null
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/i18n'
GET/v1/i18n/languages
Языки интерфейса — для экрана выбора языка
Без входа
Каждый назван на самом себе: «Тайский» ничего не говорит тому, кто ищет тайский. Флагов у языков нет: флаг — это страна, а не язык.
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/i18n/languages'
Поиск
5 эндпоинтовЛента пяти категорий (жильё, впечатления, услуги, транспорт, еда), карта, счётчик «Показать N», подсказки строки, края ползунка цены. Курсорная пагинация. Вход не нужен; вошедшему в карточках приходит is_favorite.
GET/v1/search/listings
Лента раздела: карточки по фильтрам, курсорная пагинация
Вход по желанию
Тексты приходят на языке запроса: у объекта, заведённого по-тайски, берётся перевод, и в ответе стоит пометка о нём.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
kind
запрос · string или null
stay / experience / service / transport / food / all
bbox
запрос · string или null
minLon,minLat,maxLon,maxLat
near
запрос · string или null
lat,lon
radius_m
запрос · integer или null
q
запрос · string или null
Текст запроса. Ищет по названию, описанию и месту объекта, на всех языках сразу и по словам: «вилла патонг» найдёт виллы Патонга. Отдельного фильтра места нет
date_from
запрос · string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
запрос · string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
guests
запрос · integer или null
Число гостей
price_min
запрос · integer или null
price_max
запрос · integer или null
currency
запрос · string или null
Код валюты ISO 4217 (THB, RUB, USD…)
property_type
запрос · массив string или null
room_type
запрос · string или null
bedrooms_min
запрос · integer или null
beds_min
запрос · integer или null
bathrooms_min
запрос · integer или null
beach_distance_max
запрос · integer или null
pets_allowed
запрос · boolean или null
smoking_allowed
запрос · boolean или null
children_allowed
запрос · boolean или null
Жильё: можно с детьми
parties_allowed
запрос · boolean или null
Жильё: можно вечеринки
long_stay
запрос · boolean или null
category_id
запрос · массив integer или null
Идентификатор категории (UUID)
duration_max
запрос · integer или null
languages
запрос · массив string или null
group_size_max
запрос · integer или null
same_day
запрос · boolean или null
price_unit
запрос · string или null
vehicle_kind
запрос · массив string или null
transmission
запрос · string или null
seats_min
запрос · integer или null
food_format
запрос · string или null
diets
запрос · массив string или null
Отметки меню; нужны все сразу
alcohol
запрос · boolean или null
amenities
запрос · массив string или null
Коды удобств; нужны все сразу
instant_book
запрос · boolean или null
rating_min
запрос · number или null
sort
запрос · string или null
relevance / price_asc / price_desc / rating / distance / new
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · app__schemas__search__FeedResponse
Поля ответа · 3
items
массив app__schemas__search__ListingCard
обязательно
Записи страницы
next_cursor
string или null
Курсор следующей страницы: передайте его в cursor. Нет — страница последняя. Непрозрачен: не разбирайте и не собирайте руками
has_more
boolean
обязательно
Есть ли следующая страница
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/search/listings'
GET/v1/search/map
Метки и кластеры карты по тем же фильтрам, что и лента
Без входа
Объекты в режиме city_only точки не имеют вовсе и на карту не попадают — их видно в ленте по своему городу.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
zoom
запрос · integer
обязательно
Зум карты: до 12 — кластеры, дальше метки
kind
запрос · string или null
stay / experience / service / transport / food / all
bbox
запрос · string или null
minLon,minLat,maxLon,maxLat
near
запрос · string или null
lat,lon
radius_m
запрос · integer или null
q
запрос · string или null
Текст запроса. Ищет по названию, описанию и месту объекта, на всех языках сразу и по словам: «вилла патонг» найдёт виллы Патонга. Отдельного фильтра места нет
date_from
запрос · string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
запрос · string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
guests
запрос · integer или null
Число гостей
price_min
запрос · integer или null
price_max
запрос · integer или null
currency
запрос · string или null
Код валюты ISO 4217 (THB, RUB, USD…)
property_type
запрос · массив string или null
room_type
запрос · string или null
bedrooms_min
запрос · integer или null
beds_min
запрос · integer или null
bathrooms_min
запрос · integer или null
beach_distance_max
запрос · integer или null
pets_allowed
запрос · boolean или null
smoking_allowed
запрос · boolean или null
children_allowed
запрос · boolean или null
Жильё: можно с детьми
parties_allowed
запрос · boolean или null
Жильё: можно вечеринки
long_stay
запрос · boolean или null
category_id
запрос · массив integer или null
Идентификатор категории (UUID)
duration_max
запрос · integer или null
languages
запрос · массив string или null
group_size_max
запрос · integer или null
same_day
запрос · boolean или null
price_unit
запрос · string или null
vehicle_kind
запрос · массив string или null
transmission
запрос · string или null
seats_min
запрос · integer или null
food_format
запрос · string или null
diets
запрос · массив string или null
Отметки меню; нужны все сразу
alcohol
запрос · boolean или null
amenities
запрос · массив string или null
Коды удобств; нужны все сразу
instant_book
запрос · boolean или null
rating_min
запрос · number или null
sort
запрос · string или null
relevance / price_asc / price_desc / rating / distance / new
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · app__schemas__search__MapResponse
Поля ответа · 4
clusters
массив app__schemas__search__MapCluster
points
массив MapPoint
truncated
boolean
по умолчанию false
total
integer
по умолчанию 0
Сколько всего
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/search/map'
GET/v1/search/count
Сколько вариантов подходит — для кнопки «Показать N вариантов»
Без входа
Отдельным лёгким запросом, а не полем ленты: панель фильтров пересчитывает число на каждой галочке, и тянуть ради этого двадцать карточек с фотографиями незачем.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
kind
запрос · string или null
stay / experience / service / transport / food / all
bbox
запрос · string или null
minLon,minLat,maxLon,maxLat
near
запрос · string или null
lat,lon
radius_m
запрос · integer или null
q
запрос · string или null
Текст запроса. Ищет по названию, описанию и месту объекта, на всех языках сразу и по словам: «вилла патонг» найдёт виллы Патонга. Отдельного фильтра места нет
date_from
запрос · string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
запрос · string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
guests
запрос · integer или null
Число гостей
price_min
запрос · integer или null
price_max
запрос · integer или null
currency
запрос · string или null
Код валюты ISO 4217 (THB, RUB, USD…)
property_type
запрос · массив string или null
room_type
запрос · string или null
bedrooms_min
запрос · integer или null
beds_min
запрос · integer или null
bathrooms_min
запрос · integer или null
beach_distance_max
запрос · integer или null
pets_allowed
запрос · boolean или null
smoking_allowed
запрос · boolean или null
children_allowed
запрос · boolean или null
Жильё: можно с детьми
parties_allowed
запрос · boolean или null
Жильё: можно вечеринки
long_stay
запрос · boolean или null
category_id
запрос · массив integer или null
Идентификатор категории (UUID)
duration_max
запрос · integer или null
languages
запрос · массив string или null
group_size_max
запрос · integer или null
same_day
запрос · boolean или null
price_unit
запрос · string или null
vehicle_kind
запрос · массив string или null
transmission
запрос · string или null
seats_min
запрос · integer или null
food_format
запрос · string или null
diets
запрос · массив string или null
Отметки меню; нужны все сразу
alcohol
запрос · boolean или null
amenities
запрос · массив string или null
Коды удобств; нужны все сразу
instant_book
запрос · boolean или null
rating_min
запрос · number или null
sort
запрос · string или null
relevance / price_asc / price_desc / rating / distance / new
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · CountResponse
Поля ответа · 1
count
integer
обязательно
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/search/count'
GET/v1/search/price-range
Границы ползунка цены раздела — в валюте человека
Без входа
Остальные фильтры сюда не приходят намеренно: края ползунка, прыгающие от каждой галочки, не дают его двигать. Пересчёт тот же, что у фильтра цены, — край не обещает цену, которой фильтр не найдёт.
Параметры
kind
запрос · string или null
Раздел; без него — все пять
currency
запрос · string или null
Валюта человека
Ответы
200Успешный ответ · PriceRangeResponse
Поля ответа · 4
currency
string или null
Код валюты ISO 4217 (THB, RUB, USD…)
min_minor
integer или null
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
max_minor
integer или null
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
histogram
массив integer
Сколько объектов в каждом из 24 отрезков шкалы ползунка: шкала квадратичная от нуля (ручка в положении p означает цену max_minor · p²), отрезок i — p от i/24 до (i+1)/24. Пусто, когда цен нет
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/search/price-range'
GET/v1/search/suggest
Подсказки строки поиска: места и объекты
Без входа
Ищет по переводам названий мест, а не по кодам: человек пишет «Пхукет» или «Phuket», а не phuket-province.
Параметры
q
запрос · string
обязательно
kind
запрос · string или null
Ответы
200Успешный ответ · SuggestResponse
Поля ответа · 2
places
массив PlaceSuggestion
listings
массив ListingSuggestion
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/search/suggest'
Карта
1 эндпоинтЗапасной путь тайлов и стиля карты через сервер Bounty, когда OpenFreeMap недоступен. Вход не нужен.
GET/v1/map/<span class="text-brand-ink">{path}</span>
Ресурс карты: стиль, TileJSON, тайл, шрифт, спрайт или рельеф
Без входа
Отдаётся ровно тем же телом и теми же заголовками кеширования, что пришли от OpenFreeMap: клиент обязан кешировать тайлы так же, как при прямом пути, иначе запасная дорога стоила бы вдесятеро дороже прямой.
Параметры
path
путь · string
обязательно
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/map/{path}'
События
6 эндпоинтовАфиша города: лента по дням, ближайшие события по одному на событие (страницами), полоска календаря, карта, страница события, справочник категорий. Дни и часы — в поясе площадки. Вход не нужен.
GET/v1/events/categories
Справочник категорий раздела на языке запроса
Без входа
Объявлен до /{slug}: маршрут с параметром, стоящий раньше, перехватил бы слово categories как адрес события.
Ответы
200Успешный ответ · массив app__schemas__events__CategoryResponse
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/events/categories'
GET/v1/events/calendar
Полоска календаря над лентой: сколько событий в каждом дне
Без входа
Считается с теми же фильтрами, что и лента: выбранная категория меняет числа в полоске, иначе день с цифрой «12» открывался бы пустым. День самого запроса в расчёт не идёт — полоска показывает всё окно.
В сегодняшнем дне не считается то, что уже закончилось — ровно как в ленте. Остальных дней окна отсечка не касается: она привязана к сегодняшнему числу, а не к началу окна.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
first
запрос · string (date) или null
Первый день окна; по умолчанию сегодня
days
запрос · integer
Дни — календарные даты в поясе объекта
day
запрос · string (date) или null
День афиши в поясе площадки. Без него — весь промежуток
day_from
запрос · string (date) или null
Начало промежутка дней
day_to
запрос · string (date) или null
Конец промежутка дней
category
запрос · массив string или null
Коды категорий; подходит любая из перечисленных
entry
запрос · string или null
free / paid / any
time
запрос · string или null
morning / day / evening / any
audience
запрос · string или null
family / adults / any
crowd
запрос · массив string или null
intimate / small / medium / large; подходит любая
event_lang
запрос · string или null
Язык события: ru / en / th / zh-Hans / multi (разноязычное) / any
q
запрос · string или null
Текст запроса. Ищет по названию, описанию, площадке и месту события, на всех языках и по словам
bbox
запрос · string или null
minLon,minLat,maxLon,maxLat
near
запрос · string или null
lat,lon
radius_m
запрос · integer или null
timezone
запрос · string или null
Пояс, в котором считается «сегодня». По умолчанию — Asia/Bangkok
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · CalendarResponse
Поля ответа · 3
days
массив CalendarDay
обязательно
Дни окна по порядку, от first (по умолчанию — сегодня)
timezone
string
обязательно
Пояс, в котором считается «сегодня»
today
string (date)
обязательно
Сегодня в этом поясе — клетка «Сегодня» полоски
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/events/calendar'
GET/v1/events/upcoming
Ближайшие события — по одному на событие, а не по дням
Без входа
Для витрин, которые показывают афишу не целиком: ряд на главной, блок в письме, экран приложения. Лента им не годится — её единица день, и ежедневный ночной рынок занял бы весь ряд своими датами: в ближайших пятидесяти днях его двадцать два.
Карточка та же, что в ленте, и несёт свой ближайший подходящий день. Витрине хватает первой страницы; лента «Событий» без выбранного дня листает дальше по next_cursor — порядок тот же, что у ленты по дням: день, время начала, событие.
Смотрит на окно в ближайшие 30 дней (days). «Ближайшие события» — это то, что происходит на днях; событие через полгода в такой ряд не просится, даже если оно единственное. Окно заодно режет цену запроса: без него отбор читал бы все дни всех событий до горизонта раскрытия расписаний, а это сто восемьдесят дней на каждое.
Объявлен до /{slug}: маршрут с параметром, стоящий раньше, принял бы слово upcoming за адрес события.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
limit
запрос · integer или null
Сколько записей на странице
days
запрос · integer
Окно поиска в днях от сегодня. Не действует, если задан день или конец промежутка
with_total
запрос · boolean
Добавить total — сколько всего событий подходит в окне
day
запрос · string (date) или null
День афиши в поясе площадки. Без него — весь промежуток
day_from
запрос · string (date) или null
Начало промежутка дней
day_to
запрос · string (date) или null
Конец промежутка дней
category
запрос · массив string или null
Коды категорий; подходит любая из перечисленных
entry
запрос · string или null
free / paid / any
time
запрос · string или null
morning / day / evening / any
audience
запрос · string или null
family / adults / any
crowd
запрос · массив string или null
intimate / small / medium / large; подходит любая
event_lang
запрос · string или null
Язык события: ru / en / th / zh-Hans / multi (разноязычное) / any
q
запрос · string или null
Текст запроса. Ищет по названию, описанию, площадке и месту события, на всех языках и по словам
bbox
запрос · string или null
minLon,minLat,maxLon,maxLat
near
запрос · string или null
lat,lon
radius_m
запрос · integer или null
timezone
запрос · string или null
Пояс, в котором считается «сегодня». По умолчанию — Asia/Bangkok
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · UpcomingResponse
Поля ответа · 4
items
массив EventCard
Записи страницы
next_cursor
string или null
Курсор следующей страницы; null — страниц больше нет
has_more
boolean
по умолчанию false
Есть ли ещё события после этой страницы
total
integer или null
Сколько событий подходит всего — только при with_total=true
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/events/upcoming'
GET/v1/events/map
Метки и кружки карты по тем же фильтрам, что и лента
Без входа
Событие приходит один раз — своим ближайшим подходящим днём, а не каждым. Лента идёт по дням, и еженедельная вечеринка стоит в ней пятнадцатью карточками; на карте те пятнадцать легли бы в одну точку стопкой, и человек видел бы одну метку, под которой спрятаны четырнадцать таких же.
Прошлые дни и прошедшие часы в карту не идут. Без заданного дня отсчёт начинается с сегодняшнего по поясу площадок, и из сегодняшнего выпадает уже закончившееся: карта отвечает на вопрос «куда пойти», а не «что тут было». Метка события при этом не пропадает — оно приходит своим следующим днём.
Событие без точки на карту не попадает вовсе — площадку могли записать одним адресом, и ставить её в случайное место значило бы соврать о том, куда идти.
Объявлен до /{slug}: маршрут с параметром, стоящий раньше, принял бы слово map за адрес события.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
zoom
запрос · integer
обязательно
Зум карты: до 12 — кружки, дальше метки
day
запрос · string (date) или null
День афиши в поясе площадки. Без него — весь промежуток
day_from
запрос · string (date) или null
Начало промежутка дней
day_to
запрос · string (date) или null
Конец промежутка дней
category
запрос · массив string или null
Коды категорий; подходит любая из перечисленных
entry
запрос · string или null
free / paid / any
time
запрос · string или null
morning / day / evening / any
audience
запрос · string или null
family / adults / any
crowd
запрос · массив string или null
intimate / small / medium / large; подходит любая
event_lang
запрос · string или null
Язык события: ru / en / th / zh-Hans / multi (разноязычное) / any
q
запрос · string или null
Текст запроса. Ищет по названию, описанию, площадке и месту события, на всех языках и по словам
bbox
запрос · string или null
minLon,minLat,maxLon,maxLat
near
запрос · string или null
lat,lon
radius_m
запрос · integer или null
timezone
запрос · string или null
Пояс, в котором считается «сегодня». По умолчанию — Asia/Bangkok
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · app__schemas__events__MapResponse
Поля ответа · 4
clusters
массив app__schemas__events__MapCluster
points
массив EventCard
truncated
boolean
по умолчанию false
total
integer
по умолчанию 0
Сколько всего
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/events/map'
GET/v1/events
Лента раздела: карточки событий выбранного дня, курсорная пагинация
Без входа
Единица ленты — день события, а не само событие: еженедельная вечеринка попадает в ленту каждого своего вторника. Порядок внутри дня — по времени начала; события «весь день» идут последними.
Без заданного дня лента начинается с сегодняшнего по поясу площадок: прошедшие дни остаются в базе, но афише отвечать нечем — туда уже не сходить. По той же причине из сегодняшнего дня выпадает то, что уже закончилось: концерт, доигравший в 14:00, не ответ на вопрос «куда пойти» в 19:00. Полоска календаря считает с той же отсечкой — иначе она обещала бы над лентой больше, чем лента показывает.
Спросили конкретный день — отвечаем на его вопрос целиком, включая уже прошедшее: «что было сегодня» тоже законный вопрос.
Тексты приходят на языке запроса, у переведённых стоит пометка.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
with_total
запрос · boolean
Добавить total — число подходящих событий
day
запрос · string (date) или null
День афиши в поясе площадки. Без него — весь промежуток
day_from
запрос · string (date) или null
Начало промежутка дней
day_to
запрос · string (date) или null
Конец промежутка дней
category
запрос · массив string или null
Коды категорий; подходит любая из перечисленных
entry
запрос · string или null
free / paid / any
time
запрос · string или null
morning / day / evening / any
audience
запрос · string или null
family / adults / any
crowd
запрос · массив string или null
intimate / small / medium / large; подходит любая
event_lang
запрос · string или null
Язык события: ru / en / th / zh-Hans / multi (разноязычное) / any
q
запрос · string или null
Текст запроса. Ищет по названию, описанию, площадке и месту события, на всех языках и по словам
bbox
запрос · string или null
minLon,minLat,maxLon,maxLat
near
запрос · string или null
lat,lon
radius_m
запрос · integer или null
timezone
запрос · string или null
Пояс, в котором считается «сегодня». По умолчанию — Asia/Bangkok
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · app__schemas__events__FeedResponse
Поля ответа · 4
items
массив EventCard
обязательно
Записи страницы
next_cursor
string или null
Курсор следующей страницы: передайте его в cursor. Нет — страница последняя. Непрозрачен: не разбирайте и не собирайте руками
has_more
boolean
по умолчанию false
Есть ли следующая страница
total
integer или null
Сколько всего
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/events'
GET/v1/events/<span class="text-brand-ink">{slug}</span>
Страница события по адресу
Без входа
Черновик и снятое событие отдают 404, а не «скрыто»: ответ «есть, но не покажу» рассказывает о том, чего гостю знать не нужно.
Часы приходят вместе с timezone_notice — поясом площадки и пояснением о разнице с поясом гостя. Показать «с 20:00» без пояса — та же ошибка, что показать цену без валюты.
Параметры
slug
путь · string
обязательно
Короткое имя для адреса: латиница, цифры, дефис
Ответы
200Успешный ответ · EventResponse
Поля ответа · 27
id
string (uuid)
обязательно
Идентификатор записи (UUID)
slug
string
обязательно
Короткое имя для адреса: латиница, цифры, дефис
title
string
обязательно
description
string или null
editorial
string или null
category
app__schemas__events__CategoryResponse
обязательно
Категория события: код для фильтра, название для человека.
photos
массив app__schemas__events__PhotoResponse
schedule
ScheduleResponse
обязательно
Расписание в виде данных, а не готовой строки. Подпись («каждый вторник», «22–24 сентября») собирает клиент из своих локалей: склонение дней недели на четырёх языках разное, и собранная здесь строка приехала бы тайцу по-русски.
next_day
string (date) или null
days
массив EventDayBrief
Дни — календарные даты в поясе объекта
time_from
string или null
Начало, HH:MM в поясе объекта
time_to
string или null
Конец, HH:MM в поясе объекта
timezone_notice
TimezoneNotice
обязательно
Пояс площадки и разница с поясом гостя.
label показывается всегда, hint — только когда пояс гостя отличается:
иначе человек прочитает чужое время как своё.
venue
string или null
address
string или null
place
app__schemas__events__PlaceBrief или null
lat
number или null
Широта, градусы WGS 84
lon
number или null
Долгота, градусы WGS 84
price
PriceResponse
обязательно
Вход: свободный или платный.
amount_minor в минорных единицах — как везде в проекте. note — то, что
числом не выражается («с депозитом на бар»), и стоит рядом с ценой, а не
вместо неё.
crowd
string
обязательно
audience
string
обязательно
langs
массив string
Языки: en, ru, th, zh-Hans
source_url
string или null
listings
массив LinkedListing
original_lang
string
обязательно
Язык, на котором текст написан автором
translation
app__schemas__events__TranslationMark или null
seo
SeoTags или null
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/events/{slug}'
Объекты
5 эндпоинтовСтраница объекта любой из пяти категорий, календарь, выходы и места, расчёт цены, отзывы, похожие рядом, условия долгосрочной аренды. Вход не нужен.
GET/v1/listings/<span class="text-brand-ink">{listing_id}</span>/availability
Календарь объекта: свободные даты, цена дня, минимальный срок
Без входа
Параметры
listing_id
путь · string (uuid)
обязательно
Идентификатор объекта (UUID)
from
запрос · string (date)
обязательно
to
запрос · string (date)
обязательно
Ответы
200Успешный ответ · AvailabilityResponse
Поля ответа · 6
listing_id
string (uuid)
обязательно
Идентификатор объекта (UUID)
timezone
string
обязательно
Часовой пояс IANA, например Asia/Bangkok; календарные даты объекта — в нём
regular_price_minor
integer или null
Обычная цена объекта — от неё отличается «особая» (№111)
timezone_notice
TimezoneNoticeBody
обязательно
Готовая пометка о поясе объекта — клиент показывает её как есть.
currency
string
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
days
массив AvailabilityDay
обязательно
Дни — календарные даты в поясе объекта
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/listings/{listing_id}/availability'
GET/v1/listings/<span class="text-brand-ink">{listing_id}</span>/slots
Свободные выходы впечатления или окна услуги
Без входа
Параметры
listing_id
путь · string (uuid)
обязательно
Идентификатор объекта (UUID)
from
запрос · string (date)
обязательно
to
запрос · string (date)
обязательно
Ответы
200Успешный ответ · SlotsResponse
Поля ответа · 7
listing_id
string (uuid)
обязательно
Идентификатор объекта (UUID)
timezone
string
обязательно
Часовой пояс IANA, например Asia/Bangkok; календарные даты объекта — в нём
timezone_notice
TimezoneNoticeBody
обязательно
Готовая пометка о поясе объекта — клиент показывает её как есть.
currency
string
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
slots
массив SlotBody
обязательно
rates
массив RateBody
по умолчанию []
extras
массив ExtraBody
по умолчанию []
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/listings/{listing_id}/slots'
POST/v1/listings/<span class="text-brand-ink">{listing_id}</span>/quote
Расчёт стоимости построчно
Без входа
Даты заняты — приходит available: false и conflict_dates, а не пустой ответ: гость должен видеть, какие именно даты мешают, и подвинуть их.
Параметры
listing_id
путь · string (uuid)
обязательно
Идентификатор объекта (UUID)
Тело запросаQuoteRequest · application/json
date_from
string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
slot_id
string (uuid) или null
Идентификатор выхода (UUID)
guests
integer
по умолчанию 1
Число гостей
rates
массив RatePick
extras
массив ExtraPick
Ответы
200Успешный ответ · QuoteResponse
Поля ответа · 11
available
boolean
обязательно
policy
PolicyBody или null
Условия отмены этой брони — одна политика по её датам: первый день брони в сезоне решает, иначе основная
policy_schedule
массив PolicyDay
Те же условия датами в поясе объекта: с какого по какой день сколько вернётся
currency
string
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
nights
integer
обязательно
Число ночей
lines
массив QuoteLine
обязательно
total
MoneyBody
обязательно
Сколько всего
deposit
MoneyBody или null
reason
string или null
dates_unavailable / min_nights / max_nights / too_far / slot_closed / not_enough_seats / slot_taken / table_too_small
conflict_dates
массив string (date) или null
min_nights
integer или null
Наименьшее число ночей брони
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/listings/{listing_id}/quote' \
-H 'Content-Type: application/json' \
-d '{"date_from": "2026-11-02", "date_to": "2026-11-02"}'
GET/v1/listings/<span class="text-brand-ink">{key}</span>
Полная карточка объекта — по адресу или идентификатору
Вход по желанию
Вход не нужен: выбирать можно без регистрации. Вошедшему дополнительно видно, лежит ли объект у него в избранном.
Маршрут объявлен после /{listing_id}/availability и соседей: иначе он перехватил бы их пути, приняв «availability» за адрес объекта.
Параметры
key
путь · string
обязательно
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/listings/{key}'
GET/v1/listings/<span class="text-brand-ink">{key}</span>/similar
Похожие рядом — тот же тип в том же месте
Без входа
Параметры
key
путь · string
обязательно
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/listings/{key}/similar'
Бизнес
2 эндпоинтаСтраница бизнеса-партнёра: о компании, объекты, отзывы. Вход не нужен.
GET/v1/partners/<span class="text-brand-ink">{partner_id}</span>
Карточка бизнеса и его объекты одним ответом
Вход по желанию
Одним, потому что страница без объектов — это пустая страница: два запроса означали бы, что человек сначала видит название компании, а через мгновение под ним появляются виллы и всё подпрыгивает.
Параметры
partner_id
путь · string (uuid)
обязательно
Идентификатор бизнеса-партнёра (UUID)
Ответы
200Успешный ответ · PartnerPage
Поля ответа · 2
partner
PartnerCard
обязательно
Бизнес глазами гостя.
listings
массив app__schemas__search__ListingCard
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/partners/{partner_id}'
GET/v1/partners/<span class="text-brand-ink">{partner_id}</span>/reviews
Отзывы по всем объектам бизнеса, свежие сверху
Без входа
Одной лентой, а не по объектам: человек хочет понять, как эта компания работает вообще, а не листать отзывы двадцати вилл по очереди.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
partner_id
путь · string (uuid)
обязательно
Идентификатор бизнеса-партнёра (UUID)
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
limit
запрос · integer
Сколько записей на странице
Ответы
200Успешный ответ · PartnerReviews
Поля ответа · 3
items
массив ReviewBody
Записи страницы
next_cursor
string или null
Курсор следующей страницы: передайте его в cursor. Нет — страница последняя. Непрозрачен: не разбирайте и не собирайте руками
has_more
boolean
по умолчанию false
Есть ли следующая страница
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/partners/{partner_id}/reviews'
Бронирования
8 эндпоинтовОформление, список, бронь целиком, отмена с расчётом возврата, лента заказа, билет заселения. Нужна подтверждённая почта. Создание принимает Idempotency-Key.
GET/v1/bookings
Мои поездки, новые сверху
Нужен вход
Почта подтверждена
scope отбирает по ходу поездки. Без него список остаётся прежним — всё подряд: это умолчание держит старых клиентов, которые про scope не знают. Порядок от scope не зависит, см. booking_service.page.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
status
запрос · BookingStatus или null
scope
запрос · string или null
Вкладки: upcoming — живые и не закончившиеся, completed — завершённые (в том числе неявка), cancelled — отменённые, отклонённые и просроченные; past — completed и cancelled вместе; all — всё (умолчание)
with_counts
запрос · boolean
Добавить counts — числа на трёх вкладках
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · BookingPage
Поля ответа · 4
items
массив BookingBrief
обязательно
Записи страницы
next_cursor
string или null
Курсор следующей страницы: передайте его в cursor. Нет — страница последняя. Непрозрачен: не разбирайте и не собирайте руками
has_more
boolean
по умолчанию false
Есть ли следующая страница
counts
BookingCounts или null
Только при with_counts=true
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/bookings' \
-H 'Authorization: Bearer <access>'
POST/v1/bookings
Создаёт бронь. Мгновенная сразу подтверждена, по запросу — pending
Нужен вход
Почта подтверждена
Повтор без дубля. Обязателен заголовок Idempotency-Key — любая строка до 80 символов, своя на каждую операцию. Повтор с тем же ключом и тем же телом в течение суток вернёт первый ответ, с другим телом — 409 idempotency_key_reuse.
Параметры
Idempotency-Key
заголовок · string
обязательно
Ключ повтора: любая строка до 80 символов, своя на каждую операцию
Тело запросаBookingCreate · application/json
listing_id
string (uuid)
обязательно
Идентификатор объекта (UUID)
date_from
string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
slot_id
string (uuid) или null
Идентификатор выхода (UUID)
contract_id
string (uuid) или null
Идентификатор договора (UUID)
guests_adults
integer
по умолчанию 1
guests_children
integer
по умолчанию 0
guests_infants
integer
по умолчанию 0
pets
integer
по умолчанию 0
guest_message
string или null
guests_details
массив GuestDetails
contact_phone
string или null
rates
массив RatePick
extras
массив ExtraPick
Ответы
201Успешный ответ · BookingDetail
Поля ответа · 57
id
string (uuid)
обязательно
Идентификатор записи (UUID)
code
string
обязательно
status
string
обязательно
kind
string
обязательно
booking_kind
string
по умолчанию "nightly"
nightly / contract. У контракта расчёт идёт вне сервиса
date_from
string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
nights
integer или null
Число ночей
starts_at
string (date-time) или null
Момент в UTC, ISO 8601
ends_at
string (date-time) или null
Конец выхода у брони впечатления, услуги, еды
guests
integer
обязательно
Число гостей
total
MoneyBody
обязательно
Сколько всего
payment_status
string
обязательно
respond_by
string (date-time) или null
Докуда хозяин отвечает на запрос. Плашка «Ответит до» — пока status = pending
pay_by
string (date-time) или null
Докуда ждём оплату подтверждённой брони. Плашка «Оплатить до» — пока status = confirmed и payment_status = none
pay_expired
boolean
по умолчанию false
Подтверждённую бронь не оплатили к сроку, и она закрылась
review_until
string (date-time) или null
До какого момента можно написать отзыв; пусто — нельзя или уже написан
review_from
string (date-time) или null
Бронь ещё не закончилась: с какого момента откроется отзыв
review_needs_payment
boolean
по умолчанию false
Отзыв — только по оплаченной брони: оплатите, иначе отзыва не будет
has_review
boolean
по умолчанию false
Гость уже оставил отзыв по этой брони
listing
ListingBrief
обязательно
Объект в карточке брони — столько, сколько нужно, чтобы его узнать.
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
lines
массив QuoteLine
обязательно
deposit
MoneyBody или null
free_cancel_until
string (date-time) или null
free_cancel_last_day
string (date) или null
Последний день бесплатной отмены, включительно, в поясе объекта
policy
PolicyBody или null
Условия, действующие сегодня
policies
массив PolicyBody
Условия этой брони списком из одной политики — по её датам; поле осталось для прежних клиентов
policy_schedule
массив PolicyDay
Условия этой брони датами в поясе объекта: с какого по какой день сколько вернётся
timezone_notice
object или null
Пометка о поясе объекта: label — чьё это время, hint — пояснение о разнице, когда пояс гостя другой
pay_closed
boolean
по умолчанию false
Время на оплату вышло: форма банка гаснет за минуту до pay_by, оплатить уже нельзя (409 booking_payment_expired)
guest_message
string или null
address
string или null
directions
string или null
directions_original
string или null
Оригинал «как добраться», когда directions пришло переводом; null — показан оригинал (сейчас это поле не переводится)
point
object или null
Точка объекта {lat, lon} для карты — та же, что на странице объекта
checkin_from
string или null
checkout_until
string или null
required_documents
массив string
«Что взять с собой» — коды документов объекта (passport, deposit_cash…), подписи — строками listing.checkin_doc.<код>
house_rules
string или null
Правила дома на языке запроса, где перевод готов (№90)
can_cancel
boolean
обязательно
can_check_in_now
boolean
обязательно
Примут ли код на стойке прямо сейчас. Показом кода не управляет
guest_details
object
Данные участников: режим объекта (optional/required), сколько нужно и заполнено, можно ли платить (ready) и править (editable — до оплаты)
contact_phone
string или null
Телефон для связи по заказу. Правится до оплаты вместе с участниками
confirmed_at
string (date-time) или null
Момент в UTC, ISO 8601
paid_at
string (date-time) или null
Момент в UTC, ISO 8601
cancelled_at
string (date-time) или null
Момент в UTC, ISO 8601
declined_at
string (date-time) или null
Момент в UTC, ISO 8601
checkin_at
string (date-time) или null
Момент в UTC, ISO 8601
checkout_at
string (date-time) или null
Момент в UTC, ISO 8601
cancelled_by_kind
string или null
thread_id
string (uuid) или null
Идентификатор переписки (UUID)
timezone
string или null
Часовой пояс IANA, например Asia/Bangkok; календарные даты объекта — в нём
details
object
pay_options
массив object
pay_paused
boolean
по умолчанию false
snapshot
object
Снимок покупки на момент оформления: объект, единица фонда, партнёр, условия и политика отмены. Не меняется никогда — чек обязан показывать то, что человек купил тогда, а не сегодняшнюю карточку. Адреса в снимке нет: он хранится зашифрованным
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
409Повтор Idempotency-Key с другим телом — idempotency_key_reuse; первый запрос с этим ключом ещё выполняется — idempotency_in_progress; данные расходятся с состоянием — conflict и коды эндпоинта
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/bookings' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"listing_id": "00000000-0000-0000-0000-000000000000"}'
GET/v1/bookings/<span class="text-brand-ink">{booking_id}</span>
Карточка брони. Адрес открывается только по подтверждённой
Нужен вход
Почта подтверждена
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Ответы
200Успешный ответ · BookingDetail
Поля ответа · 57
id
string (uuid)
обязательно
Идентификатор записи (UUID)
code
string
обязательно
status
string
обязательно
kind
string
обязательно
booking_kind
string
по умолчанию "nightly"
nightly / contract. У контракта расчёт идёт вне сервиса
date_from
string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
nights
integer или null
Число ночей
starts_at
string (date-time) или null
Момент в UTC, ISO 8601
ends_at
string (date-time) или null
Конец выхода у брони впечатления, услуги, еды
guests
integer
обязательно
Число гостей
total
MoneyBody
обязательно
Сколько всего
payment_status
string
обязательно
respond_by
string (date-time) или null
Докуда хозяин отвечает на запрос. Плашка «Ответит до» — пока status = pending
pay_by
string (date-time) или null
Докуда ждём оплату подтверждённой брони. Плашка «Оплатить до» — пока status = confirmed и payment_status = none
pay_expired
boolean
по умолчанию false
Подтверждённую бронь не оплатили к сроку, и она закрылась
review_until
string (date-time) или null
До какого момента можно написать отзыв; пусто — нельзя или уже написан
review_from
string (date-time) или null
Бронь ещё не закончилась: с какого момента откроется отзыв
review_needs_payment
boolean
по умолчанию false
Отзыв — только по оплаченной брони: оплатите, иначе отзыва не будет
has_review
boolean
по умолчанию false
Гость уже оставил отзыв по этой брони
listing
ListingBrief
обязательно
Объект в карточке брони — столько, сколько нужно, чтобы его узнать.
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
lines
массив QuoteLine
обязательно
deposit
MoneyBody или null
free_cancel_until
string (date-time) или null
free_cancel_last_day
string (date) или null
Последний день бесплатной отмены, включительно, в поясе объекта
policy
PolicyBody или null
Условия, действующие сегодня
policies
массив PolicyBody
Условия этой брони списком из одной политики — по её датам; поле осталось для прежних клиентов
policy_schedule
массив PolicyDay
Условия этой брони датами в поясе объекта: с какого по какой день сколько вернётся
timezone_notice
object или null
Пометка о поясе объекта: label — чьё это время, hint — пояснение о разнице, когда пояс гостя другой
pay_closed
boolean
по умолчанию false
Время на оплату вышло: форма банка гаснет за минуту до pay_by, оплатить уже нельзя (409 booking_payment_expired)
guest_message
string или null
address
string или null
directions
string или null
directions_original
string или null
Оригинал «как добраться», когда directions пришло переводом; null — показан оригинал (сейчас это поле не переводится)
point
object или null
Точка объекта {lat, lon} для карты — та же, что на странице объекта
checkin_from
string или null
checkout_until
string или null
required_documents
массив string
«Что взять с собой» — коды документов объекта (passport, deposit_cash…), подписи — строками listing.checkin_doc.<код>
house_rules
string или null
Правила дома на языке запроса, где перевод готов (№90)
can_cancel
boolean
обязательно
can_check_in_now
boolean
обязательно
Примут ли код на стойке прямо сейчас. Показом кода не управляет
guest_details
object
Данные участников: режим объекта (optional/required), сколько нужно и заполнено, можно ли платить (ready) и править (editable — до оплаты)
contact_phone
string или null
Телефон для связи по заказу. Правится до оплаты вместе с участниками
confirmed_at
string (date-time) или null
Момент в UTC, ISO 8601
paid_at
string (date-time) или null
Момент в UTC, ISO 8601
cancelled_at
string (date-time) или null
Момент в UTC, ISO 8601
declined_at
string (date-time) или null
Момент в UTC, ISO 8601
checkin_at
string (date-time) или null
Момент в UTC, ISO 8601
checkout_at
string (date-time) или null
Момент в UTC, ISO 8601
cancelled_by_kind
string или null
thread_id
string (uuid) или null
Идентификатор переписки (UUID)
timezone
string или null
Часовой пояс IANA, например Asia/Bangkok; календарные даты объекта — в нём
details
object
pay_options
массив object
pay_paused
boolean
по умолчанию false
snapshot
object
Снимок покупки на момент оформления: объект, единица фонда, партнёр, условия и политика отмены. Не меняется никогда — чек обязан показывать то, что человек купил тогда, а не сегодняшнюю карточку. Адреса в снимке нет: он хранится зашифрованным
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/bookings/{booking_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/bookings/<span class="text-brand-ink">{booking_id}</span>/refund-preview
Сколько вернётся, если отменить прямо сейчас
Нужен вход
Почта подтверждена
Отдельным эндпоинтом, а не текстом в карточке: сумма зависит от момента, и гость должен видеть её до нажатия, а не узнавать после.
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Ответы
200Успешный ответ · RefundBody
Поля ответа · 8
amount
MoneyBody
обязательно
Сумма всегда тремя полями: иначе клиент округлит её по-своему.
percent
integer
обязательно
free
boolean
обязательно
Отмена попала в бесплатное окно
reason
string
обязательно
free_window / policy / cancelled_by_partner
days_until
integer или null
Суток до заезда в поясе объекта
free_cancel_until
string (date-time) или null
policy
PolicyBody или null
policy_seasonal
boolean
по умолчанию false
Сейчас действуют сезонные условия, а не основные
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/bookings/{booking_id}/refund-preview' \
-H 'Authorization: Bearer <access>'
POST/v1/bookings/<span class="text-brand-ink">{booking_id}</span>/cancel
Отмена гостем. В ответе — сумма возврата
Нужен вход
Почта подтверждена
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Тело запросаCancelRequest · application/json
reason_code
string или null
Машинный код причины
comment
string или null
Комментарий
Ответы
200Успешный ответ · RefundBody
Поля ответа · 8
amount
MoneyBody
обязательно
Сумма всегда тремя полями: иначе клиент округлит её по-своему.
percent
integer
обязательно
free
boolean
обязательно
Отмена попала в бесплатное окно
reason
string
обязательно
free_window / policy / cancelled_by_partner
days_until
integer или null
Суток до заезда в поясе объекта
free_cancel_until
string (date-time) или null
policy
PolicyBody или null
policy_seasonal
boolean
по умолчанию false
Сейчас действуют сезонные условия, а не основные
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/bookings/{booking_id}/cancel' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"reason_code": "…", "comment": "…"}'
GET/v1/bookings/<span class="text-brand-ink">{booking_id}</span>/guests
Кто едет: список проживающих
Нужен вход
Почта подтверждена
Приходит заполненным наполовину: первая строка — сам заказчик, из его профиля, остальные пустые по числу людей в брони. Заставлять человека переписывать в форму собственные имя и возраст, которые сервис и так знает, — верный способ получить незаполненную форму.
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Ответы
200Успешный ответ · массив StayGuestBody
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/bookings/{booking_id}/guests' \
-H 'Authorization: Bearer <access>'
PUT/v1/bookings/<span class="text-brand-ink">{booking_id}</span>/guests
Переписывает список участников целиком — и телефон для связи
Нужен вход
Почта подтверждена
Пустые строки не сохраняются. У объекта с guest_details = required данные всех участников обязательны и стереть их правкой нельзя — 400 guest_details_required. contact_phone не передан — не меняется, пустой — 400 phone_required.
Правится только до оплаты: оплатой человек подтвердил, кого и как везут, и партнёр по этим данным оформляет страховку. Оплаченная или закрытая бронь отвечает 409 guests_locked.
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Тело запросаStayGuestsRequest · application/json
guests
массив StayGuestIn
Число гостей
contact_phone
string или null
Ответы
200Успешный ответ · массив StayGuestBody
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PUT 'https://api.bounty.travel/v1/bookings/{booking_id}/guests' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"guests": [{}], "contact_phone": "…"}'
GET/v1/bookings/<span class="text-brand-ink">{booking_id}</span>/qr
Билет заселения
Нужен вход
Почта подтверждена
Клиент рисует QR из строки сам: картинка с сервера не нужна и лишний раз светит бронь в кешах. Рядом с кодом печатается номер брони — им заселяют, когда камера не справилась.
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Ответы
200Успешный ответ · TicketResponse
Поля ответа · 3
ticket
string
обязательно
code
string
обязательно
Номер брони: печатается рядом с кодом
expires_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/bookings/{booking_id}/qr' \
-H 'Authorization: Bearer <access>'
Оплата
2 эндпоинтаОплата брони и заказа через Т-Банк (на стенде — только демо-терминал), состояние платежа. Нужна подтверждённая почта.
POST/v1/bookings/<span class="text-brand-ink">{booking_id}</span>/payment
Начинает оплату и возвращает адрес страницы банка или Stripe
Нужен вход
Почта подтверждена
Платить можно только подтверждённую бронь: пока партнёр не ответил, он ещё может отказать, и деньги пришлось бы возвращать.
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Тело запросаPaymentStart · application/json
return_url
string или null
Адрес возврата. Пустой — вернём на карточку брони в вебе
policy_accepted
boolean
по умолчанию true
Гость видел условия отмены и согласился с ними
provider
string или null
Способ: tbank (рубли, «Мир» и СБП) или stripe (баты, карты мира)
Ответы
200Успешный ответ · PaymentStarted
Поля ответа · 3
payment_id
string
обязательно
Идентификатор платежа (UUID)
url
string
обязательно
Страница банка — сюда уводят человека
status
string
обязательно
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/bookings/{booking_id}/payment' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"return_url": "…", "policy_accepted": true}'
GET/v1/payments/confirm
Проверяет платёж после возврата из банка
Нужен вход
Почта подтверждена
Номер платежа приходит из адреса, а состояние — из запроса к провайдеру: адрес человек правит руками, и «оплачено» в нём не значит ничего.
Параметры
payment_id
запрос · string
обязательно
Идентификатор платежа (UUID)
Ответы
200Успешный ответ · PaymentResult
Поля ответа · 3
paid
boolean
обязательно
booking_id
string (uuid) или null
Идентификатор брони (UUID)
payment_status
string или null
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/payments/confirm' \
-H 'Authorization: Bearer <access>'
Долгосрочная аренда
5 эндпоинтовДоговоры аренды от месяца: стадии, задаток, документ, подписи, чеки. Нужна подтверждённая почта.
GET/v1/rentals
Мои долгосрочные заявки
Нужен вход
Почта подтверждена
Параметры
limit
запрос · integer
Сколько записей на странице
offset
запрос · integer
Ответы
200Успешный ответ · RentalPage
Поля ответа · 2
items
массив RentalBrief
обязательно
Записи страницы
total
integer
обязательно
Сколько всего
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/rentals' \
-H 'Authorization: Bearer <access>'
GET/v1/rentals/<span class="text-brand-ink">{booking_id}</span>
Состояние сделки: что уже сделано, чей сейчас ход и все её чеки
Нужен вход
Почта подтверждена
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Ответы
200Успешный ответ · RentalDetail
Поля ответа · 44
id
string (uuid)
обязательно
Идентификатор записи (UUID)
booking_id
string (uuid)
обязательно
Идентификатор брони (UUID)
stage
string
обязательно
negotiating / awaiting_document / awaiting_signatures / signed / cancelled. living / handover / completed — стадии прежнего пути: встречаются у договоров, закрытых по прежнему пути, и новыми не становятся
months
integer
обязательно
price_minor
integer
обязательно
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
deposit_minor
integer
обязательно
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
currency
string
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
document_name
string или null
document_size
integer или null
has_document
boolean
по умолчанию false
guest_signed_at
string (date-time) или null
Момент в UTC, ISO 8601
partner_signed_at
string (date-time) или null
Момент в UTC, ISO 8601
sign_deadline_at
string (date-time) или null
Момент в UTC, ISO 8601
sign_expired
boolean
по умолчанию false
Срок вышел: подпись больше не принимается
deposit_paid_at
string (date-time) или null
Момент в UTC, ISO 8601
settled_at
string (date-time) или null
Момент в UTC, ISO 8601
cancelled_at
string (date-time) или null
Момент в UTC, ISO 8601
cancel_reason
string или null
completed_at
string (date-time) или null
Момент в UTC, ISO 8601
terminated_at
string (date-time) или null
Момент в UTC, ISO 8601
terminated_by
string или null
guest / partner
terminate_reason
string или null
handover_at
string (date-time) или null
Момент в UTC, ISO 8601
code
string
обязательно
listing_id
string (uuid)
обязательно
Идентификатор объекта (UUID)
listing_title
string
обязательно
Название объекта на языке ответа
listing_slug
string
обязательно
listing_photo
object или null
Первый снимок объекта размерами thumb/medium/large
partner_name
string
обязательно
Название бизнеса
partner_legal_name
string или null
date_from
string (date) или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
string (date) или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
waiting_for
string
обязательно
guest / partner / none — чей сейчас ход
price
MoneyBody или null
deposit
MoneyBody или null
thread_id
string (uuid) или null
Идентификатор переписки (UUID)
can_sign
boolean
по умолчанию false
stages
массив string
Стадии в порядке жизни
snapshot
object
created_at
string (date-time) или null
Момент в UTC, ISO 8601
confirmed_at
string (date-time) или null
Момент в UTC, ISO 8601
payment_status
string или null
guest_name
string или null
total
MoneyBody или null
Сколько всего
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/rentals/{booking_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/rentals/<span class="text-brand-ink">{booking_id}</span>/document
Договор потоком. Прямой ссылки на приватный файл не существует
Нужен вход
Почта подтверждена
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/rentals/{booking_id}/document' \
-H 'Authorization: Bearer <access>'
POST/v1/rentals/<span class="text-brand-ink">{booking_id}</span>/sign
Согласие с договором — и конец пути
Нужен вход
Почта подтверждена
Подписывает гость: партнёр расписался тем, что приложил договор и закрепил за ним номер с датами. С этой подписью договор заключён, изменению не подлежит, а его дни становятся занятыми.
После срока (семь дней от приложения) — 409 sign_expired: подпись больше не принимается, и партнёр решает, прислать договор заново или отменить сделку.
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Ответы
200Успешный ответ · RentalBody
Поля ответа · 23
id
string (uuid)
обязательно
Идентификатор записи (UUID)
booking_id
string (uuid)
обязательно
Идентификатор брони (UUID)
stage
string
обязательно
negotiating / awaiting_document / awaiting_signatures / signed / cancelled. living / handover / completed — стадии прежнего пути: встречаются у договоров, закрытых по прежнему пути, и новыми не становятся
months
integer
обязательно
price_minor
integer
обязательно
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
deposit_minor
integer
обязательно
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
currency
string
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
document_name
string или null
document_size
integer или null
has_document
boolean
по умолчанию false
guest_signed_at
string (date-time) или null
Момент в UTC, ISO 8601
partner_signed_at
string (date-time) или null
Момент в UTC, ISO 8601
sign_deadline_at
string (date-time) или null
Момент в UTC, ISO 8601
sign_expired
boolean
по умолчанию false
Срок вышел: подпись больше не принимается
deposit_paid_at
string (date-time) или null
Момент в UTC, ISO 8601
settled_at
string (date-time) или null
Момент в UTC, ISO 8601
cancelled_at
string (date-time) или null
Момент в UTC, ISO 8601
cancel_reason
string или null
completed_at
string (date-time) или null
Момент в UTC, ISO 8601
terminated_at
string (date-time) или null
Момент в UTC, ISO 8601
terminated_by
string или null
guest / partner
terminate_reason
string или null
handover_at
string (date-time) или null
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/rentals/{booking_id}/sign' \
-H 'Authorization: Bearer <access>'
POST/v1/rentals/<span class="text-brand-ink">{booking_id}</span>/cancel
Отказ от сделки — до подписи
Нужен вход
Почта подтверждена
После подписи договор заключён между сторонами, и расторгают его они сами: сервис не сторона этой бумаги. Такой вызов — 409 already_signed.
Параметры
booking_id
путь · string (uuid)
обязательно
Идентификатор брони (UUID)
Тело запросаRentalCancel · application/json
reason
string или null
Ответы
200Успешный ответ · RentalBody
Поля ответа · 23
id
string (uuid)
обязательно
Идентификатор записи (UUID)
booking_id
string (uuid)
обязательно
Идентификатор брони (UUID)
stage
string
обязательно
negotiating / awaiting_document / awaiting_signatures / signed / cancelled. living / handover / completed — стадии прежнего пути: встречаются у договоров, закрытых по прежнему пути, и новыми не становятся
months
integer
обязательно
price_minor
integer
обязательно
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
deposit_minor
integer
обязательно
Сумма в минорных единицах валюты (currency): у бата и рубля — сотые, 150000 = 1 500,00. Считает сервер
currency
string
обязательно
Код валюты ISO 4217 (THB, RUB, USD…)
document_name
string или null
document_size
integer или null
has_document
boolean
по умолчанию false
guest_signed_at
string (date-time) или null
Момент в UTC, ISO 8601
partner_signed_at
string (date-time) или null
Момент в UTC, ISO 8601
sign_deadline_at
string (date-time) или null
Момент в UTC, ISO 8601
sign_expired
boolean
по умолчанию false
Срок вышел: подпись больше не принимается
deposit_paid_at
string (date-time) или null
Момент в UTC, ISO 8601
settled_at
string (date-time) или null
Момент в UTC, ISO 8601
cancelled_at
string (date-time) или null
Момент в UTC, ISO 8601
cancel_reason
string или null
completed_at
string (date-time) или null
Момент в UTC, ISO 8601
terminated_at
string (date-time) или null
Момент в UTC, ISO 8601
terminated_by
string или null
guest / partner
terminate_reason
string или null
handover_at
string (date-time) или null
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/rentals/{booking_id}/cancel' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"reason": "…"}'
Чат
10 эндпоинтовПереписка с партнёрами и поддержкой: диалоги, сообщения, вложения, голосовые, прочтение. Realtime — WebSocket /v1/ws. Нужна подтверждённая почта.
GET/v1/dialogs
Мои диалоги, свежие сверху; с q — только те, где нашлось
Нужен вход
Почта подтверждена
Параметры
q
запрос · string или null
Поиск: имя хозяина, название объекта, номер брони, тема обращения, текст сообщений — оригинал и перевод на языке запроса. Скрытые контакты не ищутся
Ответы
200Успешный ответ · DialogList
Поля ответа · 1
items
массив DialogBody
обязательно
Записи страницы
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/dialogs' \
-H 'Authorization: Bearer <access>'
POST/v1/dialogs
Открывает переписку с бизнесом — по бизнесу, объекту или брони
Нужен вход
Почта подтверждена
Переписка одна на пару «гость — бизнес»: со страницы бизнеса, с объявления и из брони открывается одна и та же, объект к ней не прикрепляется — о нём пишут ссылкой. Ответ — переписка целиком, как в списке.
Тело запросаDialogOpen · application/json
partner_id
string (uuid) или null
Бизнес — со страницы бизнеса
listing_id
string (uuid) или null
Объект — с объявления
booking_id
string (uuid) или null
Бронь — бизнес этой брони
Ответы
200Успешный ответ · DialogBody
Поля ответа · 22
id
string (uuid)
обязательно
Идентификатор записи (UUID)
kind
string
обязательно
status
string
обязательно
subject
string или null
listing_id
string (uuid) или null
Объект ленты заказа (booking); у переписки с бизнесом — null
listing_title
string или null
Название объекта на языке ответа
listing_slug
string или null
Чтобы из ленты заказа открыть сам объект
listing_photo
object или null
Размеры первого снимка объекта; large может отсутствовать
booking_id
string (uuid) или null
Идентификатор брони (UUID)
partner_id
string (uuid) или null
Идентификатор бизнеса-партнёра (UUID)
partner_name
string или null
Название бизнеса
partner_logo_url
string или null
partner_kind
string или null
Раздел бизнеса (stay · experience · service · transport · food) — подпись строки
unread
integer
по умолчанию 0
last_message_at
string (date-time) или null
Момент в UTC, ISO 8601
last_message_preview
string или null
Последняя реплика без значков: текст, у голосового — длительность «0:12», у документа — имя файла
last_message_type
string или null
Вид последнего сообщения: text · photo · voice · document · event — по нему клиент рисует значок у превью
last_event_code
string или null
last_event_payload
object
contacts_hidden
boolean
по умолчанию false
Всегда false: контакты не скрываются, поле — ради старых клиентов
topic
string или null
Тема обращения в поддержку кодом; у прочих — null
last_message_mine
boolean
по умолчанию false
Последнее сообщение написал сам гость — «Вы: …» (№56)
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/dialogs' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"partner_id": "00000000-0000-0000-0000-000000000000", "listing_id": "00000000-0000-0000-0000-000000000000"}'
POST/v1/dialogs/support
Обращение в поддержку. Открытое обращение у человека одно
Нужен вход
Почта подтверждена
Тело запросаSupportOpen · application/json
subject
string или null
topic
booking | payment | listing | account | other или null
Тема кодом: ставится и открытому обращению, пока темы нет
Ответы
200Успешный ответ · DialogBody
Поля ответа · 22
id
string (uuid)
обязательно
Идентификатор записи (UUID)
kind
string
обязательно
status
string
обязательно
subject
string или null
listing_id
string (uuid) или null
Объект ленты заказа (booking); у переписки с бизнесом — null
listing_title
string или null
Название объекта на языке ответа
listing_slug
string или null
Чтобы из ленты заказа открыть сам объект
listing_photo
object или null
Размеры первого снимка объекта; large может отсутствовать
booking_id
string (uuid) или null
Идентификатор брони (UUID)
partner_id
string (uuid) или null
Идентификатор бизнеса-партнёра (UUID)
partner_name
string или null
Название бизнеса
partner_logo_url
string или null
partner_kind
string или null
Раздел бизнеса (stay · experience · service · transport · food) — подпись строки
unread
integer
по умолчанию 0
last_message_at
string (date-time) или null
Момент в UTC, ISO 8601
last_message_preview
string или null
Последняя реплика без значков: текст, у голосового — длительность «0:12», у документа — имя файла
last_message_type
string или null
Вид последнего сообщения: text · photo · voice · document · event — по нему клиент рисует значок у превью
last_event_code
string или null
last_event_payload
object
contacts_hidden
boolean
по умолчанию false
Всегда false: контакты не скрываются, поле — ради старых клиентов
topic
string или null
Тема обращения в поддержку кодом; у прочих — null
last_message_mine
boolean
по умолчанию false
Последнее сообщение написал сам гость — «Вы: …» (№56)
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/dialogs/support' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"subject": "…", "topic": "booking"}'
GET/v1/dialogs/<span class="text-brand-ink">{dialog_id}</span>/messages
Лента сообщений, новые снизу
Нужен вход
Почта подтверждена
before_id листает историю вверх, after_id добирает пропущенное вперёд: клиент, у которого не открылся сокет, спрашивает «что было после этого номера», а не «последние тридцать».
with_deleted — по запросу, а не всегда: ленту читают и клиенты, которые заглушку рисовать не умеют (лента заказа, выпущенные приложения), — у них удалённое вышло бы пустым пузырём.
Параметры
dialog_id
путь · string (uuid)
обязательно
Идентификатор диалога (UUID)
before_id
запрос · integer или null
История вверх: «дай N до этого id»
after_id
запрос · integer или null
Добор вперёд: «дай всё после этого id»
limit
запрос · integer
Сколько записей на странице
with_deleted
запрос · boolean
Вместе с удалёнными — заглушкой deleted: true без текста и файла; без флага их нет, как раньше
Ответы
200Успешный ответ · MessagePage
Поля ответа · 2
items
массив MessageBody
обязательно
Записи страницы
has_more
boolean
по умолчанию false
Есть ли следующая страница
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/dialogs/{dialog_id}/messages' \
-H 'Authorization: Bearer <access>'
POST/v1/dialogs/<span class="text-brand-ink">{dialog_id}</span>/messages
Отправляет сообщение
Нужен вход
Почта подтверждена
Перевод для собеседника ставится после ответа: это сетевой вызов к модели, и держать на нём отправителя незачем. Оригинал уйдёт сразу, перевод догонит событием message.translated.
Параметры
dialog_id
путь · string (uuid)
обязательно
Идентификатор диалога (UUID)
Тело запросаMessageSend · application/json
text
string или null
upload_id
string (uuid) или null
reply_to_id
integer или null
listing_id
string (uuid) или null
Карточка объекта над сообщением: гость пишет с объявления. Только в переписке с бизнесом и только объект этого бизнеса — иначе 400 validation_error
Ответы
200Успешный ответ · MessageBody
Поля ответа · 28
id
integer
обязательно
Идентификатор записи (UUID)
dialog_id
string (uuid)
обязательно
Идентификатор диалога (UUID)
sender_kind
string
обязательно
sender_id
string (uuid) или null
type
string
обязательно
text
string или null
Что показывать: перевод, если он есть, иначе оригинал
text_original
string или null
Как написал человек. Заполнено, только когда есть перевод
translated
boolean
по умолчанию false
Текст показан в переводе
lang
string или null
Язык: en, ru, th или zh-Hans
contacts_hidden
boolean
по умолчанию false
Всегда false: контакты не скрываются, поле — ради старых клиентов
listing_id
string (uuid) или null
Объект, с которого гость написал
listing
app__schemas__chat__ListingCard или null
Его карточка; объект снят — null при заполненном listing_id
is_official
boolean
по умолчанию false
Сообщение администрации
links
массив MessageLink
Ссылки показанного текста text
links_original
массив MessageLink
Ссылки оригинала text_original, когда есть перевод
system_code
string или null
payload
object
reply_to_id
integer или null
file_url
string или null
file_name
string или null
file_size
integer или null
duration_sec
integer или null
waveform
массив integer или null
Волна громкости голосового: 48 уровней 0–100. Пусто у документа и фото и у голосовых до 15.10.2026
width
integer или null
Ширина, px
height
integer или null
Высота, px
deleted
boolean
по умолчанию false
Удалено автором (№57): заглушка без текста, файла и перевода
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
read_at
string (date-time) или null
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/dialogs/{dialog_id}/messages' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"text": "…", "upload_id": "00000000-0000-0000-0000-000000000000"}'
POST/v1/dialogs/<span class="text-brand-ink">{dialog_id}</span>/files
Пакет документов: до десяти файлов и двадцать мегабайт суммарно
Нужен вход
Почта подтверждена
Каждый файл сначала загружается обычным POST /v1/uploads, а сюда приходят их идентификаторы. Отправка одна: для человека это одно действие, и в переписке оно должно выглядеть одним событием.
Лимит скорости — тот же, что у сообщений: пакет считается одной отправкой, иначе десять файлов упирались бы в секундный потолок на середине.
Параметры
dialog_id
путь · string (uuid)
обязательно
Идентификатор диалога (UUID)
Тело запросаFilesSend · application/json
upload_ids
массив string (uuid)
обязательно
Ответы
200Успешный ответ · массив MessageBody
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/dialogs/{dialog_id}/files' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"upload_ids": ["00000000-0000-0000-0000-000000000000"]}'
DELETE/v1/dialogs/<span class="text-brand-ink">{dialog_id}</span>/messages/<span class="text-brand-ink">{message_id}</span>
Убирает СВОЁ сообщение из переписки
Нужен вход
Почта подтверждена
Человек написал не то и хочет это убрать — обычное дело, и запрещать незачем. Из базы сообщение при этом не пропадает: спор о броне разбирается через месяцы, и «гость удалил сообщение» не должно означать «доказательств нет».
Системную запись — подтверждение брони, оплату — удалить нельзя: по ней обе стороны восстанавливают, что происходило и когда.
Параметры
dialog_id
путь · string (uuid)
обязательно
Идентификатор диалога (UUID)
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/dialogs/{dialog_id}/messages/{message_id}' \
-H 'Authorization: Bearer <access>'
POST/v1/dialogs/<span class="text-brand-ink">{dialog_id}</span>/read
Помечает прочитанным до указанного сообщения включительно
Нужен вход
Почта подтверждена
Параметры
dialog_id
путь · string (uuid)
обязательно
Идентификатор диалога (UUID)
Тело запросаapp__schemas__chat__ReadRequest · application/json
up_to_id
integer или null
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/dialogs/{dialog_id}/read' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"up_to_id": 0}'
POST/v1/uploads
Загружает вложение до отправки сообщения
Нужен вход
Почта подтверждена
Файлы в WebSocket не летят вовсе: разрыв связи посреди отправки терял бы и файл, и сообщение сразу.
Тело запросаBody_upload_v1_uploads_post · multipart/form-data
kind
string
обязательно
photo / voice / document
file
string
обязательно
Ответы
200Успешный ответ · UploadResponse
Поля ответа · 7
id
string (uuid)
обязательно
Идентификатор записи (UUID)
type
string
обязательно
file_name
string или null
file_size
integer или null
duration_sec
integer или null
Длительность голосового в секундах — измеряется при загрузке
waveform
массив integer или null
Волна громкости голосового: 48 уровней 0–100. Пусто у документа и фото и у голосовых до 15.10.2026
url
string или null
Только для фотографий: они лежат в публичном бакете. Голос и документы отдаются потоком через /v1/media
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/uploads' \
-H 'Authorization: Bearer <access>' \
-F 'file=@photo.jpg'
GET/v1/messages/<span class="text-brand-ink">{message_id}</span>/file
Приватное вложение диалога: голосовое или документ
Нужен вход
Почта подтверждена
Отдаётся потоком после проверки прав, а не ссылкой: файл лежит в приватном бакете, и ссылка из истории браузера без действующей сессии участника ничего не откроет.
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/messages/{message_id}/file' \
-H 'Authorization: Bearer <access>'
Уведомления
8 эндпоинтовЛента уведомлений, прочтение, пуш-устройства, отписка по ссылке из письма (без входа).
GET/v1/notifications
Лента: ключи и параметры, тексты собирает клиент
Нужен вход
Почта подтверждена
Название объекта в параметрах — уже на языке запроса.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
limit
запрос · integer или null
Сколько записей на странице
Ответы
200Успешный ответ · NotificationPage
Поля ответа · 4
items
массив NotificationBody
обязательно
Записи страницы
next_cursor
string или null
Курсор следующей страницы: передайте его в cursor. Нет — страница последняя. Непрозрачен: не разбирайте и не собирайте руками
has_more
boolean
по умолчанию false
Есть ли следующая страница
unread
integer
по умолчанию 0
Сколько непрочитанных всего
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/notifications' \
-H 'Authorization: Bearer <access>'
POST/v1/notifications/read
Отметить уведомления прочитанными — до up_to_id включительно или все
Нужен вход
Почта подтверждена
Ответ — {"read": сколько отмечено, "unread": сколько осталось}: число у колокольчика (/v1/me/badges) клиент берёт отсюда, без второго запроса.
Тело запросаapp__schemas__notifications__ReadRequest · application/json
up_to_id
integer или null
Без него прочитанным считается всё
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/notifications/read' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"up_to_id": 0}'
GET/v1/devices
Устройства, куда сейчас уходят пуши: с действующей сессией
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · массив DeviceBody
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/devices' \
-H 'Authorization: Bearer <access>'
POST/v1/devices
Регистрация пуш-токена. Повторный запуск приложения — обновление
Нужен вход
Почта подтверждена
Устройство записывается вместе с сессией: пуш уходит, пока сессия жива. Вышел человек или вошёл заново — клиент присылает токен ещё раз, и устройство переезжает на новую сессию. Платформы — web, android, ios.
Тело запросаDeviceRegister · application/json
push_token
string
обязательно
Токен пушей устройства (Firebase Cloud Messaging)
platform
string
обязательно
android / ios / web
app_version
string или null
Версия клиента, который прислал запрос
language
string или null
Язык: en, ru, th или zh-Hans
timezone
string или null
Часовой пояс IANA, например Asia/Bangkok; календарные даты объекта — в нём
Ответы
200Успешный ответ · DeviceBody
Поля ответа · 8
id
string (uuid)
обязательно
Идентификатор записи (UUID)
platform
string
обязательно
Платформа клиента: web, android, ios, …
app_version
string или null
Версия клиента, который прислал запрос
language
string или null
Язык: en, ru, th или zh-Hans
timezone
string или null
Часовой пояс IANA, например Asia/Bangkok; календарные даты объекта — в нём
current
boolean
по умолчанию false
Устройство этой сессии
created_at
string (date-time) или null
Момент в UTC, ISO 8601
last_seen_at
string (date-time) или null
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/devices' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"push_token": "…", "platform": "…"}'
POST/v1/devices/forget
Выключить пуши на этом устройстве — по его токену
Нужен вход
Почта подтверждена
Браузер знает свой токен, но не идентификатор строки. Чужой или незнакомый токен — тот же 204: устройство и так молчит.
Тело запросаDeviceForget · application/json
push_token
string
обязательно
Токен пушей устройства (Firebase Cloud Messaging)
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/devices/forget' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"push_token": "…"}'
POST/v1/devices/test
Тестовый пуш себе — кнопка окна разработчика
Нужен вход
Почта подтверждена
Проверяет доставку: уходит и при выключенных пушах, и в тихие часы. С токеном — только на это устройство (если оно записано на живую сессию), без токена — на все свои устройства. devices: 0 — некуда: устройство не записано, пуши здесь не включали.
Тело запросаDeviceTest · application/json
push_token
string
по умолчанию ""
Токен этого устройства; пусто — на все устройства с живой сессией
Ответы
200Успешный ответ · DeviceTestResult
Поля ответа · 4
devices
integer
обязательно
Сколько устройств нашлось; 0 — это устройство не записано
sent
integer
обязательно
Сколько FCM принял
failed
integer
обязательно
Сколько FCM отклонил
skipped
boolean
обязательно
Отправлять нечем (нет ключа Firebase) или устройство не с этого контура при выключенных исходящих
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/devices/test' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"push_token": ""}'
DELETE/v1/devices/<span class="text-brand-ink">{device_id}</span>
Забыть своё устройство: пуши на него больше не уходят
Нужен вход
Почта подтверждена
Параметры
device_id
путь · string (uuid)
обязательно
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/devices/{device_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/unsubscribe
Отписка по подписанной ссылке, без входа: выключает все уведомления роли
Без входа
Ссылка одна на все четыре роли — гостя, партнёра, модератора и админа: роль и человек лежат в токене.
Параметры
token
запрос · string
обязательно
Ответы
200Успешный ответ · UnsubscribeResult
Поля ответа · 3
ok
boolean
по умолчанию true
Успешно ли
email
string или null
Адрес, который отписан
role
string или null
Чей это аккаунт: user, partner, moderator, admin — страница ведёт в его настройки
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/unsubscribe'
Отзывы
6 эндпоинтовОтзывы гостя: оставить по завершённой брони, оценки по критериям, свои отзывы. Нужна подтверждённая почта.
GET/v1/listings/<span class="text-brand-ink">{listing_id}</span>/reviews
Отзывы объекта и средние по критериям
Без входа
Порядок, отбор по оценке и поиск нужны отдельной странице отзывов: на карточке объекта тем же эндпоинтом берутся три лучших. Средние по критериям и счётчик отбор не меняет — они по всему объекту.
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
listing_id
путь · string (uuid)
обязательно
Идентификатор объекта (UUID)
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
limit
запрос · integer или null
Сколько записей на странице
sort
запрос · string
Порядок: recent — свежие, best — лучшие, worst — худшие
rating
запрос · integer или null
Только с этой оценкой
q
запрос · string или null
Поиск по тексту отзыва
Ответы
200Успешный ответ · ListingReviews
Поля ответа · 7
items
массив ReviewBody
обязательно
Записи страницы
next_cursor
string или null
Курсор следующей страницы: передайте его в cursor. Нет — страница последняя. Непрозрачен: не разбирайте и не собирайте руками
has_more
boolean
по умолчанию false
Есть ли следующая страница
rating_avg
number или null
Средняя оценка, от 1 до 5
reviews_count
integer
по умолчанию 0
Сколько отзывов
criteria
object
Средняя по каждому критерию
sort
string
по умолчанию "recent"
Каким порядком отдана страница: recent, best или worst
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/listings/{listing_id}/reviews'
GET/v1/reviews/pending
По каким поездкам можно оставить отзыв и до какого момента
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · массив PendingBooking
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/reviews/pending' \
-H 'Authorization: Bearer <access>'
POST/v1/reviews
Отзыв об объекте по закончившейся оплаченной брони
Нужен вход
Почта подтверждена
Публикуется сразу: бизнес получает «Новый отзыв гостя» и может ответить или пожаловаться.
Тело запросаReviewCreate · application/json
booking_id
string (uuid)
обязательно
Идентификатор брони (UUID)
rating
integer
обязательно
Общая оценка 1–5
scores
object
Оценки по критериям; чужие критерии отбрасываются молча
text
string или null
Ответы
201Успешный ответ · ReviewBody
Поля ответа · 23
id
string (uuid)
обязательно
Идентификатор записи (UUID)
booking_id
string (uuid)
обязательно
Идентификатор брони (UUID)
author_kind
string
обязательно
listing_id
string (uuid) или null
Идентификатор объекта (UUID)
rating
integer
обязательно
scores
object
text
string или null
status
string
обязательно
published_at
string (date-time) или null
Момент в UTC, ISO 8601
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
reply
ReplyBody или null
author_name
string или null
Имя автора — без фамилии
author_avatar_url
string или null
listing_title
string или null
Название объекта на языке ответа
listing_slug
string или null
Чтобы из списка отзывов открыть сам объект
listing_kind
string или null
Категория объекта: по ней форма правки выбирает критерии оценки — у выхода не спрашивают ни чистоту, ни заезд
listing_photo
object или null
Размеры первого снимка объекта (thumb, medium, large может отсутствовать); в «Моих отзывах» — у каждого отзыва
booking_code
string или null
Номер брони, по которой написан отзыв
can_edit
boolean
по умолчанию false
Править можно 48 часов после публикации и пока нет ответа
can_delete
boolean
по умолчанию false
Свой отзыв автор вправе снять всегда
edited_at
string (date-time) или null
Когда отзыв правили после публикации
edit_until
string (date-time) или null
До какого момента отзыв ещё можно поправить
locked
string или null
Почему изменить уже нельзя: reply — бизнес ответил, time — 48 часов прошли
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/reviews' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"booking_id": "00000000-0000-0000-0000-000000000000", "rating": 0}'
PATCH/v1/reviews/<span class="text-brand-ink">{review_id}</span>
Правит свой отзыв — 48 часов после публикации и пока нет ответа
Нужен вход
Почта подтверждена
Ответ бизнеса относится к конкретному тексту: поменять текст после ответа значит подменить вопрос, на который уже ответили. Бизнес узнаёт о правке («Гость изменил отзыв») — читал он уже другой текст.
Параметры
review_id
путь · string (uuid)
обязательно
Идентификатор отзыва (UUID)
Тело запросаReviewUpdate · application/json
rating
integer
обязательно
Общая оценка 1–5
scores
object
text
string или null
Ответы
200Успешный ответ · ReviewBody
Поля ответа · 23
id
string (uuid)
обязательно
Идентификатор записи (UUID)
booking_id
string (uuid)
обязательно
Идентификатор брони (UUID)
author_kind
string
обязательно
listing_id
string (uuid) или null
Идентификатор объекта (UUID)
rating
integer
обязательно
scores
object
text
string или null
status
string
обязательно
published_at
string (date-time) или null
Момент в UTC, ISO 8601
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
reply
ReplyBody или null
author_name
string или null
Имя автора — без фамилии
author_avatar_url
string или null
listing_title
string или null
Название объекта на языке ответа
listing_slug
string или null
Чтобы из списка отзывов открыть сам объект
listing_kind
string или null
Категория объекта: по ней форма правки выбирает критерии оценки — у выхода не спрашивают ни чистоту, ни заезд
listing_photo
object или null
Размеры первого снимка объекта (thumb, medium, large может отсутствовать); в «Моих отзывах» — у каждого отзыва
booking_code
string или null
Номер брони, по которой написан отзыв
can_edit
boolean
по умолчанию false
Править можно 48 часов после публикации и пока нет ответа
can_delete
boolean
по умолчанию false
Свой отзыв автор вправе снять всегда
edited_at
string (date-time) или null
Когда отзыв правили после публикации
edit_until
string (date-time) или null
До какого момента отзыв ещё можно поправить
locked
string или null
Почему изменить уже нельзя: reply — бизнес ответил, time — 48 часов прошли
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/reviews/{review_id}' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"rating": 0}'
DELETE/v1/reviews/<span class="text-brand-ink">{review_id}</span>
Автор забирает свой отзыв обратно
Нужен вход
Почта подтверждена
Разрешено и после публикации: промолчать человек вправе всегда, а вот переписать сказанное задним числом — нет. Удаление мягкое: строка и текст остаются, из показа и из рейтинга отзыв уходит.
Параметры
review_id
путь · string (uuid)
обязательно
Идентификатор отзыва (UUID)
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/reviews/{review_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/reviews/my
Мои отзывы и опубликованные отзывы обо мне
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · MyReviews
Поля ответа · 2
written
массив ReviewBody
received
массив ReviewBody
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/reviews/my' \
-H 'Authorization: Bearer <access>'
Избранное
7 эндпоинтовИзбранные объекты и подборки. Нужна подтверждённая почта.
GET/v1/favorite-lists
Списки избранного вместе с числом объектов в каждом
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · массив FavoriteListResponse
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/favorite-lists' \
-H 'Authorization: Bearer <access>'
POST/v1/favorite-lists
Новый список: «Пхукет февраль», «Идеи на лето»
Нужен вход
Почта подтверждена
Тело запросаFavoriteListRequest · application/json
title
string
обязательно
Ответы
201Успешный ответ · FavoriteListResponse
Поля ответа · 5
id
string (uuid)
обязательно
Идентификатор записи (UUID)
title
string
обязательно
is_default
boolean
обязательно
listings_count
integer
обязательно
Количество
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/favorite-lists' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"title": "…"}'
PATCH/v1/favorite-lists/<span class="text-brand-ink">{list_id}</span>
Переименование списка
Нужен вход
Почта подтверждена
Параметры
list_id
путь · string (uuid)
обязательно
Тело запросаFavoriteListRequest · application/json
title
string
обязательно
Ответы
200Успешный ответ · FavoriteListResponse
Поля ответа · 5
id
string (uuid)
обязательно
Идентификатор записи (UUID)
title
string
обязательно
is_default
boolean
обязательно
listings_count
integer
обязательно
Количество
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/favorite-lists/{list_id}' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"title": "…"}'
DELETE/v1/favorite-lists/<span class="text-brand-ink">{list_id}</span>
Удаление списка вместе с закладками в нём
Нужен вход
Почта подтверждена
Список по умолчанию удалить нельзя: в него падает всё, что добавляют сердечком из ленты, и без него добавление некуда девать.
Параметры
list_id
путь · string (uuid)
обязательно
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/favorite-lists/{list_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/favorites
Объекты избранного — теми же карточками, что и в ленте, плюс цена на момент добавления
Нужен вход
Почта подтверждена
Список страницами. Ответ отдаёт next_cursor; следующую страницу просите с ним в cursor. has_more: false или нет курсора — список кончился.
Параметры
list_id
запрос · string (uuid) или null
Только этот список
limit
запрос · integer или null
Сколько записей на странице
cursor
запрос · string или null
Курсор из next_cursor прошлого ответа; без него — первая страница
Ответы
200Успешный ответ · FavoritesPage
Поля ответа · 3
items
массив FavoriteCard
обязательно
Записи страницы
next_cursor
string или null
Курсор следующей страницы: передайте его в cursor. Нет — страница последняя. Непрозрачен: не разбирайте и не собирайте руками
has_more
boolean
обязательно
Есть ли следующая страница
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/favorites' \
-H 'Authorization: Bearer <access>'
POST/v1/favorites
Положить объект в избранное
Нужен вход
Почта подтверждена
Повторное добавление ошибкой не считается: двойной тап по сердечку — это двойной тап, а не попытка обмануть сервис.
Тело запросаFavoriteRequest · application/json
listing_id
string (uuid)
обязательно
Идентификатор объекта (UUID)
list_id
string (uuid) или null
note
string или null
Заметка
Ответы
201Успешный ответ · FavoriteResponse
Поля ответа · 2
list_id
string (uuid)
обязательно
listing_id
string (uuid)
обязательно
Идентификатор объекта (UUID)
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/favorites' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"listing_id": "00000000-0000-0000-0000-000000000000"}'
DELETE/v1/favorites/<span class="text-brand-ink">{listing_id}</span>
Убрать объект из избранного — из всех своих списков сразу
Нужен вход
Почта подтверждена
Параметры
listing_id
путь · string (uuid)
обязательно
Идентификатор объекта (UUID)
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/favorites/{listing_id}' \
-H 'Authorization: Bearer <access>'
Жалобы
2 эндпоинтаПожаловаться на объект, бизнес, отзыв или сообщение. Нужен вход.
GET/v1/report-reasons
Причины для вида цели — в порядке формы, «другое» последним
Без входа
Параметры
target_kind
запрос · listing | partner | review
Ответы
200Успешный ответ · массив ReportReason
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/report-reasons'
POST/v1/reports
Жалоба на объект, бизнес или отзыв. Повтор до разбора — счётчик, а не новая
Нужен вход
Почта подтверждена
Тело запросаReportCreate · application/json
target_kind
listing | partner | review
обязательно
target_id
string (uuid)
обязательно
Идентификатор цели (UUID)
reason_code
string
обязательно
Машинный код причины
comment
string или null
Комментарий
Ответы
201Успешный ответ · ReportAccepted
Поля ответа · 4
id
string (uuid)
обязательно
Идентификатор записи (UUID)
status
string
обязательно
repeated
boolean
обязательно
created_at
string (date-time)
обязательно
Момент в UTC, ISO 8601
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/reports' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"target_kind": "listing", "target_id": "00000000-0000-0000-0000-000000000000", "reason_code": "…"}'
Заявки на подбор
1 эндпоинтЗаявка «Подберём жильё под ваш запрос»: открытая форма с капчей, дальше человека ведёт модератор.
POST/v1/leads
Оставить заявку: имя, способ связи и контакт, комментарий по желанию
Вход по желанию
Тело запросаLeadRequest · application/json
captcha_id
string
по умолчанию ""
Номер задачи капчи — ползунка-пазла, который выдаёт модуль капчи
captcha_answer
string
по умолчанию ""
Ответ на задачу капчи
name
string
обязательно
contact_kind
string
обязательно
phone / whatsapp / telegram / line
contact
string
обязательно
Номер телефона или имя в мессенджере
comment
string или null
Комментарий
Ответы
201Успешный ответ · LeadResponse
Поля ответа · 1
id
string (uuid)
обязательно
Идентификатор записи (UUID)
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/leads' \
-H 'Content-Type: application/json' \
-d '{"name": "…", "contact_kind": "…", "contact": "…"}'
Приватные файлы
2 эндпоинтаДокументы и вложения из приватного хранилища — потоком после проверки прав. Нужен вход.
GET/v1/media/<span class="text-brand-ink">{media_id}</span>
Отдаёт приватный файл потоком
Без входа
Определяем владельца одним из двух способов и только потом проверяем право: без билета — по токену, с билетом — по сессии, которой он выдан.
Параметры
media_id
путь · string (uuid)
обязательно
t
запрос · string или null
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/media/{media_id}'
POST/v1/media/<span class="text-brand-ink">{media_id}</span>/ticket
Одноразовая ссылка на 60 секунд для показа файла в <img>
Нужен вход
Почта подтверждена
Право проверяется здесь, до выдачи билета: билет — способ доставки, а не разрешение.
Параметры
media_id
путь · string (uuid)
обязательно
Ответы
200Успешный ответ · MediaTicketResponse
Поля ответа · 2
url
string
обязательно
Адрес
expires_in
integer
обязательно
Через сколько секунд истекает
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/media/{media_id}/ticket' \
-H 'Authorization: Bearer <access>'
Bounty AI
23 эндпоинтаЛичный помощник туриста: лента, сообщения текстом, голосом и с вложениями, озвучка и переводчик, блоки ответов, настройки и память. Ответ приходит событием сокета assistant.message. Нужна подтверждённая почта.
GET/v1/assistant
Работает ли помощник, сколько сообщений осталось в окне и что можно прислать
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · object
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/assistant' \
-H 'Authorization: Bearer <access>'
GET/v1/assistant/messages
Лента от старых к новым. before — листать назад, after — новые
Нужен вход
Почта подтверждена
Лента одна, тем нет: thread_id у сообщений — наследство прежних тем, клиенту разделять по нему нечего.
Параметры
before
запрос · integer или null
after
запрос · integer или null
limit
запрос · integer или null
Сколько записей на странице
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/assistant/messages' \
-H 'Authorization: Bearer <access>'
POST/v1/assistant/messages
Сообщение помощнику. 202 — вопрос сохранён, ответ пишется в фоне
Нужен вход
Почта подтверждена
В ответе — сообщение гостя, заготовка ответа (status: pending) и окно лимита. Готовый ответ приходит событием assistant.message по /v1/ws; без сокета — GET /v1/assistant/messages?after=…. Повтор с тем же Idempotency-Key возвращает то же сообщение и не тратит лимит дважды.
Ошибки: 503 assistant_unavailable; 429 assistant_limit (details.resets_at); 409 assistant_busy; 400 assistant_message_empty / assistant_text_too_long / assistant_files_too_many / assistant_files_too_large_total; 404 assistant_file_not_found.
Параметры
Idempotency-Key
заголовок · string или null
Тело запросаSendRequest · application/json
text
string
по умолчанию ""
file_ids
массив string (uuid)
Загруженные файлы, до 10
voice_id
string (uuid) или null
Загруженное голосовое
location
Location или null
«Моё местоположение»
mode
string или null
interpret — голосовое собеседника для переводчика, вместе с voice_id
Ответы
202Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"text": "", "file_ids": ["00000000-0000-0000-0000-000000000000"]}'
DELETE/v1/assistant/messages
«Очистить переписку»: прежнее скрыто у гостя, в базе остаётся
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · object
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/assistant/messages' \
-H 'Authorization: Bearer <access>'
POST/v1/assistant/greeting
Заход в помощника: приветствие, если оно положено
Нужен вход
Почта подтверждена
Клиент зовёт при каждом открытии помощника — приложение при запуске, сайт на странице /ai — с точкой устройства, если доступ к геолокации уже дан (запрашивать разрешение ради приветствия не нужно). Первый заход за окно лимита (6 ч) — в ответе новое сообщение kind: proactive, trigger: greeting (блоки greeting, events, suggestions); оно же уходит событием assistant.message на остальные устройства. Иначе — {"message": null}. Лимит сообщений не тратится. Точка сохраняется как «последнее известное место» на 30 дней в любом случае.
Тело запросаGreetingRequest · application/json
location
Location или null
Точка устройства сейчас — только если доступ к геолокации уже дан
timezone
string или null
Пояс устройства (IANA) — на случай, если места нет
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/greeting' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"location": {"lat": 0.0, "lng": 0.0}, "timezone": "…"}'
GET/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>
Одно сообщение — проверить, готов ли ответ, без сокета
Нужен вход
Почта подтверждена
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/assistant/messages/{message_id}' \
-H 'Authorization: Bearer <access>'
POST/v1/assistant/files
Файл до сообщения: фото, документ (PDF, DOCX, XLSX, CSV, TXT) или голосовое
Нужен вход
Почта подтверждена
Тип определяется по содержимому, а не по kind: kind=voice лишь говорит, что это запись (ffmpeg приведёт её к mp3). Всё ложится в приватный бакет. Ошибки: assistant_file_type, assistant_file_too_large, assistant_pdf_too_long, assistant_voice_too_long, assistant_voice_unavailable, assistant_unavailable.
Тело запросаBody_upload_v1_assistant_files_post · multipart/form-data
kind
string
по умолчанию "document"
photo · document · voice
file
string
обязательно
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/files' \
-H 'Authorization: Bearer <access>' \
-F 'file=@photo.jpg'
GET/v1/assistant/files/<span class="text-brand-ink">{file_id}</span>
Файл потоком после проверки владельца. Чужой — 404
Нужен вход
Почта подтверждена
Параметры
file_id
путь · string (uuid)
обязательно
Идентификатор файла (UUID)
size
запрос · string или null
thumb — превью фото
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/assistant/files/{file_id}' \
-H 'Authorization: Bearer <access>'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/retry
«Спросить ещё раз»: неудачный ответ снова пишется. Тратит одно сообщение
Нужен вход
Почта подтверждена
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Ответы
202Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/retry' \
-H 'Authorization: Bearer <access>'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/stop
«Остановить ответ»: заготовка — в «Вы остановили ответ» (stopped)
Нужен вход
Почта подтверждена
Клиенты кнопку больше не показывают: пока помощник отвечает, отправить новое нельзя — ждут ответа. Эндпоинт оставлен для совместимости.
Сообщение возвращается в лимит — помощник не ответил. Ответ, который уже готов, не трогается и возвращается как есть. Задача, которая пишет ответ, бросает работу на ближайшем шаге; следующий вопрос можно отправлять сразу. Повторить — POST …/retry.
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/stop' \
-H 'Authorization: Bearer <access>'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/offer
Ответ на предложение помощника: уведомление или заметка
Нужен вход
Почта подтверждена
accept у reminder_offer ставит уведомление (local_time — «Другое время»), у note_offer записывает заметку (title, text — поправленные гостем). skip — крестик: предложение скрывается. Блок получает state и номер созданного (reminder_id, note_id) на всех устройствах; повторный ответ ничего не меняет. Лимит не тратится.
Ошибки: 404 assistant_message_not_found (нет такого предложения), reminder_invalid, reminders_too_many, note_invalid, notes_too_many.
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Тело запросаOfferAnswer · application/json
block_id
string
обязательно
id блока предложения
action
string
обязательно
accept — принять, skip — отказаться
local_time
string или null
Другое время уведомления, ГГГГ-ММ-ДДTЧЧ:ММ в поясе места
timezone
string или null
Пояс другого времени
title
string или null
Поправленный заголовок
text
string или null
Поправленный текст
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/offer' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"block_id": "…", "action": "…"}'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/feedback
👍/👎 ответу. У 👎 — причина (wrong, useless, other) и текст
Нужен вход
Почта подтверждена
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Тело запросаFeedbackRequest · application/json
rating
integer или null
1 — 👍, -1 — 👎, пусто — снять
reason
string или null
wrong · useless · other
comment
string или null
Комментарий
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/feedback' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"rating": 0, "reason": "…"}'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/checklist
Галочка чек-листа. Сохраняется — видна с любого устройства
Нужен вход
Почта подтверждена
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Тело запросаChecklistRequest · application/json
item_id
string
обязательно
done
boolean
обязательно
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/checklist' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"item_id": "…", "done": false}'
POST/v1/assistant/read
Прочитано до сообщения включительно — гаснет счётчик на пункте меню
Нужен вход
Почта подтверждена
Тело запросаapp__routers__assistant__ReadRequest · application/json
up_to_id
integer
обязательно
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/read' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"up_to_id": 0}'
GET/v1/assistant/settings
Настройки помощника гостя: сообщения первым, голос, озвучка, память
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · object
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/assistant/settings' \
-H 'Authorization: Bearer <access>'
PATCH/v1/assistant/settings
Настройки помощника. Меняется только присланное
Нужен вход
Почта подтверждена
proactive— «Bounty AI пишет первым»:all,trips,off;voice— голос помощника:female,male;voice_reply— отвечать голосом на голосовое;ask_location— можно ли спрашивать точное местоположение; «Не сейчас» у запроса выключает само.
Тело запросаSettingsRequest · application/json
proactive
string или null
all · trips · off
voice
string или null
female · male
voice_reply
boolean или null
Отвечать голосом на голосовое
ask_location
boolean или null
Можно ли спрашивать точное местоположение
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/assistant/settings' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"proactive": "…", "voice": "…"}'
GET/v1/assistant/memory
Что помнит Bounty AI о госте
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ · object
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/assistant/memory' \
-H 'Authorization: Bearer <access>'
DELETE/v1/assistant/memory
Забыть всё, что помощник помнит о госте. Ответ — 204 без тела
Нужен вход
Почта подтверждена
Ответы
204Успешный ответ
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/assistant/memory' \
-H 'Authorization: Bearer <access>'
DELETE/v1/assistant/memory/<span class="text-brand-ink">{fact_id}</span>
Забыть один факт памяти помощника. Ответ — 204 без тела
Нужен вход
Почта подтверждена
Параметры
fact_id
путь · integer
обязательно
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/assistant/memory/{fact_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/speech
Озвучка потоком — для <audio src> и системного плеера
Нужен вход
Почта подтверждена
Звук уже есть — отдаётся файл из хранилища с длиной; нет — звук идёт прямо из OpenAI, пока тот говорит (первый звук через полторы секунды, а не через десять), и в конце сохраняется файлом. Что озвучить — как у POST. Отказы те же, кодом ответа: 503, 400, 404.
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
block
запрос · integer или null
Номер блока; пусто — весь ответ
item
запрос · integer или null
Номер фразы в phrases
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/assistant/messages/{message_id}/speech' \
-H 'Authorization: Bearer <access>'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/speech
Озвучить ответ помощника или одну его фразу
Нужен вход
Почта подтверждена
Без block — ответ целиком, тепло; с block — фраза блока phrases (item — её номер) или «Покажите водителю», медленно и чётко. Голос — гостя (voice в настройках). Звук создаётся один раз: повтор и другое устройство получают тот же файл. Лимит сообщений не тратится.
Ошибки: 503 assistant_speech_unavailable, 400 assistant_speech_empty, 502 assistant_speech_failed, 404 assistant_message_not_found.
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Тело запросаSpeechRequest · application/json
block
integer или null
Номер блока phrases или driver; пусто — весь ответ
item
integer или null
Номер фразы в блоке phrases
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/speech' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"block": 0, "item": 0}'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/location-request
Ответ на «Поделиться местоположением?» — пометка в блоке
Нужен вход
Почта подтверждена
Точку гость присылает обычным сообщением с location; здесь только shared или declined: кнопки гаснут на всех устройствах, модель видит ответ в истории и после отказа не спрашивает снова. Лимит не тратится. Ответ — сообщение. Другое значение или нет запроса — 404.
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Тело запросаLocationAnswer · application/json
state
string
обязательно
shared — поделился точкой, declined — «Не сейчас»
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/location-request' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"state": "…"}'
POST/v1/assistant/messages/<span class="text-brand-ink">{message_id}</span>/save-plan
«Сохранить в планы» у предложенного плана
Нужен вход
Почта подтверждена
План сохраняет гость — помощник лишь предлагает. Повтор вернёт тот же план: номер сохранённого записывается в блок (saved_plan_id), и кнопка на любом устройстве становится «Открыть план».
Параметры
message_id
путь · integer
обязательно
Идентификатор сообщения (UUID)
Тело запросаSavePlanRequest · application/json
block
integer или null
Номер блока itinerary в сообщении; пусто — первый
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/assistant/messages/{message_id}/save-plan' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"block": 0}'
Планы и уведомления
12 эндпоинтовПланы по дням, шаги, брони в днях, напоминания «за N минут» и на точное время. Нужна подтверждённая почта.
GET/v1/plans
Планы гостя: ещё не прошедшие — по дате начала, прошедшие — свежие сверху
Нужен вход
Почта подтверждена
Параметры
scope
запрос · string
upcoming · past
Ответы
200Успешный ответ · object
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/plans' \
-H 'Authorization: Bearer <access>'
POST/v1/plans
Новый план
Нужен вход
Почта подтверждена
Шаги можно прислать сразу; уведомления шагов, чьё время уже прошло, не ставятся — причина в warnings.
Тело запросаPlanCreate · application/json
title
string
обязательно
date_from
string
обязательно
Первый день, ГГГГ-ММ-ДД, в поясе места
date_to
string или null
Последний день; пусто — один день
note
string или null
Заметка
items
массив object
Записи страницы
Ответы
201Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/plans' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"title": "…", "date_from": "…"}'
GET/v1/plans/<span class="text-brand-ink">{plan_id}</span>
План целиком: дни с шагами и бронями гостя, уведомления, точки карты, пометка пояса (timezone_notice)
Нужен вход
Почта подтверждена
Параметры
plan_id
путь · string (uuid)
обязательно
Идентификатор плана (UUID)
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/plans/{plan_id}' \
-H 'Authorization: Bearer <access>'
PATCH/v1/plans/<span class="text-brand-ink">{plan_id}</span>
Название, даты, заметка
Нужен вход
Почта подтверждена
Даты, отрезающие шаги, — 400 plan_invalid (details.reason: excludes_items, details.days).
Параметры
plan_id
путь · string (uuid)
обязательно
Идентификатор плана (UUID)
Тело запросаPlanPatch · application/json
title
string или null
date_from
string или null
Первый день в поясе объекта, без времени и пояса (YYYY-MM-DD). Интервал полуоткрытый: [date_from, date_to)
date_to
string или null
День после последнего в поясе объекта, без времени и пояса (YYYY-MM-DD): для жилья — день выезда, он свободен
note
string или null
Заметка
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/plans/{plan_id}' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"title": "…", "date_from": "…"}'
DELETE/v1/plans/<span class="text-brand-ink">{plan_id}</span>
Удалить план (мягко) — его шаги и уведомления следом
Нужен вход
Почта подтверждена
Параметры
plan_id
путь · string (uuid)
обязательно
Идентификатор плана (UUID)
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/plans/{plan_id}' \
-H 'Authorization: Bearer <access>'
POST/v1/plans/<span class="text-brand-ink">{plan_id}</span>/items
Новый шаг. Ответ — план целиком и номер шага
Нужен вход
Почта подтверждена
Параметры
plan_id
путь · string (uuid)
обязательно
Идентификатор плана (UUID)
Тело запросаItemBody · application/json
day
string или null
time_from
string или null
Начало, HH:MM в поясе объекта
time_to
string или null
Конец, HH:MM в поясе объекта
title
string или null
note
string или null
Заметка
place
object или null
ref
object или null
remind_before
integer или null
За сколько минут до начала: 0, 15, 30, 60, 120, 180, 1440
done
boolean или null
Ответы
201Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/plans/{plan_id}/items' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"day": "…", "time_from": "…"}'
PATCH/v1/plans/<span class="text-brand-ink">{plan_id}</span>/items/<span class="text-brand-ink">{item_id}</span>
Правка шага, его уведомления (remind_before) и галочки «сделано»
Нужен вход
Почта подтверждена
Параметры
plan_id
путь · string (uuid)
обязательно
Идентификатор плана (UUID)
item_id
путь · integer
обязательно
Тело запросаItemBody · application/json
day
string или null
time_from
string или null
Начало, HH:MM в поясе объекта
time_to
string или null
Конец, HH:MM в поясе объекта
title
string или null
note
string или null
Заметка
place
object или null
ref
object или null
remind_before
integer или null
За сколько минут до начала: 0, 15, 30, 60, 120, 180, 1440
done
boolean или null
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/plans/{plan_id}/items/{item_id}' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"day": "…", "time_from": "…"}'
DELETE/v1/plans/<span class="text-brand-ink">{plan_id}</span>/items/<span class="text-brand-ink">{item_id}</span>
Удалить шаг (мягко) с его уведомлением
Нужен вход
Почта подтверждена
Параметры
plan_id
путь · string (uuid)
обязательно
Идентификатор плана (UUID)
item_id
путь · integer
обязательно
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/plans/{plan_id}/items/{item_id}' \
-H 'Authorization: Bearer <access>'
GET/v1/reminders
Действующие уведомления по времени, сработавшие за 30 дней и пометка каждого пояса (zones)
Нужен вход
Почта подтверждена
Ответы
200Успешный ответ
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/reminders' \
-H 'Authorization: Bearer <access>'
POST/v1/reminders
Уведомление на точное время. Такое же уже стоит — created: false и оно
Нужен вход
Почта подтверждена
Тело запросаReminderCreate · application/json
local
string
обязательно
Дата и время в поясе места: 2026-11-13T07:30
text
string
обязательно
tz
string или null
Пояс места; пусто — Asia/Bangkok
plan_id
string (uuid) или null
Идентификатор плана (UUID)
Ответы
201Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/reminders' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"local": "…", "text": "…"}'
PATCH/v1/reminders/<span class="text-brand-ink">{reminder_id}</span>
Новое время или текст. У уведомления шага время идёт за шагом
Нужен вход
Почта подтверждена
Параметры
reminder_id
путь · integer
обязательно
Тело запросаReminderPatch · application/json
local
string или null
text
string или null
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/reminders/{reminder_id}' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"local": "…", "text": "…"}'
DELETE/v1/reminders/<span class="text-brand-ink">{reminder_id}</span>
Снять уведомление. В базе остаётся со статусом cancelled
Нужен вход
Почта подтверждена
Параметры
reminder_id
путь · integer
обязательно
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/reminders/{reminder_id}' \
-H 'Authorization: Bearer <access>'
Заметки
6 эндпоинтовЗаметки гостя: текст, чек-листы, предложения помощника. Нужна подтверждённая почта.
GET/v1/notes
Заметки: закреплённые сверху, дальше — по последней правке
Нужен вход
Почта подтверждена
q — поиск (найденное — по весу: слово в заголовке важнее, чем в тексте; у заметки — mark, слово для подсветки), filter — «Все», «Закреплённые», «От Bounty AI».
Параметры
q
запрос · string
Слова в заголовке или тексте
filter
запрос · string
all · pinned · ai
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/notes' \
-H 'Authorization: Bearer <access>'
POST/v1/notes
Новая заметка. Ошибки: note_invalid, notes_too_many (500 на человека)
Нужен вход
Почта подтверждена
Тело запросаNoteCreate · application/json
title
string
обязательно
text
string
по умолчанию ""
ref
object или null
Привязка: {kind: booking | plan | listing, id}
pinned
boolean
по умолчанию false
Ответы
201Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/notes' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"title": "…"}'
GET/v1/notes/<span class="text-brand-ink">{note_id}</span>
Одна заметка; удалённая — тоже (deleted: true), чтобы её можно было вернуть
Нужен вход
Почта подтверждена
Параметры
note_id
путь · string (uuid)
обязательно
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/notes/{note_id}' \
-H 'Authorization: Bearer <access>'
PATCH/v1/notes/<span class="text-brand-ink">{note_id}</span>
Правка заметки: заголовок, текст, привязка, «Закрепить»
Нужен вход
Почта подтверждена
Параметры
note_id
путь · string (uuid)
обязательно
Тело запросаNotePatch · application/json
title
string или null
text
string или null
ref
object или null
pinned
boolean или null
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X PATCH 'https://api.bounty.travel/v1/notes/{note_id}' \
-H 'Authorization: Bearer <access>' \
-H 'Content-Type: application/json' \
-d '{"title": "…", "text": "…"}'
DELETE/v1/notes/<span class="text-brand-ink">{note_id}</span>
Удалить — мягко: вернуть можно POST …/restore
Нужен вход
Почта подтверждена
Параметры
note_id
путь · string (uuid)
обязательно
Ответы
204Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X DELETE 'https://api.bounty.travel/v1/notes/{note_id}' \
-H 'Authorization: Bearer <access>'
POST/v1/notes/<span class="text-brand-ink">{note_id}</span>/restore
«Вернуть» удалённую заметку (карточка в ленте Bounty AI)
Нужен вход
Почта подтверждена
Параметры
note_id
путь · string (uuid)
обязательно
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
401Нет входа, токен истёк или сессия закрыта — unauthorized. Обновите пару POST /v1/auth/refresh и повторите; не вышло — на вход
403Вход есть, но действие недоступно: почта не подтверждена — email_not_confirmed, аккаунт ограничен — account_restricted, нет прав — forbidden
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/v1/notes/{note_id}/restore' \
-H 'Authorization: Bearer <access>'
Связь и карта сайта
2 эндпоинтаРаздел «Связь» — тарифы SIM-карт в офисе Bounty HUB и готовая карта сайта для поисковиков. Вход не нужен.
GET/v1/connect
Офис, где оформляют SIM-карту, и тарифы на языке запроса
Без входа
Тексты тарифа — перевод на язык запроса, если он готов, иначе оригинал модератора. Покупки через сервис нет: оформление в офисе, по паспорту.
Ответы
200Успешный ответ · ConnectResponse
Поля ответа · 2
office
Office
обязательно
tariffs
массив SimTariff
Тарифы, которые продаются в офисе; пусто — цены называют на месте
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/connect'
GET/v1/seo/<span class="text-brand-ink">{name}</span>
Готовый файл карты сайта: sitemap.xml или его часть sitemap-N.xml
Без входа
Файл собирает фоновая задача раз в три часа. Ещё не собран или имя чужое — 404.
Параметры
name
путь · string
обязательно
Ответы
200Успешный ответ
400Неверные параметры или тело запроса — validation_error; в details.fields — какие поля
404Нет такого объекта или он вам не принадлежит — not_found
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/v1/seo/{name}'
Витрина в EGO
6 эндпоинтовBounty как модуль ассистента EGO: подписанные вызовы /ego/v1, не для клиентов Bounty.
GET/ego/v1/health
Проверка здоровья модуля. EGO зовёт её раз в минуту
Без входа
Подписи не требует намеренно: по этому ответу в разделе «Модули» рисуется «онлайн», и он обязан зависеть от сервиса, а не от ключа.
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X GET 'https://api.bounty.travel/ego/v1/health'
POST/ego/v1/search_listings
Поиск объектов одной из пяти категорий по фильтрам
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/search_listings'
POST/ego/v1/listing_details
Карточка объекта по адресу или идентификатору из выдачи
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/listing_details'
POST/ego/v1/search_events
Афиша города по фильтрам: день, категория, вход, время, язык
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/search_events'
POST/ego/v1/upcoming_events
Ближайшие события подборкой — по одному на событие
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/upcoming_events'
POST/ego/v1/event_details
Страница события по адресу из выдачи
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/event_details'
Витрина в EGO: аккаунт и брони
14 эндпоинтовАккаунт и брони гостя внутри EGO: подписанные вызовы, не для клиентов Bounty.
POST/ego/v1/account/status
Вошёл ли человек в Bounty, а если нет — есть ли аккаунт на его почту
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/account/status'
POST/ego/v1/account/connect
Войти в аккаунт на почту из EGO или завести его одним действием
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/account/connect'
POST/ego/v1/account/profile
Кто человек в Bounty и сколько у него броней впереди
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/account/profile'
POST/ego/v1/account/logout
Выйти: ключ EGO гасится, аккаунт остаётся
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/account/logout'
POST/ego/v1/listing/slots
Выходы объекта на день или на две недели вперёд
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/listing/slots'
POST/ego/v1/booking/quote
Сколько будет стоить бронь и что спросят перед ней
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/booking/quote'
POST/ego/v1/booking/create
Оформить бронь — тем же обработчиком, что POST /v1/bookings сайта
Без входа
Ключ идемпотентности — тот, что прислал EGO (Idempotency-Key): двойное нажатие и повтор из-за сети дают одну бронь.
Отказ по делу (места разобрали, нет телефона, не хватает участников) приходит ответом created: false с причиной словами: окно EGO показывает человеку только текст ответа, а текст ошибки — нет. Попытка откатывается целиком: бронь либо записана вся, либо её нет.
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/booking/create'
POST/ego/v1/bookings/mine
Свои брони, новые сверху: впереди, прошедшие или все
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/bookings/mine'
POST/ego/v1/bookings/details
Карточка своей брони: статус, чек, оплата, отмена, адрес, шаги
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/bookings/details'
POST/ego/v1/bookings/pay
Ссылка «Оплатить» по своей брони — и сколько, и на каких условиях
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/bookings/pay'
POST/ego/v1/bookings/messages
Лента заказа: реплики человека и партнёра, новые снизу
Без входа
Открыл ленту в окне — прочитал: счётчик непрочитанного на сайте гаснет.
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/bookings/messages'
POST/ego/v1/bookings/message
Написать партнёру в ленту заказа — тем же обработчиком, что у сайта
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/bookings/message'
POST/ego/v1/bookings/cancel_preview
Сколько вернётся, если отменить прямо сейчас, и по какому правилу
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/bookings/cancel_preview'
POST/ego/v1/bookings/cancel
Отменить свою бронь — тем же обработчиком, что у сайта
Без входа
Ответы
200Успешный ответ · object
429Слишком часто — rate_limited. Подождите столько секунд, сколько в заголовке Retry-After
500Сбой на стороне сервиса — internal_error; request_id — для поддержки
Пример
curl -X POST 'https://api.bounty.travel/ego/v1/bookings/cancel'