Bounty API Пользователи

Открытый 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» ниже.
  • Фотографии — до трёх размеров (thumb 480, medium 1600, large 2560). large существует не всегда; клиент обязан пережить его отсутствие и показать medium.

Сокет /v1/ws

Swagger сокетов не показывает, поэтому всё о нём — здесь. Адрес: wss://api.bounty.travel/v1/ws?token=… или …?ticket=…. Заголовок Authorization браузерному WebSocket не поставить, поэтому вход — параметром адреса:

  • token — токен доступа (приложения и боты).
  • ticket — одноразовый билет из POST /v1/auth/ws-ticket для веб-страницы, у которой токена нет (он в cookie HttpOnly): живёт минуту и открывает один сокет.

Почта должна быть подтверждена — иначе соединение закрывается так же, как с плохим токеном.

Отказ во входе — закрытие с кодом 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.

Аутентификация

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/<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'