emehmon · sandbox ← к дашборду Xizmat Safari · docs

Xizmat Safari (XF) — интеграция МВД ↔ E-mehmon

API двусторонней интеграции системы служебных командировок Xizmat Safari (МВД, *.imv.uz) с E-mehmon: бронирование гостиниц под госкомандировки, формирование и подписание договора, подтверждение заселения.

В отличие от CRM Hotel API, XF — прямая интеграция: Xizmat Safari ходит напрямую в E-mehmon (POST /api/xf-api), без промежуточного шлюза.

Направления обмена

Xizmat Safari (МВД)                         E-mehmon
        │                                          │
        │ ①  POST /api/xf-api  {method,data,...}    │
        │ ─────────────────────────────────────►   │
        │ ◄─────────────────────────────────────   │  {data,message,code}
        │                                          │
        │ ②  уведомления о статусе/договоре/QR       │
        │ ◄─────────────────────────────────────   │

① Входящие (МВД → E-mehmon) — единое окно POST /api/xf-api, 7 методов (см. ниже).

② Исходящие (E-mehmon → МВД) — E-mehmon отправляет уведомления на согласованные с МВД endpoint'ы по ходу жизненного цикла брони:

Уведомление HTTP Endpoint Когда
Смена статуса брони POST /api/v1/booking/emehmon/response/ отель принял/отклонил бронь
Статус договора POST /api/v1/ehotel/booking_accept/ смена статуса договора
Готовый договор GET /api/v1/booking/contract/emehmon-preview/ E-mehmon забирает сформированный договор
Подтверждение заселения POST /api/v1/booking/contract/emehmon-confirm/ заселение подтверждено (QR + PINFL)
Подтверждение выезда POST /api/v1/booking/contract/emehmon-checkout/ гость выехал (dateVisitOff выставлен)
Проверка ЭЦП (E-IMZO) POST imzo.emehmon.uz:8080/backend/auth проверка электронной подписи

Транспорт и аутентификация

POST /api/xf-api, Content-Type: application/json. Две независимые проверки:

1. IP-allowlist

Запросы принимаются только с заранее согласованных IP-адресов гейтвея МВД. Запрос с неразрешённого адреса → 401.

2. Подпись hash

Поле hash в теле запроса — SHA1 от строки id_request, секретного ключа и method:

hash = sha1(id_request + "-" + secret + "-" + method)

secret — выданный вам ключ. Сравнение регистронезависимое (hash передавайте в lowercase).

Формат запроса/ответа

Запрос:

{
  "method": "hotel-list",
  "id_request": "req-001",
  "data": { "region_id": 1703, "page": 1 },
  "hash": "<см. выше>"
}

Ответ (единый конверт):

{ "data": { /* ... */ }, "message": "success", "code": 200 }

Обязательные поля запроса: method, data, hash, id_request (отсутствие любого → 401).

Методы

method Назначение Ключевые data
hotel-list Список отелей региона (стр. по 20) region_id (COATO), page; опц. district_id (sp_id), hotel_type_id
hotel-info Карточка отеля: номера, цены, занятость hotel_id
hotel-photos Фото отеля hotel_id
make-booking Создать бронь под командировку hotel_id, checkin_date, checkout_date, organization_name, organization_tin, contact_phone, rooms_qty, doc_number, pinfl, dtb, staffname, room_id
booking-single Одна бронь по id booking_id
booking-doc-status МВД сообщает статус договора (Confirmed → E-mehmon забирает договор) booking_id, booking_status
cancel-booking Отмена брони (статусы new/paid/partly_paid/accepted) booking_id; опц. reason

region_id/district_id в запросах — это коды COATO/SP (как в официальном классификаторе), а не внутренние id. room_id в make-booking — это значение id из массива rooms[] ответа hotel-info.

Идемпотентность

Каждый запрос несёт уникальный id_request. Повторный запрос с тем же id_request, по которому уже сформирован ответ, возвращает тот же ответ без повторной обработки (защита от сетевых ретраев).

Жизненный цикл брони

make-booking → status=new
   │  (отель принимает/отклоняет бронь)
   ├─ accept  → status=accepted   → POST /emehmon/response/  (notifyStatusChange)
   └─ reject  → status=rejected   → POST /emehmon/response/  (notifyStatusChange)
        │
   МВД формирует договор → booking-doc-status (Confirmed)
        │
   E-mehmon GET emehmon-preview/ → забирает договор (contract_hashing, document)
        │
   договор Accepted → POST /ehotel/booking_accept/  (notifyContractStatus)
        │
   подтверждение заселения → POST emehmon-confirm/ (QR + PINFL + фото)
        │                     → contract_status=Accepted, листок создан
   гость проживает
        │
   выезд гостя (dateVisitOff) → POST emehmon-checkout/ (contract_uuid + datetime)

