Innprices
Resumo do payload e regras de precificacao.
Endpoint
POST /omnibees/:id
POST /hbook/:id
Base URL: https://prices.innsights.com.br
O service recebe um provider do tipo
HotelPriceProvider; por padrao usa Omnibees.
O endpoint /hbook/:id usa o provider Hbook e
envia um POST para
/Booking/GetAvailability.
O controller do Hbook segue o mesmo fluxo do Omnibees, trocando apenas o provider.
A implementacao do controller do Hbook replica o do Omnibees, mudando somente o provider injetado.
No provider Omnibees, a URL de consulta e o
fetch sao executados dentro de
getData no crawler.
Cada provider implementa buildBookingUrl e
define urlField, o nome do campo em que a URL
do motor aparece na resposta (Omnibees usa
omnibeesUrl; Hbook usa url).
O service repassa buildBookingUrl e
urlField do provider ao response builder; se a
geracao da URL falhar, o campo retorna vazio.
Token obrigatorio via query string:
?token={{secreto}}
Token invalido retorna status 401.
Body esperado
{
"checkin": "2025-12-15T03:15:00.000Z",
"checkout": "2025-12-18T03:00:00.000Z",
"adults": 1,
"childrens": 0,
"ages": "",
"code": "",
"template": [
"*PARA:* {{adults}} adulto(s)",
"Periodo: {{checkin|date}} a {{checkout|date}}"
],
"order": {
"nameList": ["Suite Luxo", "Suite premium"],
"rateNameList": ["Tarifa VIP", "Tarifa Flex"],
"ratePrice": "asc"
},
"filters": {
"roomName": "Suite Luxo"
},
"rules": {
"baseline": "price",
"markup": { "value": 10 },
"discount": { "value": 10, "category": "discount" },
"bookingWindow": {
"window": 21,
"less": { "midweek": 20, "weekend": 25 },
"more": 25,
"category": "discount"
},
"installment": { "times": 4, "withEntry": true, "entryPercent": 30 }
}
}
Campos
- RoomPriceDTO: estrutura base usada pelo crawler e pelas regras para representar quartos e tarifas.
-
id (path): valor usado no parametro
qda URL Omnibees. -
checkin / checkout:
datas ISO; sao convertidas para formato
ddmmyyyy. -
period: calculado pelo dia do checkin
(
midweekouweekend). -
bookingWindowDays: antecedencia da
reserva em dias (hoje ate o checkin, em UTC). Negativo
quando o checkin ja passou;
nullquando a data nao parseia. E o mesmo numero que a regrabookingWindowusa para decidir entrelessemore. - adults: precisa ser maior ou igual a 1.
- childrens: numero de criancas.
-
ages: string com idades separadas por
virgula (ex.:
"1,3"); quantidade deve bater comchildrens. -
code: codigo opcional que vai para o
parametro
Codeda Omnibees; quando informado ignora regras comcategoryigual adiscount. -
discount: percentual retornado pelas
regras ou pelo
code(ex.:WEB05retorna5). No Hbook, quando a tarifa possuiAppliedOffer.OfferName(ex.:40% OFF), o percentual e convertido para numero e preenchido emdiscount. Regra ignorada nao entra aqui: comcodeinformado o campo nunca repeterules.discount.value— se nada reduzir o preco,discountvolta0. -
engineDiscount: percentual da oferta
que o proprio motor de reservas ja tinha aplicado no
finalPricee querules.baseline: "price"descartou. Aparece somente quando o descarte realmente acontece (ou seja, quando alguma regra seguinte ajusta o preco) — serve para o consumidor da API nao perder o sinal da oferta depois que odiscounte limpo. -
template: string, array de strings ou
nullcom placeholders (retornamessageoumessage_1,message_2...). -
order: objeto opcional ou
nullque define o criterio de ordenacao dos quartos. -
filters: objeto opcional ou
nullcom filtros adicionais sobre os quartos retornados. -
rules: objeto opcional ou
nullcombaselinee regras derate,markup,discount,bookingWindoweinstallment. -
price: valor base do crawler; ao ler
atributo
data-price-before-discountde cada.rate_plan;finalPricevem do atributodata-original-price-after-tax. O texto dentro de.price-total-bolde ignorado.
Order (Strategy)
O order define como a lista de quartos e ordenada antes de escolher o primeiro item. Ele segue o mesmo padrao Strategy das regras.
A aplicacao de order e filters e
feita no service, antes de selecionar o quarto retornado
pelo crawler.
nameList
Lista de nomes em ordem de prioridade. O primeiro nome encontrado vira o resultado. Qualquer nome fora da lista fica depois, mantendo a ordem original.
"order": {
"nameList": ["Suite Luxo", "Suite premium", "Standard"]
}
rateNameList
Lista de nomes de tarifas em ordem de prioridade. Reordena o
campo rates
dentro de cada quarto e usa a primeira tarifa como base do
preco.
"order": {
"rateNameList": ["Tarifa VIP", "Tarifa Flex", "Tarifa Standard"]
}
ratePrice
Ordena as tarifas por preco dentro de cada quarto e usa a
primeira tarifa como base. Valores:
"asc" (menor preco) ou
"desc" (maior preco).
"order": {
"ratePrice": "desc"
}
price
Ordena por preco quando nameList nao e
informado. Valores: "asc" ou
"desc".
A ordenacao por preco usa o valor selecionado das tarifas; se nenhuma regra de tarifa for aplicada, o preco pode ficar nulo e a ordem original e mantida.
"order": {
"price": "asc"
}
Filters
Os filtros sao aplicados apos o order e antes das regras. Se
nenhum quarto atender ao filtro, retorna
room_unavailable.
roomName
Filtra pelo nome exato do quarto retornado pela Omnibees.
Se vazio, o filtro nao e aplicado.
"filters": {
"roomName": "Suite Luxo"
}
Rules (Strategy)
As regras sao aplicadas no retorno do crawler via Strategy. Cada regra transforma o item (nome e preco) e retorna o mesmo item ajustado.
O campo comments e normalizado para um array
antes de adicionar novas mensagens de regras.
Regras de desconto nao se somam: cada nova regra sobrescreve
o
finalPrice gerado pela anterior.
baseline
Escolhe sobre qual preco as regras vao operar:
"finalPrice" (padrao) ou "price".
Omitir o campo mantem exatamente o comportamento de sempre.
O motor de reservas pode devolver o finalPrice
ja com uma oferta propria aplicada sobre o rack. No Hbook
ela vem de AppliedOffer.OfferName: por exemplo
price 985.71, finalPrice 837.8535
e discount 15. Como as regras partem do
finalPrice, um rate de
-30 cascateia sobre essa oferta e entrega 40,5%
efetivos sobre a tarifa OTA (15% + 0.85 * 30% = 586.50), e
nao os 30% pedidos.
Com "baseline": "price" a oferta do motor e
descartada antes de qualquer regra rodar
(finalPrice = price) e toda a cadeia
(rate, markup,
discount, bookingWindow,
installment) passa a operar a partir do rack.
No exemplo acima, -30 resulta em 690.00.
O percentual original nao se perde: vai para o campo
engineDiscount da resposta. O
discount e limpo no reset — ele descrevia uma
oferta que nao corresponde mais ao finalPrice —
e as regras seguintes voltam a preenche-lo normalmente. Um
comment registra o descarte:
engine offer 15% discarded (baseline=price).
Quando o motor nao trouxe oferta alguma o reset e inocuo:
nao gera comment nem engineDiscount.
Nao e ignorado quando code e
informado: e selecao de base de calculo, nao uma concessao
comercial — mesmo racional do rate.
O reset e condicional
O reset so acontece quando alguma regra seguinte de fato vai
ajustar o finalPrice. Cotar a tarifa cheia serve
para aplicar um desconto negociado sobre ela; sem desconto
nenhum para conceder, devolver o hospede ao rack seria tirar
a oferta publica do motor sem contrapartida. Quando nenhuma
regra ajusta o preco, baseline vira no-op total:
a resposta fica identica a de uma requisicao sem o campo —
sem comment e sem engineDiscount.
Contam como ajuste de preco:
-
rate: valor numerico finito, diferente de0e maior que-100. String vazia ("", o que chega quando o campo do contato esta em branco),0, espacos em branco ou texto nao numerico nao contam — a menos que umdefaultValuelegivel assuma o lugar dovaluevazio, e ai o percentual do padrao e que conta. -
discount: valor numerico finito maior que0e que nao esteja sendo ignorado pelocode. -
bookingWindow: percentual resolvido para ocheckinem questao (less/more,midweek/weekend) maior que0e que nao esteja sendo ignorado pelocode.
Nao contam: markup, que altera
o price e nao o finalPrice, e
installment, que apenas parcela o valor que ja
existe.
Com rack 985.71 e oferta de 15% do motor
(finalPrice 837.8535):
| rules | finalPrice | Reset |
|---|---|---|
{ "baseline": "price" } |
837.8535 | Nao |
+ "rate": { "value": "" }
|
837.8535 | Nao |
+ "rate": { "value": 0 }
|
837.8535 | Nao |
+ "rate": { "value": -30 }
|
690.00 | Sim |
+ "discount": { "value": 30 }
|
690.00 | Sim |
+ "discount": { "value": 30 }
com code informado
|
837.8535 | Nao (regra ignorada) |
+ "markup": { "value": 10 }
|
837.8535 | Nao |
+ "installment": { "times": 3 }
|
837.8535 | Nao |
"rules": {
"baseline": "price",
"rate": { "value": -30 }
}
rate
Aplica o tipo de tarifa sobre o preco final. Formula:
finalPrice = finalPrice * (1 + valor/100).
Valor negativo reduz: -25 => multiplica por
0.75. O rack permanece intacto em price — a
resposta traz "De price por
finalPrice" — e o ajuste nao preenche o campo
discount.
Roda antes das outras regras — so a selecao de
baseline vem antes — e nao e
ignorada quando code e informado: e o tipo de
tarifa, nao uma concessao. Um discount aplicado
depois compoe sobre o valor ja tarifado (25% de tarifa +
10% de desconto = 32,5% sobre o rack, nao 35%).
Valores 0 ou menores/iguais a -100
sao ignorados.
"rules": {
"rate": { "value": -25 },
"discount": { "value": 10 }
}
defaultValue
rate.defaultValue e opcional e entra em cena
quando value nao traz numero algum para ler —
string vazia ("", o que chega quando o campo do
contato esta em branco), so espacos ou texto nao numerico.
Nesses casos a regra tarifa pelo padrao em vez de virar
no-op. Aceita numero ou string numerica, igual ao
value.
0 (ou "0") nao
aciona o padrao: zero e escolha explicita de "sem desconto",
nao ausencia de valor. Se defaultValue tambem
nao for legivel, a regra segue no-op como antes.
O percentual do padrao e resolvido antes de tudo, entao ele
tambem conta como ajuste de preco para o
baseline: "value": "" com
"defaultValue": -20 reseta a base e cota os 20%
sobre o rack. Quando o padrao e usado, o comment sai como
rate: -20% (defaultValue), distinguindo do
rate: -20% pedido explicitamente.
"rules": {
"baseline": "price",
"rate": { "value": "", "defaultValue": -20 }
}
| value | defaultValue | Percentual aplicado |
|---|---|---|
-25 |
-15 |
-25% (o pedido vence) |
"" |
-15 |
-15% (padrao) |
"abc" |
-15 |
-15% (padrao) |
0 |
-15 |
nenhum — zero e explicito |
"" |
ausente | nenhum — no-op |
"" |
"" |
nenhum — no-op |
markup
Corrige o preco base usando markup. Formula:
preco_corrigido = preco / (1 - percentual/100).
Exemplo: 10% => divide por 0.90.
Quando markup e aplicado, o campo
discount retorna o mesmo percentual para
facilitar templates que exibem desconto.
"rules": {
"markup": { "value": 10 }
}
discount
rules.discount.value e um percentual (ex.: 10 =
10%). O desconto e aplicado diretamente no
finalPrice de cada item.
Categoria: discount. Quando code e
informado, regras com essa categoria nao sao aplicadas.
bookingWindow
Aplica desconto com base na antecedencia entre hoje e o
check-in. Usa window para decidir entre
less e more.
less aplica quando dias_antecedencia <=
window. more aplica quando dias_antecedencia
> window. Os valores podem ser numero (percentual fixo)
ou objeto { midweek, weekend }.
Weekend padrao: qui, sex, sab (o resto e midweek). O campo
opcional weekendDays reescreve essa definicao
com nomes de dias em ingles; qualquer dia fora da lista
conta como midweek. O campo period da resposta
segue a mesma definicao.
"rules": {
"bookingWindow": {
"window": 21,
"less": { "midweek": 25, "weekend": 20 },
"more": 25,
"weekendDays": ["friday", "saturday", "sunday"]
}
}
Categoria: discount. Quando code e
informado, regras com essa categoria nao sao aplicadas.
installment
Divide o valor final em parcelas. Quando
withEntry e verdadeiro, calcula entrada com
base no percentual e parcela o restante.
"rules": {
"installment": { "times": 4, "withEntry": true, "entryPercent": 30 }
}
Code
Quando code e informado, regras com
category igual a discount
nao sao aplicadas.
Codigos no formato WEB## (ex.:
WEB05) retornam o percentual no campo
discount.
Para os demais codigos o campo discount vem da
diferenca entre price e
finalPrice — o desconto que o motor de reservas
de fato concedeu. Quando essa diferenca e zero (ex.: a
tarifa nao tem oferta do motor e a regra
discount foi ignorada pelo code),
a resposta traz discount: 0 em vez do
percentual da regra que nao rodou.
Erros
-
adults_required: adults precisa ser maior ou igual a 1. -
ages_required: ages e obrigatorio quando childrens > 0. -
ages_count_mismatch: quantidade de idades nao bate com childrens. -
invalid_date: checkin ou checkout invalido, ou checkout anterior ao checkin (Omnibees e Hbook). -
unavailable: hotel sem disponibilidade. -
minimum_nights: reserva exige minimo de noites. -
room_unavailable: nenhum quarto atende ao filtro de nome. -
too_many_people: ha quartos, mas a ocupacao solicitada e alta. Detectado quando a Omnibees mostra a tela de grupos (.no-rooms-avail-info-bar) ou nenhum quarto, e a re-consulta com 1 adulto encontra disponibilidade. unknown_error: erro inesperado.-
internal_server_error: falha inesperada no controller (retorna status500e registra nolog.errorjunto comparamsebodyda requisicao).
Template (Message)
O campo template permite montar um texto usando
as variaveis do resultado. Use
{{'{{'}}campo{{'}}'}} para interpolar valores.
Aceita string unica ou array de strings. Quando for array, o
retorno inclui
message_1, message_2 e assim por
diante.
*PARA:* {{adults}} adulto(s){{childrens|if: e {{childrens}} crianca(s) com idades {{ages}}:}}
*PERIODO:* {{checkin|date}} a {{checkout|date}}
*Check-in:* A partir das 16h
*Check-out:* Ate as 14h
*Acomodacao:* _{{name}}_ - {{finalPrice|currency}}
*Forma de pagamento:*
Sinal de {{entryValue|currency}} via Pix no ato da reserva;
Saldo restante em ate {{times}}x de {{installment|currency}} sem juros no check-in.
*Tarifa valida somente ate as 23h59 de hoje!*
Filtros disponiveis:
-
currency: formata numero como moeda BRL. -
date: formata data ISO paradd/mm/aaaa. -
if:THEN:ELSE: renderiza o texto se o valor for verdadeiro (numero > 0).
Campos disponiveis no template:
| Campo | Descricao | Quando aparece |
|---|---|---|
name |
Nome da acomodacao. | Sempre, quando ha resultado. |
price |
Preco original (sem desconto). | Sempre, quando ha resultado. |
finalPrice |
Preco final apos regras. | Sempre, quando ha resultado. |
discount |
Percentual aplicado
(discount/bookingWindow/markup) ou code
(ex.: WEB05).
|
Quando alguma regra alterar o preco. |
engineDiscount |
Percentual da oferta do motor de reservas
descartada por
rules.baseline: "price".
|
Somente quando o motor trouxe oferta, o
baseline e price e alguma regra
seguinte ajusta o finalPrice.
|
checkin |
Data de check-in (ISO). | Sempre (input). |
period |
Periodo calculado pelo dia do check-in
(midweek ou
weekend).
|
Sempre (gerado). |
checkout |
Data de check-out (ISO). | Sempre (input). |
adults |
Numero de adultos. | Sempre (input). |
childrens |
Numero de criancas. | Sempre (input). |
ages |
Idades das criancas (texto). | Sempre (input). |
code |
Codigo promocional enviado para a Omnibees. | Somente quando informado. |
rules |
Objeto com regras recebidas. | Sempre (input). |
template |
Texto original do template. | Sempre (input). |
omnibeesUrl |
URL final gerada pelo
buildBookingUrl do provider
Omnibees (urlField =
omnibeesUrl); pode ficar vazia
quando a geracao da URL falhar.
|
Nas respostas do provider Omnibees. |
url |
URL final gerada pelo
buildBookingUrl do provider
Hbook (urlField =
url).
|
Nas respostas do provider Hbook. |
comments |
Lista de aplicacoes de regras. Inclui
"promotional code is applied" quando
code e informado no service.
Quando uma
regra for ignorada, inclui o motivo em
texto.
|
Quando alguma regra rodar ou for ignorada. |
entryValue |
Valor da entrada. |
Somente com regra installment e
withEntry.
|
entryPercent |
Percentual de entrada. |
Somente com regra installment e
withEntry.
|
remaining |
Valor restante apos a entrada. |
Somente com regra installment.
|
installment |
Valor de cada parcela. |
Somente com regra installment.
|
times |
Quantidade de parcelas. |
Somente com regra installment.
|
Exemplo completo
Request
{
"checkin": "2026-01-17T03:15:00.000Z",
"checkout": "2026-01-18T03:00:00.000Z",
"adults": 2,
"childrens": 0,
"ages": "",
"code": "",
"rules": {
"discount": { "value": 50, "category": "discount" },
"installment": { "times": 4, "withEntry": true, "entryPercent": 30 }
},
"template": [
"*🏨 PARA:* {{adults}} adulto(s){{childrens|if: e {{childrens}} criança(s) com idades {{ages}}:}}\n📅 *PERÍODO:* {{checkin|date}} a {{checkout|date}}\n\n*Check-in:* A partir das 16h\n*Check-out:* Até as 14h\n\n*Acomodação:* _{{name}}_ - {{finalPrice|currency}}\n\n*💳 Forma de pagamento:*\nSinal de {{entryValue|currency}} via Pix no ato da reserva;\nSaldo restante em até {{times}}x de {{installment|currency}} sem juros no check-in.\n\n*⏳ Tarifa válida somente até as 23h59 de hoje!*",
"Estamos concedendo *{{discount}}% de desconto* e sua reserva sai de {{price|currency}} por apenas *{{finalPrice|currency}}*.\n\nSinal de {{entryPercent}}% no valor de {{entryValue|currency}} e o restante parcelado em {{times}}x de {{installment|currency}} pagos no check-in.\n\n*Oferta exclusiva para fechamento hoje!*"
]
}
Response
{
"status": "available",
"name": "Superior Casal",
"price": 687,
"finalPrice": 343.5,
"comments": [
"discount: 50%",
"installment: entry 30% + 4x 60.11"
],
"entryValue": 103.05,
"entryPercent": 30,
"remaining": 240.45,
"installment": 60.11,
"times": 4,
"discount": 50,
"id": "6605",
"checkin": "2026-01-17T03:15:00.000Z",
"period": "weekend",
"checkout": "2026-01-18T03:00:00.000Z",
"adults": 2,
"childrens": 0,
"ages": "",
"code": "",
"omnibeesUrl": "https://book.omnibees.com/hotelresults?q=6605¤cyId=16&lang=pt-BR&hotel_folder=&NRooms=1&version=4&CheckIn=17012026&CheckOut=18012026&ad=2&ch=0&ag=&Code=",
"rules": {
"discount": { "value": 50, "category": "discount" },
"installment": { "times": 4, "withEntry": true, "entryPercent": 30 }
},
"template": [
"*🏨 PARA:* {{adults}} adulto(s){{childrens|if: e {{childrens}} criança(s) com idades {{ages}}:}}\n📅 *PERÍODO:* {{checkin|date}} a {{checkout|date}}\n\n*Check-in:* A partir das 16h\n*Check-out:* Até as 14h\n\n*Acomodação:* _{{name}}_ - {{finalPrice|currency}}\n\n*💳 Forma de pagamento:*\nSinal de {{entryValue|currency}} via Pix no ato da reserva;\nSaldo restante em até {{times}}x de {{installment|currency}} sem juros no check-in.\n\n*⏳ Tarifa válida somente até as 23h59 de hoje!*",
"Estamos concedendo *{{discount}}% de desconto* e sua reserva sai de {{price|currency}} por apenas *{{finalPrice|currency}}*.\n\nSinal de {{entryPercent}}% no valor de {{entryValue|currency}} e o restante parcelado em {{times}}x de {{installment|currency}} pagos no check-in.\n\n*Oferta exclusiva para fechamento hoje!*"
],
"message_1": "*🏨 PARA:* 2 adulto(s)\n📅 *PERÍODO:* 17/01/2026 a 18/01/2026\n\n*Check-in:* A partir das 16h\n*Check-out:* Até as 14h\n\n*Acomodação:* _Superior Casal_ - R$ 343,50\n\n*💳 Forma de pagamento:*\nSinal de R$ 103,05 via Pix no ato da reserva;\nSaldo restante em até 4x de R$ 60,11 sem juros no check-in.\n\n*⏳ Tarifa válida somente até as 23h59 de hoje!*",
"message_2": "Estamos concedendo *50% de desconto* e sua reserva sai de R$ 687,00 por apenas *R$ 343,50*.\n\nSinal de 30% no valor de R$ 103,05 e o restante parcelado em 4x de R$ 60,11 pagos no check-in.\n\n*Oferta exclusiva para fechamento hoje!*"
}