Pular para o conteúdo

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.

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.

  1. Regista uma URL de webhook no Wink.
  2. Quando ocorre um evento (por exemplo, uma nova reserva), o Wink envia um HTTP POST para a sua URL.
  3. O seu servidor processa o payload e responde com um 200 OK.
  1. Inicie sessão na sua conta (Extranet, Studio ou TripPay — todos suportam webhooks).
  2. Navegue até Applications e depois Webhooks. Veja Webhooks.
  3. Clique em Create webhook.
  4. Introduza um nome (por exemplo, “Sincronização de Reservas PMS”).
  5. Introduza a sua URL de webhook — o endpoint HTTPS no seu servidor.
  6. Selecione eventos — Escolha eventos específicos para subscrever, ou deixe vazio para receber todos os eventos.
  7. Ative o botão Enabled.
  8. Clique em Save — a resposta mostra o seu segredo de assinatura uma vez; guarde-o agora.

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:

CategoriaExemplos
Reservabooking.create, booking.cancelled, booking.refund.partial, booking.refund.full, booking.review.created
Propriedadeproperty.created, property.status.updated, property.policy.updated
Inventárioroom_type.updated, rate_plan.created, master_rate.updated, special_rate.created, sales_channel.created
Contamanaging_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

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çalho Wink-Event-Type). Faça ramificações com base em type e schemaVersion para analisar object.
  • object — um resumo selecionado do recurso a que o evento se refere (identificadores, estado, os campos que você manipula) mais links.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çalhoSignificado
Wink-VersionVersão do contrato de comunicação, 2.0.
Wink-Event-IdIgual a id no corpo — a sua chave de idempotência.
Wink-Delivery-IdÚnico por endpoint por evento; muda apenas se reenviar.
Wink-Event-TypeIgual a type no corpo.
Wink-Delivery-AttemptNúmero da tentativa para esta entrega, começando em 1.
Wink-SignatureAssinatura HMAC — veja abaixo.

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')));
}
// Java
static 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.

  • Responda com qualquer 2xx dentro de 10 segundos para confirmar. Faça o trabalho pesado de forma assíncrona.
  • Um 5xx, timeout, 408 ou 429 é 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.

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.

  • Use HTTPS — O Wink envia payloads apenas para endpoints HTTPS.
  • Responda rapidamente — Retorne um 200 OK assim 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 resposta 2xx.
  • 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.

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.