{"openapi":"3.1.0","info":{"title":"API do HotelGestão","version":"1.0.0","description":"API REST do HotelGestão para sites, channel managers, chatbots, BI e automações.\n\n**Autenticação:** `Authorization: Bearer hg_…` (ou `x-api-key: hg_…`). A chave é criada pelo dono do hotel em Configurações → Integrações → Canais → API, com escopo *somente leitura* ou *leitura e escrita*, e aparece uma única vez.\n\n**Datas:** estadias em `AAAA-MM-DD` no dia do hotel, intervalo `[checkIn, checkOut)` — o dia da saída não conta como ocupado. Valores em reais (BRL).\n\n**Preço e disponibilidade** são os mesmos do balcão e do site de reservas: tabela por número de hóspedes, tabela própria da unidade, temporadas e dias da semana, manutenção programada. A trava do banco impede reserva dupla mesmo com vários canais escrevendo ao mesmo tempo (`409`).\n\n**Listas** vêm como `{ data, nextCursor }`, da mudança mais recente para a mais antiga. **Erros** vêm como `{ error: { code, message, field? }, requestId }`.\n\n**Webhooks:** cada chave pode ter uma URL HTTPS (mesma tela). Eventos `reservation.created`, `reservation.updated`, `reservation.cancelled`, `block.created`, `block.removed`, assinados com `x-hotelgestao-signature: sha256=<HMAC do corpo>` e reenviados com espera crescente até 10 vezes.\n\n**Limite:** 120 chamadas por minuto por chave. Disponível nos planos Avançado e Rede (e no teste grátis).","contact":{"name":"VisionX — HotelGestão","email":"visionxma@gmail.com","url":"https://app.hotelgestao.com.br/desenvolvedores"}},"servers":[{"url":"https://app.hotelgestao.com.br/api/v1","description":"Produção"}],"security":[{"chave":[]}],"tags":[{"name":"Hotel","description":"Dados do estabelecimento e das unidades (quartos, suítes, chalés, camas…)."},{"name":"Disponibilidade e preço","description":"O que dá para vender e por quanto, com as regras do hotel aplicadas."},{"name":"Reservas"},{"name":"Hóspedes"},{"name":"Bloqueios","description":"Fechar datas de uma unidade (stop-sell, manutenção combinada, uso próprio)."},{"name":"Motel","description":"Suítes por período (2h, 3h, pernoite) para totem de autoatendimento, tablet da recepção e integrações. Só para hotel do tipo Motel, com a tabela preenchida em Configurações do Sistema → Motel."}],"paths":{"/hotel":{"get":{"tags":["Hotel"],"summary":"Dados do hotel","operationId":"lerHotel","responses":{"200":{"description":"Hotel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hotel"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/room-types":{"get":{"tags":["Hotel"],"summary":"Tipos de unidade","description":"Cada tipo com quantas unidades tem, a capacidade máxima e a diária-base por número de hóspedes (sem temporada).","operationId":"listarTipos","responses":{"200":{"description":"Tipos","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TipoDeUnidade"}},"nextCursor":{"type":["string","null"],"description":"Envie em `cursor` para a próxima página; `null` = acabou."}}}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/rooms":{"get":{"tags":["Hotel"],"summary":"Unidades","operationId":"listarUnidades","parameters":[{"name":"type","in":"query","description":"Filtra por tipo.","schema":{"type":"string"}}],"responses":{"200":{"description":"Unidades","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Unidade"}},"nextCursor":{"type":["string","null"],"description":"Envie em `cursor` para a próxima página; `null` = acabou."}}}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/rooms/{id}":{"get":{"tags":["Hotel"],"summary":"Uma unidade","operationId":"lerUnidade","parameters":[{"name":"id","in":"path","required":true,"description":"Id da unidade.","schema":{"type":"string"}}],"responses":{"200":{"description":"Unidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Unidade"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/availability":{"get":{"tags":["Disponibilidade e preço"],"summary":"Disponibilidade e preço de uma estadia","description":"Por tipo: quantas unidades estão livres no período inteiro e o total da estadia para o número de hóspedes (a mais barata livre do tipo).","operationId":"consultarDisponibilidade","parameters":[{"name":"checkIn","in":"query","required":true,"description":"Entrada.","schema":{"type":"string","format":"date","examples":["2026-10-10"]}},{"name":"checkOut","in":"query","required":true,"description":"Saída.","schema":{"type":"string","format":"date","examples":["2026-10-10"]}},{"name":"guests","in":"query","description":"Número de hóspedes (padrão 2).","schema":{"type":"integer","minimum":1,"maximum":30,"default":2}}],"responses":{"200":{"description":"Disponibilidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Disponibilidade"}}}},"400":{"description":"Datas inválidas.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/calendar":{"get":{"tags":["Disponibilidade e preço"],"summary":"Calendário por unidade","description":"Dia a dia, se cada unidade está livre, e o que a ocupa. Janela padrão 30 dias; máxima 366.","operationId":"calendario","parameters":[{"name":"from","in":"query","required":false,"description":"Primeiro dia (padrão: hoje).","schema":{"type":"string","format":"date","examples":["2026-10-10"]}},{"name":"to","in":"query","required":false,"description":"Dia seguinte ao último.","schema":{"type":"string","format":"date","examples":["2026-10-10"]}}],"responses":{"200":{"description":"Calendário","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Calendario"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/rates":{"get":{"tags":["Disponibilidade e preço"],"summary":"Diárias por noite","description":"Diária de cada noite por tipo, para o número de hóspedes, com temporada e dia da semana aplicados.","operationId":"diarias","parameters":[{"name":"from","in":"query","required":false,"description":"Primeira noite (padrão: hoje).","schema":{"type":"string","format":"date","examples":["2026-10-10"]}},{"name":"to","in":"query","required":false,"description":"Dia seguinte à última noite.","schema":{"type":"string","format":"date","examples":["2026-10-10"]}},{"name":"guests","in":"query","description":"Número de hóspedes (padrão 2).","schema":{"type":"integer","minimum":1,"maximum":30,"default":2}}],"responses":{"200":{"description":"Diárias","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Diarias"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/reservations":{"get":{"tags":["Reservas"],"summary":"Listar reservas","operationId":"listarReservas","description":"Para sincronizar: guarde o `updatedAt` mais recente e volte com `updatedSince`.","parameters":[{"name":"status","in":"query","description":"Um ou vários, separados por vírgula.","schema":{"type":"string","examples":["confirmed,checked_in"]}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"checkInFrom","in":"query","required":false,"description":"Entrada a partir de.","schema":{"type":"string","format":"date","examples":["2026-10-10"]}},{"name":"checkInTo","in":"query","required":false,"description":"Entrada até (inclusive).","schema":{"type":"string","format":"date","examples":["2026-10-10"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","description":"O `nextCursor` da página anterior.","schema":{"type":"string"}}],"responses":{"200":{"description":"Reservas","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Reserva"}},"nextCursor":{"type":["string","null"],"description":"Envie em `cursor` para a próxima página; `null` = acabou."}}}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}},"post":{"tags":["Reservas"],"summary":"Criar reserva","operationId":"criarReserva","description":"Com `roomType`, a API escolhe a unidade livre mais barata do tipo que caiba os hóspedes; com `roomId`, usa exatamente aquela. Sem `total`, o preço é o da tabela do hotel. **Idempotente:** repetir com o mesmo cabeçalho `Idempotency-Key` (ou o mesmo `externalId`) devolve a mesma reserva com `duplicate: true` em vez de criar outra. O hóspede é reaproveitado pelo documento, ou pelo telefone + nome.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","minLength":8,"maxLength":120}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NovaReserva"}}}},"responses":{"200":{"description":"Repetição: a mesma reserva, com duplicate: true","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reserva"}}}},"201":{"description":"Criada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reserva"}}}},"400":{"description":"Campo inválido (veja `field`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Chave somente leitura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"roomId/roomType não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Sem unidade livre no período.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/reservations/{id}":{"get":{"tags":["Reservas"],"summary":"Uma reserva","operationId":"lerReserva","parameters":[{"name":"id","in":"path","required":true,"description":"Id da reserva.","schema":{"type":"string"}}],"responses":{"200":{"description":"Reserva","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reserva"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}},"patch":{"tags":["Reservas"],"summary":"Alterar reserva","operationId":"alterarReserva","description":"Muda observações, número de hóspedes e contato do hóspede. Datas, unidade e valores mudam no balcão, onde a troca fica registrada no histórico da reserva; pela API, cancele e crie outra.","parameters":[{"name":"id","in":"path","required":true,"description":"Id da reserva.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlteracaoReserva"}}}},"responses":{"200":{"description":"Alterada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reserva"}}}},"400":{"description":"Campo não permitido ou inválido.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Chave somente leitura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Reserva cancelada ou encerrada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/reservations/{id}/cancel":{"post":{"tags":["Reservas"],"summary":"Cancelar reserva","operationId":"cancelarReserva","description":"Idempotente. Reserva com check-in feito é cancelada no balcão (409).","parameters":[{"name":"id","in":"path","required":true,"description":"Id da reserva.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":300}}}}}},"responses":{"200":{"description":"Cancelada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reserva"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Chave somente leitura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Check-in já feito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/guests":{"get":{"tags":["Hóspedes"],"summary":"Listar/buscar hóspedes","operationId":"listarHospedes","parameters":[{"name":"q","in":"query","description":"Nome, telefone, e-mail ou documento (mín. 2 caracteres).","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","description":"O `nextCursor` da página anterior.","schema":{"type":"string"}}],"responses":{"200":{"description":"Hóspedes","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Hospede"}},"nextCursor":{"type":["string","null"],"description":"Envie em `cursor` para a próxima página; `null` = acabou."}}}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}},"post":{"tags":["Hóspedes"],"summary":"Cadastrar hóspede","operationId":"criarHospede","description":"Se já existir (mesmo documento, ou mesmo telefone + nome), devolve o cadastro com `duplicate: true`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HospedeEntrada"}}}},"responses":{"200":{"description":"Já existia","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hospede"}}}},"201":{"description":"Criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hospede"}}}},"400":{"description":"Campo inválido.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Chave somente leitura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/guests/{id}":{"get":{"tags":["Hóspedes"],"summary":"Um hóspede","operationId":"lerHospede","parameters":[{"name":"id","in":"path","required":true,"description":"Id do hóspede.","schema":{"type":"string"}}],"responses":{"200":{"description":"Hóspede","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hospede"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/blocks/{uid}":{"put":{"tags":["Bloqueios"],"summary":"Fechar datas de uma unidade","operationId":"bloquear","description":"Idempotente pelo `uid` que VOCÊ escolhe (ex.: `stopsell-natal-101`): enviar de novo com outras datas move o bloqueio.","parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9._:-]{1,120}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NovoBloqueio"}}}},"responses":{"200":{"description":"Bloqueado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Bloqueio"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Chave somente leitura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"roomId não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Já há reserva no período.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}},"delete":{"tags":["Bloqueios"],"summary":"Reabrir datas","operationId":"desbloquear","parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Removido","content":{"application/json":{"schema":{"type":"object","properties":{"uid":{"type":"string"},"removed":{"type":"boolean"}}}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/suites":{"get":{"tags":["Motel"],"summary":"Suítes agora, com preço de cada período","operationId":"listarSuites","description":"Estado de cada suíte (`livre`, `ocupada`, `excedida`, `limpeza`, `manutencao`, `reservada`), quanto falta do período em curso e o preço de cada período para aquele tipo de suíte no momento (fim de semana e data especial já aplicados). É o que o totem mostra na tela.","responses":{"200":{"description":"Suítes","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Suite"}},"nextCursor":{"type":["string","null"],"description":"Envie em `cursor` para a próxima página; `null` = acabou."}}}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/suites/{id}/stays":{"post":{"tags":["Motel"],"summary":"Abrir entrada numa suíte","operationId":"abrirPermanencia","description":"Abre a permanência por período. Sem cadastro do hóspede: a placa é opcional. Uma suíte só pode ter uma entrada aberta (o banco recusa a segunda).","parameters":[{"name":"id","in":"path","required":true,"description":"Id da suíte (roomId).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NovaPermanencia"}}}},"responses":{"201":{"description":"Entrada aberta","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Permanencia"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Chave somente leitura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Suíte não encontrada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Suíte ocupada, em limpeza ou em manutenção.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/stays":{"get":{"tags":["Motel"],"summary":"Permanências","operationId":"listarPermanencias","parameters":[{"name":"status","in":"query","description":"aberta (padrão), agendada, fechada ou cancelada.","schema":{"type":"string","default":"aberta"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Permanências","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Permanencia"}},"nextCursor":{"type":["string","null"],"description":"Envie em `cursor` para a próxima página; `null` = acabou."}}}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/stays/{id}":{"get":{"tags":["Motel"],"summary":"Uma permanência, com a conta do momento","operationId":"lerPermanencia","parameters":[{"name":"id","in":"path","required":true,"description":"Id da permanência.","schema":{"type":"string"}}],"responses":{"200":{"description":"Permanência","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Permanencia"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Não existe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}},"/stays/{id}/close":{"post":{"tags":["Motel"],"summary":"Fechar a conta da suíte","operationId":"fecharPermanencia","description":"Calcula período, hora adicional (com tolerância), consumo e desconto, exige que os pagamentos somem o total a pagar, lança no caixa aberto do hotel e devolve a suíte para limpeza.","parameters":[{"name":"id","in":"path","required":true,"description":"Id da permanência.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FechamentoPermanencia"}}}},"responses":{"200":{"description":"Conta fechada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Permanencia"}}}},"401":{"description":"Chave ausente, inválida ou revogada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"402":{"description":"O plano do hotel não inclui a API ou está vencido/bloqueado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"403":{"description":"Chave somente leitura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"404":{"description":"Permanência aberta não encontrada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"409":{"description":"Sem caixa aberto no hotel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"423":{"description":"Hotel suspenso pela VisionX.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"429":{"description":"Mais de 120 chamadas por minuto nesta chave (veja o cabeçalho `retry-after`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}},"500":{"description":"Erro interno — informe o `requestId` ao suporte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erro"}}}}}}}},"components":{"securitySchemes":{"chave":{"type":"http","scheme":"bearer","bearerFormat":"hg_…","description":"Chave do hotel. Também aceita o cabeçalho `x-api-key`."}},"schemas":{"Suite":{"type":"object","properties":{"roomId":{"type":"string"},"number":{"type":"string"},"type":{"type":"string"},"state":{"type":"string","enum":["livre","ocupada","excedida","limpeza","manutencao","reservada"]},"minutesLeft":{"type":["integer","null"],"description":"Minutos que faltam do período (negativo = passou)."},"stayId":{"type":["string","null"]},"periods":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hours":{"type":"number"},"price":{"type":["number","null"]},"available":{"type":"boolean"}}}},"stay":{"$ref":"#/components/schemas/Permanencia"}}},"NovaPermanencia":{"type":"object","required":["periodId"],"properties":{"periodId":{"type":"string","description":"Id do período (ex.: `2h`, `pernoite`), como vem em /suites.","examples":["2h"]},"plate":{"type":"string","description":"Placa do carro (opcional).","examples":["ABC1D23"]},"note":{"type":"string"}}},"FechamentoPermanencia":{"type":"object","required":["payments"],"properties":{"payments":{"type":"array","items":{"type":"object","required":["method","amount"],"properties":{"method":{"type":"string","examples":["Dinheiro","Pix","Cartão de Crédito"]},"amount":{"type":"number"}}}},"discount":{"type":"number","description":"Desconto em reais sobre o total."}}},"Permanencia":{"type":"object","properties":{"id":{"type":"string"},"roomId":{"type":"string"},"number":{"type":["string","null"]},"type":{"type":["string","null"]},"status":{"type":"string","enum":["aberta","agendada","fechada","cancelada"]},"periodId":{"type":"string"},"periodName":{"type":"string"},"hours":{"type":"number"},"checkIn":{"type":"string","format":"date-time"},"expectedCheckOut":{"type":"string","format":"date-time"},"checkOut":{"type":["string","null"],"format":"date-time"},"periodPrice":{"type":"number"},"extraHourPrice":{"type":"number"},"toleranceMinutes":{"type":"integer"},"fractionMinutes":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"}}}},"plate":{"type":["string","null"]},"note":{"type":["string","null"]},"deposit":{"type":"number"},"total":{"type":"number"},"live":{"type":"object","description":"Só na permanência aberta: a conta agora.","properties":{"minutesUsed":{"type":"integer"},"minutesOver":{"type":"integer"},"extraFractions":{"type":"integer"},"extraAmount":{"type":"number"},"itemsAmount":{"type":"number"},"dueNow":{"type":"number"}}}}},"Erro":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","rate_limited","plan_required","hotel_suspended","internal_error"]},"message":{"type":"string","description":"Em português, pronta para mostrar."},"field":{"type":"string","description":"Campo que causou o erro, quando há um."}}},"requestId":{"type":"string"}}},"Hotel":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"segment":{"type":"string","enum":["hotel","pousada","hostel","motel","chales","temporada","camping"]},"address":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"timezone":{"type":"string","examples":["America/Fortaleza"]},"currency":{"type":"string","const":"BRL"},"checkInTime":{"type":"string","examples":["14:00"]},"checkOutTime":{"type":"string","examples":["12:00"]}}},"TipoDeUnidade":{"type":"object","properties":{"name":{"type":"string"},"units":{"type":"integer"},"maxGuests":{"type":"integer"},"baseNightlyByGuests":{"type":"object","additionalProperties":{"type":"number"},"examples":[{"1":90,"2":170}]}}},"Unidade":{"type":"object","properties":{"id":{"type":"string"},"number":{"type":"string"},"type":{"type":"string"},"capacity":{"type":["integer","null"]},"status":{"type":"string","examples":["available","occupied","cleaning","maintenance"]},"description":{"type":"string"},"maintenance":{"type":["object","null"],"properties":{"from":{"type":["string","null"],"format":"date"},"to":{"type":["string","null"],"format":"date"}}},"updatedAt":{"type":["string","null"],"format":"date-time"}}},"Disponibilidade":{"type":"object","properties":{"checkIn":{"type":"string","format":"date","examples":["2026-10-10"]},"checkOut":{"type":"string","format":"date","examples":["2026-10-10"]},"nights":{"type":"integer"},"guests":{"type":"integer"},"data":{"type":"array","items":{"type":"object","properties":{"roomType":{"type":"string"},"available":{"type":"integer"},"maxGuests":{"type":"integer"},"fits":{"type":"boolean","description":"Cabe esse número de hóspedes numa unidade do tipo."},"price":{"type":["object","null"],"properties":{"guests":{"type":"integer"},"nightly":{"type":"number","description":"Diária-base (sem temporada)."},"total":{"type":"number","description":"Total da estadia com temporada aplicada e as taxas obrigatórias da estadia (fees) somadas."},"seasonalAdjusted":{"type":"boolean"},"currency":{"type":"string"},"fees":{"type":"array","description":"Taxas obrigatórias da estadia já somadas no total (ex.: taxa de limpeza). Vazio quando o hotel não cobra.","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"amount":{"type":"number"}}}}}}}}}}},"Calendario":{"type":"object","properties":{"from":{"type":"string","format":"date","examples":["2026-10-10"]},"to":{"type":"string","format":"date","examples":["2026-10-10"]},"data":{"type":"array","items":{"type":"object","properties":{"roomId":{"type":"string"},"number":{"type":"string"},"type":{"type":"string"},"free":{"type":"object","additionalProperties":{"type":"boolean"}},"occupied":{"type":"array","items":{"type":"object","properties":{"reservationId":{"type":["string","null"]},"status":{"type":"string"},"start":{"type":"string","format":"date","examples":["2026-10-10"]},"end":{"type":"string","format":"date","examples":["2026-10-10"]}}}}}}}}},"Diarias":{"type":"object","properties":{"from":{"type":"string","format":"date","examples":["2026-10-10"]},"to":{"type":"string","format":"date","examples":["2026-10-10"]},"data":{"type":"array","items":{"type":"object","properties":{"roomType":{"type":"string"},"guests":{"type":"integer"},"currency":{"type":"string"},"nightly":{"type":"object","additionalProperties":{"type":"number"}}}}}}},"Reserva":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string","examples":["#01205"]},"status":{"type":"string","enum":["pending","confirmed","checked_in","checked_out","cancelled","no_show"]},"roomId":{"type":"string"},"roomNumber":{"type":["string","null"]},"roomType":{"type":["string","null"]},"checkIn":{"type":"string","format":"date","examples":["2026-10-10"]},"checkOut":{"type":"string","format":"date","examples":["2026-10-10"]},"guests":{"type":["integer","null"]},"guest":{"type":"object","properties":{"id":{"type":["string","null"]},"name":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"total":{"type":"number"},"paid":{"type":"number"},"balance":{"type":"number"},"currency":{"type":"string"},"groupId":{"type":["string","null"],"description":"Reservas de vários quartos do mesmo pedido compartilham o grupo."},"notes":{"type":"string"},"source":{"type":"object","properties":{"kind":{"type":"string","examples":["hotel","site","api","channex","ical"]},"channel":{"type":["string","null"]},"externalId":{"type":["string","null"]}}},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"},"duplicate":{"type":"boolean","description":"Só nas repetições idempotentes."}}},"HospedeEntrada":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2,"maxLength":120},"phone":{"type":"string","description":"DDD + número, só dígitos (10 a 13)."},"email":{"type":"string","format":"email"},"document":{"type":"string","description":"CPF, passaporte ou outro documento."}}},"NovaReserva":{"type":"object","required":["checkIn","checkOut","guest"],"properties":{"roomType":{"type":"string","description":"Tipo (veja /room-types). Obrigatório se não houver roomId."},"roomId":{"type":"string","description":"Unidade exata."},"checkIn":{"type":"string","format":"date","examples":["2026-10-10"]},"checkOut":{"type":"string","format":"date","examples":["2026-10-10"]},"guests":{"type":"integer","minimum":1,"maximum":30,"default":1},"guest":{"$ref":"#/components/schemas/HospedeEntrada"},"total":{"type":"number","description":"Valor acertado no canal. Sem ele, vale a tabela do hotel."},"paid":{"type":"number","default":0,"description":"Quanto já foi pago no canal."},"status":{"type":"string","enum":["confirmed","pending"],"default":"confirmed"},"channel":{"type":"string","description":"Nome do canal para o relatório (ex.: \"Site próprio\", \"Chatbot\").","default":"API"},"externalId":{"type":"string","description":"Id da reserva no seu sistema (também torna a criação idempotente)."},"notes":{"type":"string","maxLength":500}}},"AlteracaoReserva":{"type":"object","properties":{"notes":{"type":"string"},"guests":{"type":"integer","minimum":1,"maximum":30},"guest":{"type":"object","properties":{"phone":{"type":"string"},"email":{"type":"string"}}}}},"Hospede":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"document":{"type":["string","null"]},"notes":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]},"duplicate":{"type":"boolean"}}},"NovoBloqueio":{"type":"object","required":["roomId","start","end"],"properties":{"roomId":{"type":"string"},"start":{"type":"string","format":"date","examples":["2026-10-10"]},"end":{"type":"string","format":"date","examples":["2026-10-10"],"description":"Dia seguinte à última noite fechada."},"reason":{"type":"string"}}},"Bloqueio":{"type":"object","properties":{"uid":{"type":"string"},"roomId":{"type":"string"},"start":{"type":"string","format":"date","examples":["2026-10-10"]},"end":{"type":"string","format":"date","examples":["2026-10-10"]},"reason":{"type":"string"}}}}}}