Процесс оплаты
Какие типы оплаты принимать при онлайн-бронировании, отель решает в панели управления. Модуль бронирования показывает этот список, и для каждого типа процесс идёт по-своему. В этом руководстве описаны четыре типа оплаты и действия для каждого из них.
Список типов оплаты#
curl "https://test.hms.gen.tr/external/online/payment/type?hotelID=1000" \
-H "Authorization: Bearer $HMS_TOKEN"{
"success": true,
"count": 3,
"items": [
{
"title": "Pay at Hotel",
"title_translate": "odeme.otelde_odeme",
"typeID": 1
},
{
"title": "Bank Transfer",
"title_translate": "odeme.havale",
"typeID": 3
},
{
"title": "Online Card Payment",
"title_translate": "odeme.online_odeme",
"typeID": 10
}
]
}| typeID | Тип | Что происходит |
|---|---|---|
1 | Оплата в отеле | Оплата не взимается; бронирование передаётся сразу. |
3 | Банковский перевод | Гостю показываются банковские счета отеля; бронирование передаётся как «ожидает оплаты». |
9 | Кредитная карта (гарантия) | Данные карты передаются в HMS вместе с бронированием в PaymentCard; списание с карты выполняет отель. |
10 | Онлайн-оплата (виртуальный POS) | HMS запускает платёжную сессию; гость переходит на платёжную страницу провайдера и возвращается на ваш returnUrl. |
Тип 1 · Оплата в отеле#
Дополнительных шагов нет. При желании можно вызвать эндпоинт и получить подтверждение:
{
"success": true,
"message": "payment_at_the_hotel"
}Тип 3 · Банковский перевод#
Получите банковские счета, которые отель включил для онлайн-продаж, и покажите их гостю:
curl -X POST "https://test.hms.gen.tr/external/online/payment/type/3" \
-H "Authorization: Bearer $HMS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"hotelID": 1000}'{
"success": true,
"message": "payment_by_bank_transfer",
"banks": [
{
"companyName": "Ziraat Bank",
"holder": "Demo Turizm A.Ş.",
"branchName": "Denizli",
"branchNumber": "0123",
"bankAccountNumber": "12345678-5001",
"iban": "TR00 0001 0001 2345 6789 5001 01"
}
]
}Если счёт не настроен, возвращается bank_info_is_not_found; в этом случае скройте этот тип из списка.
Тип 9 · Кредитная карта#
Эндпоинт лишь сообщает, что нужно запросить данные карты:
{
"success": true,
"message": "credit_card_info_should_be_requested"
}Соберите данные карты в своей форме и передайте их в поле PaymentCard каждого элемента RoomStays при передаче бронирования:
{
"PaymentCard": {
"CardHolder": {
"fullname": "Ayşe Demir",
"address": "Kumsal Cad. No: 12",
"country": "Türkiye",
"city": "Antalya"
},
"cardNumber": "5571135571135575",
"expireDate": "0329",
"cardCode": "MasterCard",
"seriesCode": "000"
}
}Тип 10 · Онлайн-оплата#
Запустите платёжную сессию с данными гостя и корзины. Все поля обязательны; об отсутствующем поле сообщают required_input_info_not_submitted и errors[].
curl -X POST "https://test.hms.gen.tr/external/online/payment/type/10" \
-H "Authorization: Bearer $HMS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"hotelID": 1000,
"totalPrice": 2330.00,
"orderID": "4811174883",
"returnUrl": "https://booking.example.com/payment/result",
"name": "Ayşe", "surname": "Demir",
"email": "[email protected]", "phone": "05551112233",
"city": "Denizli", "address": "Kumsal Cad. No: 12", "countryID": 1,
"baskets": [
{ "id": 2, "name": "Standard Room · Bed & Breakfast", "piece": 1, "price": 1930.00 },
{ "id": 12, "name": "Dinner", "piece": 1, "price": 400.00 }
]
}'const res = await fetch("https://test.hms.gen.tr/external/online/payment/type/10", {
method: "POST",
headers: { "Authorization": `Bearer ${process.env.HMS_TOKEN}`, "Content-Type": "application/json" },
body: JSON.stringify({
hotelID: 1000,
totalPrice: 2330.00,
orderID: "4811174883",
returnUrl: "https://booking.example.com/payment/result",
name: "Ayşe", surname: "Demir",
email: "[email protected]", phone: "05551112233",
city: "Denizli", address: "Kumsal Cad. No: 12", countryID: 1,
baskets: [
{ id: 2, name: "Standard Room · Bed & Breakfast", piece: 1, price: 1930.00 },
{ id: 12, name: "Dinner", piece: 1, price: 400.00 }
]
})
});
const data = await res.json();
if (!data.success) throw new Error(data.message + " " + (data.errors || []).join(", "));
// data.code — HTML-фрагмент, который передаёт гостя провайдеру: выведите его на своей странице оплаты как есть
res.send(paymentPageTemplate({ providerHtml: data.code }));{
"success": true,
"message": "payment_order_code",
"code": "<form method=\"post\" action=\"https://vpos.provider.example/3d\"><input type=\"hidden\" name=\"orderId\" value=\"4811174883\"> … </form><script>document.forms[0].submit()</script>"
}Возвращённый code — это HTML-фрагмент: в зависимости от провайдера виртуального POS отеля это автоматически отправляемая форма 3D Secure, скрипт перенаправления window.location или встроенная платёжная форма (например, iyzico). Выведите фрагмент на своей странице оплаты как есть и не пытайтесь его разбирать. Гость завершает оплату у провайдера и возвращается на ваш returnUrl; результат передаётся в добавленных к нему параметрах строки запроса (sonuc=1 — успех, sonuc=0 — неудача). Номер вашего заказа (orderID) сохраняется вместе с записью об оплате; при возврате сопоставьте его со своей записью и передавайте бронирование, только если оплата прошла успешно.
| Поле | Примечание |
|---|---|
totalPrice | Должно совпадать с итогом корзины: именно эта сумма уходит провайдеру. |
orderID | Должен быть уникальным. Если использовать ID бронирования, сверка упрощается. |
countryID | id из списка стран. |
baskets[] | Одна строка на каждый номер или дополнительную услугу. id — ID типа номера или пакета, piece — количество, price — цена за единицу. |
Прямое использование данных виртуального POS#
Если вы хотите подключаться к провайдеру со своего сервера, а не через платёжную страницу HMS, эндпоинт данных виртуального POS возвращает ID мерчанта, ключи и код провайдера. Это секретные данные: используйте их только на сервере и заранее согласуйте такой подход с HMS.
После оплаты#
- Для типа 10 передавайте бронирование после подтверждения оплаты; при неудачной оплате не передавайте его.
- Для типа 3 передавайте бронирование сразу; отель отметит перевод в панели управления, когда он поступит.
- При передаче бронирования значение
Total.amountAfterTaxesдолжно совпадать с полученной или ожидаемой к получению суммой.