Usar a API REST pública da Nowistay

Atualizado em

A API REST pública da Nowistay liga os seus scripts e as integrações de parceiros à sua conta. Leia e atualize as definições dos alojamentos, os calendários, as reservas e as missões; gira fichas de hóspedes, conversas, conhecimento privado e guias de boas-vindas; peça pagamentos de reservas e reembolsos de cancelamentos; e consulte extras, compras e relatórios do portefólio. Explore os esquemas exatos de pedido e de resposta em /public/docs e /public/openapi.json.

Este guia apresenta três caminhos: a forma mais rápida de experimentar a API (o ambiente de testes da documentação interativa), a forma mais simples de executar os seus próprios scripts (uma credencial de API pessoal criada na aplicação) e o fluxo OAuth padrão que vai usar quando criar uma aplicação para outros anfitriões.

O que pode fazer com a API

  • Alojamentos e calendários: pesquisar e ler alojamentos, atualizar as definições de funcionamento e gerir diariamente a disponibilidade, as tarifas e as restrições de estadia.
  • Reservas e pagamentos: criar reservas diretas, atualizar reservas elegíveis, pedir o pagamento durante a criação, instruir reembolsos de cancelamentos e ler o estado seguro dos pedidos de pagamento.
  • Hóspedes: ler a sua base de clientes, criar fichas de hóspedes e obter o histórico de estadias.
  • Missões: criar, atualizar e atribuir missões, filtrar cargas de trabalho e ler os detalhes das missões e os relatórios de conclusão.
  • Conversas: encontrar conversas com hóspedes, ler as respetivas mensagens e enviar uma resposta do anfitrião pelo canal de envio selecionado.
  • Conhecimento privado: ler, adicionar e atualizar perguntas e respostas dos alojamentos, ou fundi-las noutros alojamentos.
  • Guias de boas-vindas: editar introduções localizadas e páginas estruturadas, alterar a posição das páginas e carregar imagens.
  • Extras e relatórios: ler o catálogo de extras e as compras das reservas, e exportar listas de reservas ou de missões em formato de tabela.
  • Ferramentas existentes: os parâmetros de reserva personalizados, as leituras de membros da equipa, os feeds de atividade dos alojamentos e os webhooks de reservas continuam disponíveis.

Antes de começar

