VipterCentral de Ajuda
Integrações

Receber eventos no seu sistema (webhooks)

Receba no seu servidor um aviso assinado a cada venda, reembolso, assinatura ou cliente novo, com novas tentativas automáticas e histórico de entregas.

Admin ou DonoTodos os planosVerificado em 28 de set. de 2026

Um webhook é um endereço do seu sistema que o Vipter chama quando algo acontece na loja: uma venda aprovada, um reembolso, uma assinatura cancelada. Cada chamada é um POST com os dados em JSON e uma assinatura que prova que veio do Vipter. Esta página é para quem vai programar o recebimento, ou para passar a quem vai.

Antes de começar

  • Um endereço https:// no seu sistema que aceite POST e responda com um código 2xx em até 10 segundos.
  • Papel Admin ou Dono no projeto do Vipter.

Passo 1: adicionar o endpoint

  1. No painel do Vipter, abra GeralIntegraçõesAutomaçõesWebhooks.
  2. Clique em Adicionar endpoint.
  3. Preencha os campos numerados:
Formulário Adicionar endpoint com URL, descrição e a lista de tipos de evento numerados
#CampoO que colar
1URL do endpointObrigatórioO endereço que vai receber os eventos. Precisa começar com https://.
2DescriçãoOpcionalUm lembrete para você, como "ERP da loja". Até 200 caracteres.
3Tipos de eventoOpcionalMarque só os eventos que o seu sistema usa. Sem nenhum marcado, o endpoint recebe todos, inclusive os que forem criados no futuro.
  1. Clique em Criar endpoint.

Os eventos de um endpoint não podem ser editados depois. Para mudar a lista, crie um endpoint novo e remova o antigo.

Passo 2: guardar o segredo de assinatura

Logo depois de criar, o Vipter mostra Seu segredo de assinatura: um valor que começa com whsec_. Guarde agora. Só é exibido uma vez; você pode rotacionar depois.

Copie o segredo e guarde no seu sistema, por exemplo numa variável de ambiente. Depois de fechar a janela, o endpoint mostra só o final do segredo.

Trate o segredo como uma senha

Quem tem o segredo consegue forjar eventos que passam pela verificação. Não coloque o segredo no código-fonte nem o envie por e-mail. Se ele vazar, gere outro pelo botão Rotacionar segredo.

Passo 3: verificar a assinatura

Cada chamada traz estes cabeçalhos:

CabeçalhoConteúdo
Vipter-Signaturet=<data em segundos Unix>,v1=<assinatura>. Durante a troca de segredo, vem um segundo v1=.
Vipter-Event-IdO ID do evento, como evt_….
Vipter-Event-TypeO tipo do evento, como order.paid.
User-AgentVipter-Webhooks/1.0

A assinatura é um HMAC SHA-256, em hexadecimal, calculado com o seu segredo sobre o texto <t>.<corpo>: o valor de t, um ponto e o corpo da requisição exatamente como chegou. Para conferir:

  1. Leia o corpo cru, antes de qualquer conversão para JSON. Um corpo reformatado gera outra assinatura.
  2. Recalcule o HMAC com o seu segredo e compare com cada v1= do cabeçalho. Basta um igual.
  3. Recuse chamadas com t muito antigo. O exemplo abaixo aceita até 5 minutos de diferença.

O mesmo código aparece no painel, em Trecho de verificação (Node.js):

import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyVipterSignature(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  return header.split(',').filter((p) => p.startsWith('v1=')).some((p) => {
    const given = Buffer.from(p.slice(3), 'hex');
    return given.length === expected.length / 2 && timingSafeEqual(given, Buffer.from(expected, 'hex'));
  });
}

Um exemplo com Express, que recebe o corpo cru e responde logo:

import express from 'express';

const app = express();

app.post('/webhooks/vipter', express.raw({ type: 'application/json' }), (req, res) => {
  const raw = req.body.toString('utf8');
  if (!verifyVipterSignature(raw, req.get('Vipter-Signature') ?? '', process.env.VIPTER_WEBHOOK_SECRET)) {
    return res.status(400).send('assinatura inválida');
  }
  const event = JSON.parse(raw);
  // Guarde event.id e ignore se ele já foi processado.
  res.sendStatus(200);
  // Processe event.type e event.data.object depois de responder.
});

Passo 4: enviar um evento de teste

  1. Com o endpoint ativo, clique em Enviar evento de teste, no topo da página.
  2. Aparece Evento de teste enfileirado. e a entrega entra em Entregas recentes.

O teste é um evento customer.created com um cliente fictício e "test": true dentro de data.object. Ele só chega aos endpoints ativos que recebem customer.created ou todos os eventos.

Deu certo se

A entrega aparece em Entregas recentes com o status succeeded e o código HTTP que o seu sistema respondeu, e o seu sistema aceitou a assinatura.

O formato dos eventos

Todo evento tem o mesmo envelope. O objeto em data.object depende do tipo.

