Pular para o conteúdo

Integração com Webhook

Webhooks permitem que 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 você na configuração e nas melhores práticas.

Este guia é para desenvolvedores que integram o Wink com sistemas externos, como sistemas de gestão de propriedades (PMS), gerenciadores de canais, CRMs ou painéis personalizados.

  1. Você registra uma URL de webhook no Wink.
  2. Quando um evento ocorre (por exemplo, uma nova reserva), o Wink envia um HTTP POST para sua URL.
  3. Seu servidor processa o payload e responde com um 200 OK.
  1. Faça login 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. Insira um nome (ex.: “Sincronização de Reservas PMS”).
  5. Insira sua URL do webhook — o endpoint HTTPS no seu servidor.
  6. Selecione eventos — Escolha eventos específicos para assinar ou deixe vazio para receber todos os eventos.
  7. Ative o botão Enabled.
  8. Clique em Save — a resposta mostrará seu segredo de assinatura uma única vez; armazene-o agora.

O Wink publica hoje 70 tipos de eventos de webhook relacionados a reservas, propriedades, contas (entidades gestoras) e inventário (tipos de quarto, planos de tarifa, tarifas mestre, adicionais, 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, quem a recebe 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.

Veja todos os tipos de eventos

Cada entrega é um HTTP POST para 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 — identificador do evento; idêntico para cada endpoint da sua conta que recebe este evento e para cada reenvio. Use como sua chave de idempotência.
  • type — 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 curado do recurso ao qual o evento se refere (identificadores, status, os campos que você atua) mais links.self, a URL REST canônica do lado do fornecedor do recurso completo. Busque com suas próprias credenciais de API quando precisar de mais 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 ao id no corpo — sua chave de idempotência.
Wink-Delivery-IdÚnico por endpoint por evento; muda apenas se você reenviar.
Wink-Event-TypeIgual ao 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 única vez, quando você cria o webhook ou gira seu segredo. Armazene como uma senha. Cada entrega carrega

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 do seu segredo, e rawBody é o corpo exato da requisição em bytes conforme recebido — não reserialize o JSON antes de verificar. Por 24 horas após a rotação do segredo, o cabeçalho carrega 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 seu segredo; compare com uma comparação em tempo constante; rejeite se |agora − t| exceder 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)));
}

Gire o segredo pelo portal ou com POST /api/managing-entity/{id}/webhook/{webhookId}/rotate-secret; a resposta mostra o novo segredo uma única vez, e o antigo continua válido por 24 horas enquanto você o substitui.

  • Responda com qualquer 2xx em até 10 segundos para confirmar. Faça o processamento pesado de forma assíncrona.
  • Um 5xx, timeout, 408 ou 429 é reenviado 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 “você rejeitou esta entrega” e não é reenviado.
  • Cada evento, entrega e tentativa (status, trecho da resposta) é visível em Applications > Webhooks e via API (…/webhook/event/grid, …/webhook/delivery/grid). Você 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 mesmo um evento sintético webhook.test pelo portal ou com POST /api/managing-entity/{id}/webhook/{webhookId}/test. Ele é assinado e entregue exatamente como um evento real, para que você possa verificar seu endpoint, a verificação da assinatura e o tratamento de idempotência antes de assinar 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 — Seu handler deve ser idempotente; deduplique pelo Wink-Event-Id. O Wink reenvia quando não recebe uma resposta 2xx.
  • Valide a origem — Verifique o cabeçalho Wink-Signature (veja Verificando assinaturas) antes de processar; rejeite qualquer coisa que falhar.
  • Registro de logs — Registre todo payload de webhook que receber. Isso facilita muito a depuração de problemas de integração.

Você pode desabilitar um webhook sem excluí-lo. Isso pausa a entrega para que você possa solucionar problemas sem perder sua configuração. Quando estiver pronto, ative-o novamente.

Excluir um webhook remove-o permanentemente. Qualquer integração que dependa desse webhook deixará de receber notificações.