O acesso é verificado em função da propriedade e do direito de assistente do alojamento. É necessária uma ligação PMS ativa para as operações que dependem dela, incluindo a gestão do calendário e a criação de reservas diretas. Os outros recursos não exigem uma ligação PMS apenas para serem lidos ou editados.

  • Precisa de uma subscrição ativa do AI Channel Manager nos alojamentos que quer expor. A API só devolve os alojamentos em que esse direito está ativo.
  • Inicia sessão como anfitrião ou gestor de alojamentos. A API nunca expõe alojamentos que não lhe pertençam.
  • O URL base é https://api.nowistay.com
  • Todos os endpoints em /public/v1/* exigem um token de acesso OAuth2, enviado como Authorization: Bearer ....

A forma mais rápida: experimentar no ambiente de testes da documentação

Abra https://api.nowistay.com/public/docs no navegador. A página é uma interface Swagger UI completa da API, com um ambiente de testes OAuth integrado que regista automaticamente um cliente por si. Não é preciso programar para testar chamadas.

  1. Atualize a página sem usar a cache (Cmd+Shift+R no Mac, Ctrl+F5 no Windows).
  2. Aguarde que a pequena faixa no topo indique OAuth playground ready.
  3. Clique no botão verde Authorize (em cima à direita).
  4. Na caixa de diálogo, na secção OAuth2, clique em Authorize.
  5. É redirecionado para a página de início de sessão e de consentimento da Nowistay.
  6. Inicie sessão como anfitrião ou gestor de alojamentos com a subscrição do AI Channel Manager.
  7. Reveja os âmbitos pedidos pelo ambiente de testes e aprove-os.
  8. Volta a /public/docs, já autenticado.
  9. Abra GET /public/v1/properties, clique em Try it out e depois em Execute.
  10. Deve ver os seus alojamentos na resposta.

A partir daqui, pode experimentar cada endpoint com um clique, ver o JSON exato que a Nowistay devolve e copiar o comando cURL de qualquer chamada. É a forma recomendada de explorar a API antes de escrever código.

Importante. O cliente do ambiente de testes só existe no seu navegador. Serve para testar, mas numa integração real deve criar uma credencial de API pessoal ou registar o seu próprio cliente OAuth (ambos explicados abaixo).

Os seus próprios scripts: criar uma credencial de API pessoal

Se está a automatizar a sua própria conta (um script de relatórios, uma sincronização com a sua ferramenta de contabilidade, um pequeno painel), não precisa de todo o fluxo OAuth. Crie uma credencial de API pessoal na aplicação e troque-a por um token numa única chamada. Sem ecrã de consentimento e sem tokens de atualização para gerir.

  1. Na aplicação, abra o menu e aceda a A minha conta > Programador, ou abra diretamente app.nowistay.com/hub/user/developer.
  2. Clique em Nova credencial.
  3. Dê-lhe um nome claro (por exemplo Reporting script) e marque apenas as permissões de que precisa.
  4. Clique em Criar credencial. A chave secreta é mostrada uma única vez: copie-a agora e guarde-a num local seguro. Não a poderá ver novamente.

O seu script troca então a credencial por um token de acesso (válido durante uma hora) e chama a API:

curl -X POST https://api.nowistay.com/public/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=client_credentials" \
  --data-urlencode "client_id=YOUR_CLIENT_ID" \
  --data-urlencode "client_secret=YOUR_CLIENT_SECRET"

Quando o token expirar, peça um novo da mesma forma. Neste fluxo não há token de atualização, e é essa a ideia: duas linhas de código, nada para vigiar.

Gerir as suas credenciais

  • Última utilização mostra quando cada credencial chamou a API pela última vez. É a forma mais fácil de detetar um script antigo que ainda funciona, ou uma credencial que pode remover com segurança.
  • Rodar o segredo gera uma nova chave secreta se a atual possa ter sido exposta, ou quando roda as chaves periodicamente. A nova chave é mostrada uma vez; a chave anterior continua a funcionar durante 7 dias para o seu script poder migrar e depois deixa de funcionar.
  • Eliminar remove uma credencial que já não usa. Tudo o que ainda a use deixa de funcionar de imediato.

Pode criar até 10 credenciais, cada uma com o seu nome e as suas permissões. Uma credencial só lê e escreve os dados a que a sua própria conta tem acesso e precisa da mesma subscrição ativa do AI Channel Manager que o resto da API.

Como adicionar âmbitos a um token de API existente

Não pode editar os âmbitos de um token ou de uma credencial pessoal existente. Crie uma credencial de substituição com o conjunto completo de permissões de que a sua integração precisa. Os clientes, os tokens de acesso, os códigos de autorização e os tokens de atualização existentes mantêm as concessões originais; nenhuma permissão é adicionada automaticamente.

Credenciais pessoais: substituir, testar e depois mudar

  1. Abra A minha conta > Programador, ou use https://app.nowistay.com/hub/user/developer. Anote as permissões usadas pela integração existente.
  2. Clique em Nova credencial. Dê à substituta um nome reconhecível e selecione as permissões existentes de que ainda precisa mais os novos âmbitos. Por exemplo, as atualizações de preços do calendário precisam de calendar.write; o envio de mensagens precisa de messages.write; pedir o pagamento de uma reserva precisa de bookings.write e payments.write.
  3. Clique em Criar credencial e copie com segurança o Client ID e o Client secret mostrados uma única vez.
  4. Peça um novo token de acesso a POST /public/oauth/token com grant_type=client_credentials e as credenciais de substituição. Verifique o valor scope devolvido e teste um endpoint permitido por esses âmbitos. GET /public/v1/properties exige especificamente properties.read.
  5. Atualize as credenciais da sua integração e o token de acesso em cache. Verifique que as operações existentes e a operação recém-ativada funcionam.
  6. Quando todos os consumidores tiverem mudado, use Eliminar na credencial anterior. Eliminá-la interrompe de imediato as integrações que ainda a usem.

Rodar o segredo não adiciona âmbitos. Apenas substitui o segredo da mesma credencial; o segredo anterior continua válido durante 7 dias. Atualizar ou pedir outro token de acesso não pode ampliar a concessão original. Os âmbitos de escrita não incluem automaticamente os de leitura.

Aplicações OAuth de parceiros: novo registo e novo consentimento

  1. Envie POST /public/oauth/register com o conjunto completo de âmbitos pretendido e os dados normais da sua aplicação. Um registo equivalente com exatamente o mesmo conjunto de âmbitos reutiliza o cliente correspondente; um conjunto de âmbitos alterado cria um novo registo. Guarde as credenciais de cliente devolvidas.
  2. Inicie um novo fluxo de código de autorização com PKCE para esse registo. Peça ao anfitrião que aprove os âmbitos pretendidos na página de consentimento e troque depois o novo código por tokens.
  3. Mude a integração para esses tokens depois de testar. Os tokens de atualização e os códigos de autorização existentes mantêm os âmbitos originais e não podem ser usados para adicionar permissões.

No ambiente de testes da documentação, atualize a página e autorize de novo com os âmbitos necessários. As novas permissões são listadas com etiquetas legíveis e os respetivos identificadores em inglês, francês, espanhol, alemão, neerlandês e italiano.

OAuth, em termos simples

A API usa o OAuth 2.1 padrão, com o fluxo de código de autorização e PKCE. Numa frase: o utilizador abre uma página da Nowistay, diz que sim, a aplicação recebe um código curto, troca-o por um token de acesso e chama a API com esse token. Os tokens expiram e podem ser atualizados sem voltar a incomodar o utilizador.

Os três endpoints OAuth que vai usar:

  • Registar a sua aplicação (uma só vez): /public/oauth/register (POST)
  • Enviar o utilizador para dar consentimento: /public/oauth/authorize (GET, redirecionamento do navegador)
  • Trocar o código por tokens: /public/oauth/token (POST)

Pode também obter os metadados OAuth em /.well-known/oauth-authorization-server/public-api, que lista todos os endpoints e as funcionalidades suportadas.

As novas aplicações começam como não verificadas

Qualquer pessoa pode registar um cliente OAuth, pelo que os anfitriões precisam de uma forma de distinguir uma aplicação recém-criada de uma integração consolidada. Por isso, todas as aplicações recém-registadas começam como não verificadas:

  • O ecrã de consentimento mostra aos anfitriões um aviso claro de que a aplicação não foi verificada pela Nowistay.
  • Uma aplicação não verificada pode ser ligada a um máximo de 3 contas de anfitrião.
  • Os clientes registados que nunca concluam uma única ligação são eliminados automaticamente após 30 dias.

Está a criar algo para mais de 3 contas? Escreva ao suporte com o nome da sua aplicação, o site e o caso de utilização. Depois de a sua aplicação ser verificada, o aviso desaparece e o limite de contas é levantado.

Âmbitos disponíveis

A API REST suporta 25 âmbitos, incluindo dez permissões adicionais para edições de alojamentos, mensagens, guias, conhecimento, criação de hóspedes, extras e pagamentos. Selecione apenas as permissões de que a sua integração precisa.

  • properties.read: ler os detalhes e as definições de funcionamento dos alojamentos.
  • properties.write: atualizar os detalhes e as definições de funcionamento dos alojamentos.
  • calendar.read: ler a disponibilidade, as tarifas por noite e as restrições de estadia.
  • calendar.write: atualizar a disponibilidade, as tarifas por noite e as restrições de estadia.
  • bookings.read: ler reservas, detalhes financeiros e o estado seguro dos pedidos de pagamento.
  • bookings.sensitive.read: incluir nas respostas das reservas os contactos dos hóspedes, as moradas postais e os códigos de acesso; exige também bookings.read para leituras.
  • bookings.write: criar e atualizar reservas diretas. Os pedidos de pagamento e os reembolsos exigem também payments.write.
  • booking_parameters.read: ler as definições e os valores dos parâmetros de reserva personalizados.
  • booking_parameters.write: criar e atualizar definições e valores de parâmetros.
  • missions.read: ler missões e relatórios de conclusão.
  • missions.write: criar, atualizar e atribuir missões.
  • activity.read: ler os registos de atividade dos alojamentos.
  • team_members.read: ler membros da equipa, contactos e atribuições a alojamentos.
  • webhooks.read: ler as subscrições de webhooks.
  • webhooks.write: criar, atualizar, pausar e eliminar subscrições de webhooks.
  • customers.read: ler fichas de hóspedes, contactos e histórico de estadias.
  • customers.write: criar fichas de hóspedes.
  • upsells.read: ler o catálogo de extras e as compras das reservas.
  • payments.write: pedir o pagamento durante a criação da reserva e instruir reembolsos totais ou parciais de cancelamentos; exige também bookings.write.
  • messages.read: ler conversas e mensagens dos hóspedes.
  • messages.write: enviar mensagens aos hóspedes.
  • guides.read: ler guias de boas-vindas e o conteúdo das páginas.
  • guides.write: editar guias, criar e atualizar páginas, alterar a posição das páginas e carregar imagens.
  • knowledge.read: ler as perguntas e respostas privadas dos alojamentos.
  • knowledge.write: criar e atualizar conhecimento privado. A cópia exige também knowledge.read.

Os oito âmbitos REST predefinidos continuam a ser properties.read, calendar.read, bookings.read, booking_parameters.read, missions.read, activity.read, team_members.read e webhooks.read. Os predefinidos não atualizam os tokens existentes.

Operações que exigem dois âmbitos

  • Pedidos de pagamento e reembolsos explícitos totais/parciais de cancelamentos: bookings.write + payments.write. O cancelamento sem reembolso usa apenas bookings.write.
  • Histórico de reservas de um hóspede: customers.read + bookings.read.
  • Compras de extras de uma reserva: upsells.read + bookings.read. A leitura do catálogo só precisa de upsells.read.
  • Cópia de conhecimento: knowledge.read + knowledge.write.
  • Um PATCH de reserva que combine campos principais e valores de parâmetros personalizados: bookings.write + booking_parameters.write. Um PATCH só com parâmetros mantém booking_parameters.write e funciona também em reservas OTA.

Os novos endpoints de escrita devolvem resultados de ação mínimos, a menos que o token tenha também o âmbito de leitura correspondente. A ocultação de dados nas reservas existentes mantém-se. Os endpoints de missões e de conversas incluem o contexto da reserva associada sob os seus próprios âmbitos.

Passo a passo: criar a sua própria integração

Estes exemplos usam IDs e credenciais fictícios. Substitua-os pelos seus valores. Este fluxo destina-se a aplicações de parceiros; as credenciais pessoais usam client_credentials, como mostrado acima.

Passo 1. Registar o seu cliente OAuth

Chame POST /public/oauth/register com as permissões de que precisa. Guarde com segurança o client_id e o client_secret devolvidos. O exemplo pede leituras de alojamentos, reservas e missões.

curl -X POST https://api.nowistay.com/public/oauth/register \
  -H "Content-Type: application/json" \
  -d '{"clientName":"My integration","redirectUris":["https://my-app.example.com/oauth/callback"],"grantTypes":["authorization_code","refresh_token"],"responseTypes":["code"],"tokenEndpointAuthMethod":"client_secret_post","scope":"properties.read bookings.read missions.read"}'

Para um cliente público sem backend, use "tokenEndpointAuthMethod": "none" e PKCE, sem client secret.

Passo 2. Enviar o utilizador para o URL de autorização

Gere um verificador PKCE, o respetivo desafio S256 e um state aleatório. Redirecione o utilizador para o endpoint de autorização. O URL seguinte está numa só linha; codifique os valores da query como URL.

https://api.nowistay.com/public/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fmy-app.example.com%2Foauth%2Fcallback&scope=properties.read%20bookings.read%20missions.read&state=RANDOM_STATE&code_challenge=BASE64URL_S256_HASH&code_challenge_method=S256

O anfitrião inicia sessão, revê as permissões e aprova ou nega o acesso. Se aprovar, o callback contém um code de utilização única e o seu state. Rejeite um callback cujo state não coincida.

https://my-app.example.com/oauth/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE

Passo 3. Trocar o código por tokens

curl -X POST https://api.nowistay.com/public/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=authorization_code" \
  --data-urlencode "code=AUTHORIZATION_CODE" \
  --data-urlencode "redirect_uri=https://my-app.example.com/oauth/callback" \
  --data-urlencode "client_id=YOUR_CLIENT_ID" \
  --data-urlencode "client_secret=YOUR_CLIENT_SECRET" \
  --data-urlencode "code_verifier=ORIGINAL_PKCE_VERIFIER"

A resposta inclui access_token, token_type, expires_in, refresh_token e scope. Guarde os tokens com segurança. Os tokens de acesso duram normalmente uma hora; use o prazo devolvido.

Passo 4. Chamar a API

Este exemplo exige properties.read. Leia os campos data e pagination da resposta.

curl "https://api.nowistay.com/public/v1/properties" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Passo 5. Atualizar o token quando expirar

curl -X POST https://api.nowistay.com/public/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=refresh_token" \
  --data-urlencode "refresh_token=YOUR_REFRESH_TOKEN" \
  --data-urlencode "client_id=YOUR_CLIENT_ID" \
  --data-urlencode "client_secret=YOUR_CLIENT_SECRET"

Guarde o novo token de atualização devolvido pela resposta de atualização. Se a atualização falhar, reinicie a autorização. A atualização mantém os âmbitos concedidos anteriormente. As credenciais pessoais não têm token de atualização: peça um novo token de acesso com client_credentials.

Exemplos de endpoints

Ler disponibilidade, tarifas e restrições de estadia

GET /public/v1/properties/{property_id}/calendar exige calendar.read. Indique as datas from e to (inclusivas); um pedido pode abranger até 730 dias.

GET /public/v1/properties/101/calendar?from=2026-12-18&to=2026-12-20

Cada dia pode devolver availability, rate, minStay, maxStay, stopSell, closedToArrival, closedToDeparture, restricted e restrictionReasons. availability é o inventário vendável restante depois das reservas confirmadas. Os campos de restrição explicam por que razão uma data, ou uma ação de check-in/check-out, está restringida.

Atualizar o calendário de um alojamento

PATCH /public/v1/properties/{property_id}/calendar exige calendar.write. O pedido é parcial: envie apenas os controlos que devem mudar e os campos omitidos permanecem inalterados.

{
  "from": "2026-12-18",
  "to": "2026-12-31",
  "availability": 1,
  "rate": 145.0,
  "minStay": 2,
  "maxStay": 14,
  "stopSell": false,
  "closedToArrival": false,
  "closedToDeparture": false,
  "daysOfWeek": [0, 1, 2, 3, 4]
}

daysOfWeek é opcional: 0 é segunda-feira e 6 é domingo. Omita-o para atualizar todas as datas do intervalo. A resposta indica daysUpdated e a atualização normalizada que foi aplicada. As alterações são sincronizadas através do Nowistay PMS.

As operações de calendário exigem propriedade, o direito de assistente e a gestão de calendário ativa da Nowistay. Para ativar os âmbitos de calendário numa integração existente, siga Como adicionar âmbitos a um token de API existente acima; atualizar um token ou rodar o respetivo segredo não é suficiente.

Listar as reservas de um alojamento num intervalo de datas

Os filtros suportados incluem propertyId, propertyIds repetido, status, channel, fromDate e toDate. A paginação JSON padrão usa limit (máximo 100) e offset. Os filtros de data das reservas mantêm a semântica de sobreposição: departure >= fromDate e arrival <= toDate.

curl "https://api.nowistay.com/public/v1/bookings?propertyId=101&fromDate=2026-12-01&toDate=2026-12-31&status=confirmed" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Obter o detalhe de uma reserva com os contactos do hóspede

curl "https://api.nowistay.com/public/v1/bookings/9001" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Exige o âmbito adicional bookings.sensitive.read. Sem ele, email, phone e o código da fechadura inteligente são omitidos.

Atualizar uma reserva direta

As edições principais de uma reserva exigem bookings.write e uma reserva direta elegível. As reservas OTA permanecem só de leitura nos campos principais. Um PATCH que contenha apenas customParameters suporta também reservas OTA e usa booking_parameters.write.

curl -X PATCH "https://api.nowistay.com/public/v1/bookings/9001" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "notes": "Guest requested a baby cot.",
  "reservationNumber": "DIRECT-9001",
  "silent": true
}'

Os pedidos PATCH de reservas existentes usam por predefinição silent=true. Defina silent=false para desencadear as notificações de atualização habituais. A criação de reservas usa por predefinição silent=false. Os campos omitidos permanecem inalterados e os valores null já suportados continuam a limpar campos. A sincronização da disponibilidade continua a fazer parte da operação partilhada.

Adicionar um campo personalizado às suas reservas

Os parâmetros de reserva personalizados são úteis quando quer espelhar em cada reserva da Nowistay dados do seu próprio sistema.

curl -X POST "https://api.nowistay.com/public/v1/booking-parameters" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "key": "external_status",
  "name": "External status"
}'

curl -X PATCH "https://api.nowistay.com/public/v1/bookings/9001" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "customParameters": {
    "external_status": "ready"
  }
}'

Ambos os exemplos usam booking_parameters.write. As atualizações mistas de campos principais e de parâmetros exigem os dois âmbitos de escrita de reservas; uma falha de validação deixa ambos inalterados.

Envie null como valor para limpar um campo personalizado numa reserva.

Criar uma missão de limpeza e atribuí-la a um membro da equipa

Exige missions.write. Os fluxos de atribuição e de notificação também são executados nas missões criadas pela API.

curl -X POST "https://api.nowistay.com/public/v1/missions" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "propertyId": 101,
  "bookingId": 9001,
  "missionType": "cleaning",
  "title": "Checkout cleaning",
  "scheduledAt": "2026-12-18T11:30:00Z",
  "timezone": "Europe/Paris",
  "assignedTeamMemberId": 301
}'

Ler o feed de atividade de um alojamento

Exige activity.read.

curl "https://api.nowistay.com/public/v1/properties/101/activity?limit=20" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Os eventos estão agrupados em três categorias: booking, mission e automation (mensagens aos hóspedes, eventos de fechaduras inteligentes).

Endpoints e exemplos adicionais

Todos os caminhos desta secção são relativos a /public/v1. Substitua os IDs de exemplo por recursos pertencentes à conta ligada. O esquema OpenAPI lista todos os campos, enumerações e formatos de resposta suportados.

Detalhes e definições de funcionamento dos alojamentos

Use GET /properties/{id} com properties.read e PATCH /properties/{id} com properties.write. As listas de alojamentos aceitam search. As edições suportadas incluem o nome, a morada, a capacidade, o tipo de alojamento, os links de arrendamento, a capa, as horas de check-in/check-out, os limites de reserva e as definições predefinidas de preços e de estadia.

curl -X PATCH "https://api.nowistay.com/public/v1/properties/101" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "capacity": 4,
  "defaultMinStay": 2,
  "cutOffDays": 1
}'

Criar uma reserva e pedir o pagamento

POST /bookings exige bookings.write, o direito de assistente e uma ligação PMS ativa. Inclua as datas, o e-mail e os dados do hóspede, com os campos de preços e operacionais suportados. requestPayment=true exige adicionalmente payments.write e cria a reserva pendente de pagamento.

curl -X POST "https://api.nowistay.com/public/v1/bookings" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "propertyId": 101,
  "arrival": "2026-12-18",
  "departure": "2026-12-20",
  "guestFirstName": "Maya",
  "guestLastName": "Martin",
  "guestEmail": "maya@example.com",
  "adults": 2,
  "amount": "290.00",
  "currency": "EUR",
  "requestPayment": true
}'

A criação pode ter êxito mesmo que a geração do link de pagamento falhe. A resposta continua a conter a reserva persistida ou o respetivo ID, com paymentRequest.sent=false e um erro explícito. Verifique este resultado antes de tentar de novo, para não criar uma reserva duplicada. Um URL de checkout só é devolvido por uma ação de pedido de pagamento autorizada.

Leia GET /bookings/{id}/payment-request com bookings.read para obter o estado seguro da reserva e do pedido de pagamento. Não devolve URLs de checkout. Esta versão não acrescenta uma API autónoma de administração de pagamentos.

Reembolsos e restrições de reservas relacionadas com pagamentos

O PATCH de reservas existentes suporta reservationNumber, cancellationRefundMode (none, full ou partial) e cancellationRefundAmount. Um reembolso explícito total ou parcial de um cancelamento exige bookings.write e payments.write. O cancelamento sem reembolso exige apenas bookings.write.

curl -X PATCH "https://api.nowistay.com/public/v1/bookings/9001" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "cancelled",
  "cancellationRefundMode": "partial",
  "cancellationRefundAmount": "50.00"
}'

Uma reserva cancelada não prova que o reembolso foi concluído. Verifique o estado do pagamento antes de dizer ao hóspede que o reembolso foi efetuado. payments.write autoriza pedidos de pagamento e reembolsos de cancelamentos, não a revisão do preço de um checkout existente.

  • Depois de existir uma ordem de pagamento, são rejeitadas alterações de datas, total, tarifa por noite, valor da limpeza, imposto ou moeda. Isto aplica-se também a ordens históricas falhadas ou expiradas. As entradas de preços sem efeito aceites continuam permitidas.
  • Uma reserva confirmada e paga não pode voltar a pendente. Uma reserva cancelada e reembolsada não pode ser reativada.
  • Os contactos, as moradas postais, as notas e as edições suportadas de check-in/check-out continuam permitidos.
  • As edições simultâneas e a criação de pedidos de pagamento usam um instantâneo consistente da reserva: o pedido de pagamento usa uma edição anterior bem-sucedida, ou a edição em conflito é rejeitada depois de a ordem existir.

Fichas de hóspedes e histórico de estadias

POST /guests usa customers.write; a criação duplicada de um hóspede devolve 409. As leituras existentes de clientes ao nível do proprietário continuam disponíveis. As listas de hóspedes aceitam propertyId, propertyIds repetido e os valores de orderBy suportados: created_at, updated_at, full_name, bookings_count, total_amount, last_stay. Use o prefixo - para ordem descendente; a predefinição é -updated_at.

curl -X POST "https://api.nowistay.com/public/v1/guests" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "firstName": "Maya",
  "lastName": "Martin",
  "email": "maya@example.com",
  "language": "en"
}'

GET /guests/{id}/bookings exige customers.read e bookings.read e devolve o histórico de estadias elegível.

Detalhes, relatórios e filtros de missões

GET /missions/{id} e GET /missions/{id}/report usam missions.read. Uma missão válida sem relatório de conclusão devolve 200 com report: null. As listas de missões aceitam filtros de datas UTC agendadas, inclusivos, fromDate/toDate, propertyIds e teamMemberIds repetidos, a par dos filtros existentes.

curl "https://api.nowistay.com/public/v1/missions?propertyIds=101&propertyIds=102&teamMemberIds=301&fromDate=2026-12-01&toDate=2026-12-31" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Ler conversas e enviar uma resposta do anfitrião

GET /conversations suporta os filtros propertyId e bookingId. GET /conversations/{id}/messages lê o histórico de mensagens. Ambos exigem messages.read. Envie uma resposta com POST /messages e messages.write, indicando exatamente um de conversationId ou bookingId. O channelKind ou threadChannelId opcional seleciona um canal; não indique os dois seletores.

curl -X POST "https://api.nowistay.com/public/v1/messages" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "bookingId": 9001,
  "message": "Hello Maya, your arrival instructions are ready."
}'

As mensagens seguem o circuito normal de envio de respostas do anfitrião, incluindo o encaminhamento de reservas com vários quartos. Uma mensagem persistida cujo envio falhou devolve o respetivo ID e o estado de envio: inspecione o resultado antes de tentar de novo. Os anexos de mensagens de hóspedes não são suportados por estes endpoints.

Perguntas e respostas privadas dos alojamentos

Use GET /properties/{id}/knowledge-questions e GET /properties/{id}/knowledge-questions/{questionId} com knowledge.read. Use POST na coleção e PATCH numa pergunta individual com knowledge.write.

curl -X POST "https://api.nowistay.com/public/v1/properties/101/knowledge-questions" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "question": "Where is the recycling area?",
  "answer": "In the courtyard, next to the bicycle shelter."
}'

POST /properties/{id}/knowledge-questions/copy trata {id} como a origem e exige knowledge.read e knowledge.write. Envie targetPropertyIds para fundir noutros alojamentos. A cópia nunca elimina nem substitui respostas de destino; cada destino é validado antes de começar qualquer escrita.

curl -X POST "https://api.nowistay.com/public/v1/properties/101/knowledge-questions/copy" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "targetPropertyIds": [102, 103]
}'

Guias de boas-vindas localizados, páginas e imagens

  • GET/PATCH /properties/{id}/welcome-guide: ler ou editar o guia, incluindo as introduções localizadas.
  • GET/POST /properties/{id}/welcome-guide/pages: listar ou criar páginas.
  • GET/PATCH /properties/{id}/welcome-guide/pages/{pageId}: ler ou editar uma página individual e a sua posição.
  • POST /properties/{id}/welcome-guide/images: carregar uma imagem a partir de um URL público suportado ou de uma entrada base64.

As leituras exigem guides.read; as escritas exigem guides.write. Ao editar páginas estruturadas, mantenha os blocos EditorJS content/contents e os respetivos IDs, a formatação aninhada e os conteúdos multimédia. Os idiomas omitidos permanecem inalterados. A substituição de uma página estruturada por texto simples é rejeitada. Os tokens dos guias e os links de acesso dos hóspedes não são devolvidos.

curl -X PATCH "https://api.nowistay.com/public/v1/properties/101/welcome-guide" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "intros": {
    "en": "Welcome! Your practical information is below.",
    "fr": "Bienvenue ! Retrouvez les informations pratiques ci-dessous."
  }
}'

As transferências de imagens têm de usar endereços acessíveis publicamente. Os redirecionamentos são verificados e os limites de tamanho são aplicados. Consulte o esquema do pedido de imagem para ver os campos de URL/base64 suportados e os limites.

Ler extras e compras

GET /upsells exige upsells.read. GET /bookings/{id}/upsell-purchases exige upsells.read e bookings.read. Estes endpoints são só de leitura.

curl "https://api.nowistay.com/public/v1/bookings/9001/upsell-purchases" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Exportar tabelas de reservas e de missões

Acrescente responseFormat=table às listas de reservas ou de missões para obter columns, rows e pagination, com limit até 500. O JSON padrão continua a ser a predefinição e mantém o máximo de 100. Use offset para obter as páginas seguintes. Vários propertyIds são intersetados com propertyId se ambos os filtros forem indicados.

curl "https://api.nowistay.com/public/v1/bookings?propertyIds=101&propertyIds=102&fromDate=2026-12-01&toDate=2026-12-31&responseFormat=table&limit=500&offset=0" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

As tabelas de reservas usam bookings.read; as tabelas de missões usam missions.read. As atribuições de limpeza nos relatórios de reservas exigem adicionalmente missions.read e a presença nas conversas exige messages.read. Os filtros de data das reservas mantêm a semântica de sobreposição; os filtros de data das missões usam datas UTC agendadas.

Compatibilidade com integrações existentes

As rotas REST existentes, as predefinições de JSON padrão, a paginação, a ocultação de dados nas reservas, a limpeza de valores nulos suportada e as predefinições de notificação continuam disponíveis. As restrições de reservas relacionadas com pagamentos descritas acima passam a ser aplicadas. O REST e o MCP partilham as operações subjacentes e os respetivos efeitos secundários, enquanto os contratos das ferramentas MCP e o comportamento de pré-visualização/confirmação permanecem inalterados.

Como estruturar os blocos das páginas do guia de boas-vindas

Uma página da Nowistay contém um documento EditorJS por idioma. A matriz blocks define a ordem de apresentação. Cada objeto dessa matriz é um bloco; coloque os exemplos abaixo dentro de content.blocks ou contents.<locale>.blocks. Os valores dos exemplos são fictícios e devem ser adaptados ao seu alojamento.

Estrutura comum: id é uma cadeia estável, única dentro do documento; mantenha os IDs existentes e atribua um novo a cada bloco novo. type é o nome exato do bloco, sensível a maiúsculas e minúsculas. data é um objeto cujos campos dependem do tipo. Preserve também os tunes e os metadados do documento existentes devolvidos numa leitura, em vez de os reconstruir sem necessidade.

Pedido de criação: POST /public/v1/properties/{id}/welcome-guide/pages com guides.write. Use locale + title + content para um idioma, ou titles + contents para vários. icon tem como predefinição info. position aceita start, end ou after_page; este último exige afterPageId. Eis um corpo de pedido completo em inglês/francês:

{
  "titles": {
    "en": "Arrival",
    "fr": "Arrivée"
  },
  "contents": {
    "en": {
      "blocks": [
        {
          "id": "arrival001",
          "type": "header",
          "data": {
            "text": "Getting here",
            "level": 2
          }
        },
        {
          "id": "arrival002",
          "type": "paragraph",
          "data": {
            "text": "Use the <b>main entrance</b>."
          }
        }
      ]
    },
    "fr": {
      "blocks": [
        {
          "id": "arrival001",
          "type": "header",
          "data": {
            "text": "Venir au logement",
            "level": 2
          }
        },
        {
          "id": "arrival002",
          "type": "paragraph",
          "data": {
            "text": "Utilisez l’<b>entrée principale</b>."
          }
        }
      ]
    }
  },
  "position": "end"
}

Títulos (header)

data.text é o texto do título. Use data.level: 2, em linha com o editor de guias. O próprio título da página pertence a title ou titles, fora dos blocos.

{
  "id": "guide00001",
  "type": "header",
  "data": {
    "text": "Arrival / Arrivée",
    "level": 2
  }
}

Parágrafos e formatação em linha (paragraph)

data.text é uma cadeia. Use as marcas em linha <b>, <i> e <a href="https://…"> para negrito, itálico e links. Escape as aspas duplas dentro de cadeias JSON. Não envie uma página HTML inteira nem Markdown como content.

{
  "id": "guide00002",
  "type": "paragraph",
  "data": {
    "text": "<b>Wi-Fi</b>: GuestNetwork. <i>Welcome / Bienvenue !</i> <a href=\"https://example.com/\">Information</a>"
  }
}

Listas com marcadores e aninhadas (list)

Use style: unordered. items contém objetos, não cadeias. Cada item tem content (texto formatado), meta (um objeto) e items (uma matriz de itens filhos, vazia numa folha). Repita a mesma estrutura para o aninhamento.

{
  "id": "guide00003",
  "type": "list",
  "data": {
    "style": "unordered",
    "meta": {},
    "items": [
      {
        "content": "Kitchen / Cuisine",
        "meta": {},
        "items": [
          {
            "content": "Coffee machine / Machine à café",
            "meta": {},
            "items": []
          }
        ]
      }
    ]
  }
}

Listas numeradas (list)

Use style: ordered com meta.counterType: numeric na raiz. Mantenha a mesma estrutura de itens e as mesmas matrizes aninhadas de uma lista com marcadores.

{
  "id": "guide00004",
  "type": "list",
  "data": {
    "style": "ordered",
    "meta": {
      "counterType": "numeric"
    },
    "items": [
      {
        "content": "Close the windows / Fermez les fenêtres",
        "meta": {},
        "items": []
      },
      {
        "content": "Return the keys / Rendez les clés",
        "meta": {},
        "items": []
      }
    ]
  }
}

Listas de verificação (list)

Use style: checklist. Coloque o estado inicial booleano da caixa em meta.checked de cada item. É conteúdo do guia, não um relatório de conclusão de missão.

{
  "id": "guide00005",
  "type": "list",
  "data": {
    "style": "checklist",
    "meta": {},
    "items": [
      {
        "content": "Windows closed / Fenêtres fermées",
        "meta": {
          "checked": false
        },
        "items": []
      }
    ]
  }
}

Citações e destaques (quote)

data.text é a citação, caption é a sua atribuição (ou uma cadeia vazia) e alignment é a definição de alinhamento do editor. Use left; a vista do hóspede aplica o seu próprio esquema de citação.

{
  "id": "guide00006",
  "type": "quote",
  "data": {
    "text": "Please respect the neighbours / Merci de respecter le voisinage.",
    "caption": "Your host / Votre hôte",
    "alignment": "left"
  }
}

Separadores (delimiter)

Um separador visual tem um objeto data vazio. A sua posição em blocks determina onde aparece a separação.

{
  "id": "guide00007",
  "type": "delimiter",
  "data": {}
}

Tabelas (table)

data.content é uma matriz de linhas; cada linha é uma matriz de cadeias de células. Mantenha o mesmo número de células em cada linha. Com withHeadings: true, a primeira linha fornece os cabeçalhos das colunas. Use false quando todas as linhas contiverem dados normais.

{
  "id": "guide00008",
  "type": "table",
  "data": {
    "withHeadings": true,
    "content": [
      [
        "Service",
        "Time / Horaire"
      ],
      [
        "Check-in / Arrivée",
        "16:00"
      ],
      [
        "Check-out / Départ",
        "10:00"
      ]
    ]
  }
}

Imagens (image)

data.file.url é o URL da imagem carregada, não um nome de ficheiro local nem uma cadeia base64. caption é uma cadeia; withBorder, withBackground e stretched são booleanos. Faça primeiro POST da imagem para /public/v1/properties/{id}/welcome-guide/images e insira depois em content.blocks o editorJsImageBlock devolvido. Preserve os campos devolvidos e use um ID de bloco único. O URL abaixo é ilustrativo: substitua-o pelo URL real devolvido.

{
  "id": "guide00009",
  "type": "image",
  "data": {
    "file": {
      "url": "https://images.example.com/replace-with-uploaded-image.jpg"
    },
    "caption": "Entrance / Entrée",
    "withBorder": false,
    "withBackground": false,
    "stretched": false
  }
}

Vídeos e Shorts do YouTube (video)

Use service: youtube para um vídeo normal do YouTube, ou youtubeShort para um Short. source é o URL original; embed é o URL de incorporação do YouTube correspondente. width e height são números e caption é uma cadeia. O editor usa 580 × 320 para um vídeo normal e 315 × 560 para um Short. Substitua VIDEO_ID_11 nos dois URLs pelo mesmo ID real de 11 carateres do vídeo; nos Shorts, o caminho de origem é /shorts/VIDEO_ID_11. O HTML arbitrário de iframe não é o formato do bloco.

{
  "id": "guide00010",
  "type": "video",
  "data": {
    "service": "youtube",
    "source": "https://www.youtube.com/watch?v=VIDEO_ID_11",
    "embed": "https://www.youtube.com/embed/VIDEO_ID_11",
    "width": 580,
    "height": 320,
    "caption": "Arrival instructions / Instructions d’arrivée"
  }
}

Blocos de incorporação existentes (embed)

embed usa os mesmos campos data que video. Preserve o tipo existente ao editar uma página; ambos apresentam vídeos e Shorts do YouTube. Não presuma que todos os fornecedores de incorporação suportados pelo EditorJS são suportados pela Nowistay.

{
  "id": "guide00011",
  "type": "embed",
  "data": {
    "service": "youtubeShort",
    "source": "https://www.youtube.com/shorts/VIDEO_ID_11",
    "embed": "https://www.youtube.com/embed/VIDEO_ID_11",
    "width": 315,
    "height": 560,
    "caption": ""
  }
}

Catálogo de extras (upsellCatalog)

Use um objeto data vazio para colocar aqui o catálogo de extras elegíveis. Os produtos, os preços e a disponibilidade vêm do catálogo configurado e do contexto do hóspede; não estão incorporados neste bloco.

{
  "id": "guide00012",
  "type": "upsellCatalog",
  "data": {}
}

Um produto extra (upsellProduct)

data.itemId é o ID numérico de um extra existente. Encontre o ID correto com GET /public/v1/upsells usando upsells.read; substitua o 401 fictício abaixo. Mantenha o ID original, a menos que queira selecionar outro produto. Escrever a página usa guides.write; este bloco não cria um produto, não define um preço nem o compra.

{
  "id": "guide00013",
  "type": "upsellProduct",
  "data": {
    "itemId": 401
  }
}

Validação REST: a criação e as atualizações de páginas rejeitam tipos de bloco não suportados e dados malformados com HTTP 422. Todos os idiomas fornecidos são verificados antes de qualquer escrita, incluindo itens de listas aninhadas, células de tabelas e campos multimédia. O erro identifica o documento e o bloco em causa. Os IDs continuam opcionais nos documentos existentes; quando fornecidos, têm de ser cadeias únicas não vazias. Os metadados e a formatação são preservados. Esta validação estrutural não verifica se uma imagem está acessível nem se um extra existe.

Controlos do editor e formatos a preservar

imageLibrary é o controlo de seleção de imagens do editor, não um bloco de galeria da API. Use blocos image. linkPreview é uma definição de bloco (tunes), não um tipo de conteúdo separado; preserve os dados existentes. Não invente blocos html, code, button nem fornecedores de vídeo não documentados: a aceitação de um objeto JSON não garante que seja apresentado no guia.

Editar uma página sem perder conteúdo

Comece por ler GET /public/v1/properties/{id}/welcome-guide/pages/{pageId} com guides.read para obter content e contents. Trabalhe numa cópia do documento completo do idioma que está a editar, altere apenas os blocos pretendidos e faça depois PATCH desse documento para o mesmo URL com guides.write. Enviar apenas um bloco substitui o documento por esse único bloco; os blocos não são fundidos por id. Os idiomas omitidos permanecem inalterados. Para mover uma página existente, use order, não position.

Os campos text e texts não substituem o documento estruturado. Siga as indicações simpleTextUpdateAllowed, recommendedUpdateMode e recommendedUpdateField da resposta de leitura; uma página estruturada rejeita a substituição por texto simples. Os exemplos individuais desta secção descrevem blocos, não pedidos PATCH completos para uma página existente. Volte a ler a página depois de editar e verifique idiomas, IDs, links e conteúdos multimédia. Só com guides.write, a resposta de escrita é mínima; acrescente guides.read para receber os detalhes.

Webhooks (eventos em tempo real)

Se não quer consultar a API repetidamente para detetar alterações, pode subscrever webhooks. A Nowistay chamará então um URL que indicar sempre que uma reserva for criada ou atualizada no alojamento e enviará os mesmos dados da reserva que GET /public/v1/bookings/{id} devolve.

Hoje são suportados dois eventos:

  • booking.created: foi registada uma nova reserva no alojamento.
  • booking.updated: uma reserva existente mudou (datas, estado, dados do hóspede, código da fechadura inteligente, etc.).

Cada webhook está associado a um único alojamento e pode registar até três por alojamento. As entregas são assinadas (HMAC-SHA256) para poder verificar que provêm mesmo da Nowistay, são repetidas com recuo exponencial em caso de falha e o endpoint é desativado automaticamente se continuar a falhar durante mais de 72 horas. Os payloads dos webhooks não contêm campos sensíveis do hóspede (e-mail, telefone, morada, código da fechadura inteligente). Quando precisar deles, chame a API com o âmbito bookings.sensitive.read.

Os detalhes completos de configuração e de verificação da assinatura estão no artigo dedicado: API pública: receber webhooks de reservas em tempo real.

Limites de pedidos

  • Endpoints de leitura: 120 pedidos por minuto por cliente e por rota.
  • Endpoints de escrita (POST, PATCH): 30 pedidos por minuto por cliente e por rota.
  • Endpoints OAuth: 20 pedidos por minuto por IP ou cliente.

Quando atinge o limite, a API devolve 429 Rate limit exceeded. Aguarde e tente de novo passados alguns segundos.

Formato dos erros

Todos os erros seguem a mesma estrutura, com um code estável, uma mensagem legível e um requestId que pode incluir nos pedidos de suporte.

{
  "error": {
    "code": "validation_error",
    "message": "The request contains an invalid value.",
    "requestId": "example-request-id"
  }
}

400: pedido inválido (corpo malformado, campo em falta).

  • 401: token bearer em falta ou inválido.
  • 403: o token é válido, mas falta-lhe um âmbito necessário, ou não tem o direito do AI Channel Manager.
  • 404: recurso não encontrado, ou não tem acesso a ele.
  • 409: conflito (por exemplo, a chave do parâmetro já existe).
  • 422: falha de validação.
  • 429: limite de pedidos atingido.

Boas práticas

  • Peça o menor conjunto de âmbitos possível. Adicione novos âmbitos mais tarde, à medida que a sua integração crescer.
  • Guarde os tokens no servidor. Nunca distribua um token de longa duração num cliente público nem o inclua num repositório.
  • Trate o 401 com uma atualização. Quando a atualização também falhar, envie o utilizador de volta pelo fluxo de autorização.
  • Use o indicador silent nas escritas. Defina-o como true quando sincroniza dados em massa e não quer desencadear notificações aos hóspedes.
  • Guarde o requestId nos seus registos. Torna os pedidos de suporte muito mais rápidos de resolver.

Onde ir a seguir

  • Abra a documentação em direto e experimente todos os endpoints: api.nowistay.com/public/docs.
  • Leia o esquema completo e transfira um ficheiro OpenAPI em /public/openapi.json.
  • Precisa de um âmbito ou de um endpoint que ainda não está listado? Escreva ao suporte e conte-nos o seu caso de utilização.

Pronto para pôr o seu alojamento em piloto automático?

Junte-se a mais de 1000 gestores de alojamentos que poupam horas todas as semanas com a comunicação com hóspedes assistida por IA.