Integração de Webhook
Os webhooks permitem que os seus sistemas recebam notificações em tempo real quando eventos acontecem na sua conta Wink — novas reservas, cancelamentos, atualizações de pagamento e mais. Este guia orienta-o na configuração e nas melhores práticas.
Público-alvo
Seção intitulada “Público-alvo”Este guia destina-se a desenvolvedores que integram o Wink com sistemas externos, como sistemas de gestão de propriedades (PMS), gestores de canais, CRMs ou painéis personalizados.
Como funcionam os webhooks
Seção intitulada “Como funcionam os webhooks”- Regista uma URL de webhook no Wink.
- Quando ocorre um evento (por exemplo, uma nova reserva), o Wink envia um HTTP POST para a sua URL.
- O seu servidor processa o payload e responde com um
200 OK.
Configurar um webhook
Seção intitulada “Configurar um webhook”- Inicie sessão na sua conta (Extranet, Studio ou TripPay — todos suportam webhooks).
- Navegue até
Applicationse depoisWebhooks. Veja Webhooks. - Clique em
Create webhook. - Introduza um nome (por exemplo, “Sincronização de Reservas PMS”).
- Introduza a sua URL de webhook — o endpoint HTTPS no seu servidor.
- Selecione eventos — Escolha eventos específicos para subscrever, ou deixe vazio para receber todos os eventos.
- Ative o botão Enabled.
- Clique em
Save— a resposta mostra o seu segredo de assinatura uma vez; guarde-o agora.
Tipos de eventos
Seção intitulada “Tipos de eventos”O Wink publica atualmente 70 tipos de eventos de webhook relacionados com reservas, propriedades, contas (entidades gestoras) e inventário (tipos de quarto, planos tarifários, tarifas principais, extras, instalações, canais de venda, promoções). Os mais comuns:
| Categoria | Exemplos |
|---|---|
| Reserva | booking.create, booking.cancelled, booking.refund.partial, booking.refund.full, booking.review.created |
| Propriedade | property.created, property.status.updated, property.policy.updated |
| Inventário | room_type.updated, rate_plan.created, master_rate.updated, special_rate.created, sales_channel.created |
| Conta | managing_entity.created, managing_entity.status.updated, managing_entity.manager.added |
A lista completa e gerada — com descrição, destinatários e um link para a página de referência de cada evento — é o Catálogo de Eventos de Webhook. A página de referência para cada evento (corpo JSON, cabeçalhos, política de reenvio) está na API de Webhooks.
Ver todos os tipos de evento
O que recebe
Seção intitulada “O que recebe”Cada entrega é um HTTP POST para a sua URL de webhook com Content-Type: application/json e este envelope:
{ "id": "0198a4f2-6b0e-7c1d-9a3e-2f4b8c6d1e0a", "type": "booking.create", "occurredAt": "2026-08-15T09:30:00Z", "ownerIdentifier": "3c6b1a5d-8e2f-4a0b-9c7d-6e4f0a8b2c51", "recipientRole": "SUPPLIER", "schemaVersion": 2, "object": { "...": "payload específico do evento, ex. BookingWebhookPayload" }}id— o identificador do evento; idêntico para cada endpoint da sua conta que recebe este evento e para cada reenvio. Use-o como a sua chave de idempotência.type— a chave do tipo de evento (também enviada no cabeçalhoWink-Event-Type). Faça ramificações com base emtypeeschemaVersionpara analisarobject.object— um resumo selecionado do recurso a que o evento se refere (identificadores, estado, os campos que você manipula) maislinks.self, a URL REST canónica do lado do fornecedor do recurso completo. Busque-a com as suas próprias credenciais API quando precisar de mais do que o resumo; se receber o evento como revendedor ou agente de viagens, use o endpoint correspondente da sua própria API para o mesmo identificador.
Cada esquema de payload está documentado por evento na referência da API de Webhooks.
Cabeçalhos
Seção intitulada “Cabeçalhos”| Cabeçalho | Significado |
|---|---|
Wink-Version | Versão do contrato de comunicação, 2.0. |
Wink-Event-Id | Igual a id no corpo — a sua chave de idempotência. |
Wink-Delivery-Id | Único por endpoint por evento; muda apenas se reenviar. |
Wink-Event-Type | Igual a type no corpo. |
Wink-Delivery-Attempt | Número da tentativa para esta entrega, começando em 1. |
Wink-Signature | Assinatura HMAC — veja abaixo. |
Verificação de assinaturas
Seção intitulada “Verificação de assinaturas”Cada webhook tem um segredo de assinatura (whsec_…) que o Wink mostra uma vez, quando cria o webhook ou roda o seu segredo. Guarde-o como uma palavra-passe. Cada entrega traz
Wink-Signature: t=1755250200,v1=5d41402abc4b2a76b9719d911017c592…onde t é um timestamp Unix (segundos) e v1 é o HMAC-SHA256 em hex minúsculo da string t + "." + rawBody, com chave no seu segredo, e rawBody são os bytes exatos do corpo da requisição tal como recebidos — não reserialize o JSON antes de verificar. Durante 24 horas após a rotação do segredo, o cabeçalho traz um segundo valor v1= assinado com o segredo anterior; aceite a entrega se qualquer v1 corresponder.
Verifique em quatro passos: analise t e cada v1; recalcule o HMAC sobre t.rawBody com o seu segredo; compare com uma comparação em tempo constante; rejeite se |agora − t| exceder a sua tolerância (recomendado 5 minutos).
// Node.js (estilo Express; certifique-se de ter o corpo RAW, não um objeto parseado)import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWinkSignature(header, rawBody, secret, toleranceSeconds = 300) { const parts = Object.fromEntries(header.split(',').map((p) => p.split('=').map((s) => s.trim()))); const t = Number(parts.t); if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false; const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); return header .split(',') .filter((p) => p.trim().startsWith('v1=')) .map((p) => p.trim().slice(3)) .some((v1) => v1.length === expected.length && timingSafeEqual(Buffer.from(v1, 'utf8'), Buffer.from(expected, 'utf8')));}// Javastatic boolean verify(String header, String rawBody, String secret, long nowSeconds, long toleranceSeconds) throws Exception { long t = Long.MIN_VALUE; List<String> signatures = new ArrayList<>(); for (String part : header.split(",")) { String[] kv = part.trim().split("=", 2); if (kv[0].equals("t")) t = Long.parseLong(kv[1]); else if (kv[0].equals("v1")) signatures.add(kv[1]); } if (t == Long.MIN_VALUE || Math.abs(nowSeconds - t) > toleranceSeconds) return false; Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); byte[] expected = HexFormat.of().formatHex(mac.doFinal((t + "." + rawBody).getBytes(StandardCharsets.UTF_8))).getBytes(StandardCharsets.US_ASCII); return signatures.stream().anyMatch(v1 -> MessageDigest.isEqual(expected, v1.toLowerCase().getBytes(StandardCharsets.US_ASCII)));}Rode o segredo a partir do portal ou com POST /api/managing-entity/{id}/webhook/{webhookId}/rotate-secret; a resposta mostra o novo segredo uma vez, e o antigo continua a verificar durante 24 horas enquanto o implementa.
Repetições e reentregas
Seção intitulada “Repetições e reentregas”- Responda com qualquer
2xxdentro de 10 segundos para confirmar. Faça o trabalho pesado de forma assíncrona. - Um
5xx, timeout,408ou429é reintentado com backoff: após 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas, 12 horas, depois diariamente — 10 tentativas em cerca de 3 dias — após o que a entrega é marcada como morta. - Qualquer outro
4xxé tratado como “rejeitou esta entrega” e não é reintentado. - Cada evento, entrega e tentativa (estado, excerto da resposta) é visível em Applications > Webhooks e via API (
…/webhook/event/grid,…/webhook/delivery/grid). Pode reenviar qualquer entrega (POST …/webhook/delivery/{deliveryId}/redeliver, que inicia uma nova série de tentativas), reenviar todas as entregas mortas de um webhook de uma vez (POST …/webhook/{webhookId}/redeliver-dead), ou cancelar uma. - As entregas são mantidas por 30 dias.
Eventos de teste
Seção intitulada “Eventos de teste”Envie para si próprio um evento sintético webhook.test a partir do portal ou com POST /api/managing-entity/{id}/webhook/{webhookId}/test. É assinado e entregue exatamente como um evento real, para que possa verificar o seu endpoint, a verificação da assinatura e o tratamento de idempotência antes de subscrever eventos ao vivo.
Melhores práticas
Seção intitulada “Melhores práticas”- Use HTTPS — O Wink envia payloads apenas para endpoints HTTPS.
- Responda rapidamente — Retorne um
200 OKassim que receber o payload. Faça qualquer processamento pesado de forma assíncrona. - Idempotência — O seu handler deve ser idempotente; deduplique com base em
Wink-Event-Id. O Wink reenvia quando não recebe uma resposta2xx. - Valide a origem — Verifique o cabeçalho
Wink-Signature(veja Verificação de assinaturas) antes de processar; rejeite tudo o que falhar. - Registo — Registe todos os payloads de webhook que receber. Isto facilita muito a depuração de problemas de integração.
Pausar e eliminar
Seção intitulada “Pausar e eliminar”Pode desativar um webhook sem o eliminar. Isto pausa a entrega para que possa resolver problemas sem perder a configuração. Quando estiver pronto, volte a ativá-lo.
Eliminar um webhook remove-o permanentemente. Qualquer integração que dependa desse webhook deixará de receber notificações.
Leitura adicional
Seção intitulada “Leitura adicional”- Catálogo de Eventos de Webhook — Todos os tipos de evento, gerados a partir do catálogo da plataforma.
- Referência da API de Webhooks — Esquemas de payload por evento, cabeçalhos e endpoints de gestão de subscrição/entrega.
- Webhooks — Referência completa para gestão de webhooks.
- Applications — Gerir as suas credenciais API.
- Developers > APIs — Documentação completa da API.