Заселение создаёт регистрацию (листок) и запускает соответствующие госуведомления. Выезд (confirmCheckout) срабатывает автоматически при выселении гостя в кабинете. В песочнице эти побочные эффекты отключены/застаблены — см. sandbox.md.

Песочница Xizmat Safari

Песочница доступна снаружи как sandbox-api.emehmon.uz, где интеграторы МВД тестируют интеграцию Xizmat Safari (/api/xf-api) на фейковых данных, не затрагивая прод и не вызывая реальные госуведомления.

[!NOTE] Статус (2026-05-26): развёрнута и работает. Приём hotel-list через sandbox-api.emehmon.uz/api/xf-api200; дашборд /sandbox/xf + эмуляция действий отеля проверены; документация — /sandbox/xf/docs. Endpoint, тестовый ключ и эта документация переданы интеграторам.

Чем отличается от прода

Прод (emehmon.uz) Песочница (sandbox-api.emehmon.uz)
База данных боевая отдельная sandbox-БД
Госуведомления (СГБ/ГНИ/ГТК) реальные отключены
Проверка иностранцев реальная застаблена — любой «подтверждён»
KOGG/виза при заселении реальный вызов застаблен — фейковые данные
Уведомления о статусе/договоре в боевой контур МВД в dev-контур МВД
Telegram-алерты об ошибках боевой чат выключены
Контракт, hash, IP-allowlist, идемпотентность, коды ошибок идентичны проду

Песочница повторяет реальный контракт /api/xf-api — отличаются только данные и отключённые/застабленные побочные эффекты.

Доступ

Фейковые данные

Администратор засевает в песочнице тест-данные:

Вам передают готовые значения: hotel_id, region_id (COATO для hotel-list), district_id (sp_id), price_id (= room_id для make-booking), booking_id и готовую curl-команду smoke-теста с валидным SHA1-hash.

Справочники (регионы/районы с COATO, типы номеров) — настоящие коды.

Дашборд и эмуляция действий — /sandbox/xf

https://sandbox-api.emehmon.uz/sandbox/xf:

new ──[Принять]──► accepted ──[Договор: Accepted]──► (Accepted)
          │                                              │
       [Отклонить] → rejected            [Забрать договор] → договор сохранён
                                                           │
                                              [Подтвердить заселение] → QR

Каждая кнопка прогоняет тот же сценарий, что прод-кабинет, и шлёт соответствующее уведомление в МВД — так интегратор прогоняет полный двусторонний цикл без логина в кабинет.

Сброс

На дашборде кнопка «Сбросить» очищает журнал входящих и XF-брони; тест-отель, номера, прайс и справочники остаются — удобно начать тесты с чистого листа.

Примеры запросов

Python (рабочий SHA1):

import hashlib, json, requests

BASE   = "https://sandbox-api.emehmon.uz/api/xf-api"
SECRET = "<ваш тестовый ключ>"

def call(method, data, id_request):
    h = hashlib.sha1(f"{id_request}-{SECRET}-{method}".encode()).hexdigest()
    body = {"method": method, "id_request": id_request, "data": data, "hash": h}
    r = requests.post(BASE, json=body, verify=False)  # verify=False — если самоподписанный
    print(r.status_code, json.dumps(r.json(), ensure_ascii=False, indent=2))
    return r.json()

# 1. Список отелей региона (region_id — COATO, переданный администратором)
call("hotel-list", {"region_id": 1703, "page": 1}, "req-001")

# 2. Создать бронь (room_id = price_id из hotel-info)
call("make-booking", {
    "hotel_id": 123, "checkin_date": "2026-06-01", "checkout_date": "2026-06-03",
    "organization_name": "Test Org", "organization_tin": "999999999",
    "contact_phone": "+998900000000", "rooms_qty": 1,
    "doc_number": "CMD-001", "pinfl": "00000000000000",
    "dtb": "1990-01-01", "staffname": "Test Xodim", "room_id": 456,
}, "req-002")

curl (hash вычислить заранее: echo -n "req-001-<SECRET>-hotel-list" | sha1sum):

curl -sk https://sandbox-api.emehmon.uz/api/xf-api \
  -H 'Content-Type: application/json' \
  -d '{"method":"hotel-list","id_request":"req-001","data":{"region_id":1703,"page":1},"hash":"<sha1>"}'

Поведение callback'ов в песочнице

По запросу администратор включает отправку уведомлений (callback'ов) в ваш dev-контур МВД. В песочнице они отправляются синхронно (в проде часть из них идёт асинхронно), а забор договора и подтверждение заселения работают как на проде. Если callback'и не нужны — их можно отключить (останется только приём входящих запросов).

Ограничения