{
  "id": "evt_4f1c2a9b0d3e5f6a7b8c9d0e",
  "object": "event",
  "type": "order.paid",
  "created": 1790000000,
  "livemode": true,
  "api_version": "2026-09-01",
  "data": {
    "object": {
      "object": "order",
      "id": "…",
      "status": "…",
      "total_amount": 19700,
      "currency": "BRL"
    }
  }
}
  • id é único por evento. Use para ignorar repetições: uma entrega reenviada chega com o mesmo id.
  • Valores em dinheiro vêm em centavos, como 19700 para R$ 197,00.
  • Pedido ("object": "order"): id, customer_id, customer_email, subscription_id, status, total_amount, currency, refunded_amount, order_type, recurrence, offer_id, payment_method, provider_slug, paid_at, items, external_order_id, status_source, created_at, updated_at. Em order.paid, também downloads, com os links de download do comprador quando o produto tem arquivos.
  • Assinatura ("object": "subscription"): id, customer_id, customer_email, customer_name, status, current_offer_id, offer_name, product_id, product_name, billing_cycle, currency, current_amount, current_period_start, current_period_end, next_billing_at, trial_start, trial_end, cycles_completed, cycle_limit, cancel_at_period_end, cancelled_at, cancellation_reason, payment_instrument_id, created_at, updated_at.
  • Cliente ("object": "customer"): id, email, name, phone, document_type, metadata, created_at, updated_at.
  • Checkout abandonado ("object": "checkout_abandonment"): o comprador (customer), a oferta, o produto, a quantidade e o valor.

Lista de eventos

EventoQuando é enviado
order.paidUm pagamento foi aprovado. Vale também para as renovações de assinatura, com recurrence: "subsequent", e para vendas marcadas como pagas pela equipe, com status_source: "manual".
order.failedUma cobrança foi recusada.
order.refundedUm pedido foi reembolsado.
order.partially_refundedParte de um pedido foi reembolsada.
order.charged_backO comprador contestou a compra no banco (chargeback).
subscription.createdUma assinatura foi criada.
subscription.renewedUma assinatura foi renovada.
subscription.dunningA cobrança da renovação falhou e a assinatura está em recuperação.
subscription.reactivatedUma assinatura voltou a ficar ativa.
subscription.upgradedO assinante mudou para um plano mais caro.
subscription.downgradedO assinante mudou para um plano mais barato.
subscription.payment_method_changedO cartão da assinatura foi trocado.
subscription.pausedA assinatura foi pausada.
subscription.resumedA assinatura pausada voltou.
subscription.cancelledA assinatura foi cancelada.
subscription.expiredA assinatura terminou.
customer.createdUm cliente novo foi cadastrado.
customer.updatedOs dados de um cliente mudaram.
checkout.abandonedO comprador preencheu os dados no checkout e não pagou. É enviado depois de um tempo sem atividade, e só se ele não comprou nesse meio-tempo.
checkout.recoveredUm checkout abandonado terminou em compra.

Entregas e novas tentativas

Uma entrega dá certo quando o seu sistema responde com um código 2xx em até 10 segundos. Qualquer outra resposta, incluindo redirecionamentos, ou a falta de resposta conta como falha.

Depois de uma falha, o Vipter tenta de novo, até 8 tentativas no total. A espera entre elas é de 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas, 24 horas e 48 horas. Depois da oitava tentativa, a entrega fica com o status exhausted.

Em Entregas recentes, cada linha mostra o Evento, o Status com o código HTTP e o erro, as Tentativas e a Última tentativa. As entregas que não deram certo têm o botão Reenviar, que recomeça as tentativas do zero.

Endpoint desativado sozinho

Se 20 entregas seguidas esgotarem as tentativas, o Vipter desativa o endpoint e mostra o motivo no card dele. Uma entrega bem-sucedida zera essa contagem. Corrija o seu sistema e ligue o endpoint de novo pela chave Ativo.

Enquanto um endpoint está desativado, os eventos novos não são guardados para ele. Use a lista de pedidos e de assinaturas do painel para conferir o que aconteceu nesse período.

Trocar o segredo ou remover o endpoint

  • Rotacionar segredo: gera um segredo novo e mostra uma única vez. Rotacionar o segredo? O anterior continua válido por 24 horas. Nesse período, cada chamada traz as duas assinaturas, e o seu sistema pode trocar o segredo sem perder eventos.
  • Remover: Remover este endpoint e seu histórico de entregas?

Problemas comuns

  • Informe uma URL https://

    O endereço não começa com https:// ou tem erro de digitação. Endereços http:// não são aceitos.

  • A assinatura nunca confere

    O corpo foi convertido para JSON antes da verificação, ou o segredo é de outro endpoint. Verifique o corpo cru e confira o final do segredo no card do endpoint.

  • As entregas falham com timeout

    O seu sistema demora mais de 10 segundos para responder. Responda 200 assim que validar a assinatura e processe o evento depois.

  • O botão de teste está desabilitado

    Não há endpoint ativo. Ligue a chave Ativo de um endpoint.

O que fazer a seguir

Nesta página