VipterCentral de Ajuda
Desenvolvedores

Formato do envelope

A requisição que o Vipter faz ao seu endpoint, campo a campo, com os cabeçalhos, o prazo de resposta, como tratar eventos repetidos e o que o Vipter garante sobre a ordem.

Cada evento chega como um POST para a URL do endpoint. O corpo é um objeto JSON, o envelope, que é igual para todos os tipos. O que muda é o objeto dentro de data.object, descrito no catálogo de eventos.

A requisição

POST /webhooks/vipter HTTP/1.1
Host: erp.example.com
Content-Type: application/json
User-Agent: Vipter-Webhooks/1.0
Vipter-Signature: t=1790604192,v1=5d41402abc4b2a76b9719d911017c592ae2e6b7c0f1d3e5a7b9c2d4f6a8b0c1e
Vipter-Event-Id: evt_3f9a1c7e5b2d4f6a8c0e1b3d
Vipter-Event-Type: order.paid

{"id":"evt_3f9a1c7e5b2d4f6a8c0e1b3d","object":"event","type":"order.paid","created":1790604191,"livemode":true,"api_version":"2026-09-01","data":{"object":{"object":"order","id":"ord_5c1e8a2b9d4f4e7a8b3c6d1e2f7a9b0c", "…": "…"}}}

O corpo vem em JSON compacto, sem espaços nem quebras de linha, em UTF-8. Não reformate o corpo antes de verificar a assinatura.

Cabeçalhos

CabeçalhoConteúdo
Content-Typeapplication/json
User-AgentVipter-Webhooks/1.0
Vipter-Signaturet=<segundos Unix>,v1=<HMAC em hexadecimal>. Durante a troca de segredo, vem um segundo v1=. Veja Verificar a assinatura.
Vipter-Event-IdO mesmo valor do campo id do corpo. Dá para descartar uma repetição antes de ler o corpo.
Vipter-Event-TypeO mesmo valor do campo type do corpo. Dá para rotear o evento sem ler o corpo.

Na maioria dos frameworks, os nomes de cabeçalho não diferenciam maiúsculas: vipter-signature no Node.js, $_SERVER['HTTP_VIPTER_SIGNATURE'] no PHP.

Campos do envelope

CampoTipoConteúdo
idtextoID único do evento: evt_ seguido de 24 caracteres hexadecimais. É o mesmo em todas as tentativas e reenvios.
objecttextoSempre "event".
typetextoTipo do evento, como order.paid. Veja o catálogo.
createdinteiroQuando o evento foi criado, em segundos Unix. Não muda entre tentativas.
livemodebooleanoO ambiente do Vipter que gerou o evento. Não indica se o provedor de pagamento estava em modo de teste: uma compra de teste com um provedor em sandbox chega com o mesmo valor das vendas reais.
api_versiontextoVersão do formato. Hoje todos os eventos saem com "2026-09-01".
data.objectobjetoO pedido, a assinatura, o cliente ou o checkout abandonado, no estado em que estava quando o evento foi criado.

created e o t da assinatura são coisas diferentes. created é o momento do evento e fica fixo. t é o momento do envio daquela tentativa e muda a cada tentativa.

A resposta

A entrega dá certo quando o seu servidor responde com qualquer código 2xx em até 10 segundos. O corpo da resposta é ignorado.

Conta como falha, e gera nova tentativa:

  • Qualquer código fora de 2xx, inclusive 3xx. O Vipter não segue redirecionamentos: se a URL mudou, atualize o endpoint.
  • Nenhuma resposta em 10 segundos. A entrega fica com o erro timeout.
  • Erro de rede, DNS ou TLS. A URL precisa ser https://, com certificado válido.

Responda 2xx também para os tipos de evento que o seu sistema ignora. Uma resposta de erro não descarta o evento: ele volta nas tentativas seguintes e conta para a desativação automática.

Responda antes de processar

Verifique a assinatura, grave o evento numa fila ou tabela e responda 200. Faça o trabalho pesado, como chamar outros sistemas, depois de responder.

Idempotência

A entrega é "pelo menos uma vez". O mesmo evento, com o mesmo id, pode chegar mais de uma vez quando:

  • o seu servidor processou o evento mas a resposta não chegou ao Vipter em 10 segundos, e a tentativa seguinte repete o envio;
  • alguém clicou em Reenviar numa entrega;
  • o envio foi interrompido do lado do Vipter antes de registrar o resultado. A entrega volta para a fila depois de 5 minutos e é enviada de novo.

Para isso, guarde o id (ou o cabeçalho Vipter-Event-Id) numa coluna com restrição de unicidade e ignore o evento se ele já existe:

create table vipter_events (
  id text primary key,          -- evt_…
  type text not null,
  received_at timestamptz not null default now()
);

-- Ao receber: se a linha já existe, o evento é uma repetição.
insert into vipter_events (id, type) values ($1, $2) on conflict (id) do nothing;

Existe um segundo caso, com id diferente: o mesmo fato em dois eventos. Uma mudança feita no painel ou na área do cliente, como cancelar uma assinatura, gera o evento na hora, e a confirmação do provedor sobre a mesma mudança pode gerar outro evento do mesmo tipo. Por isso, além de descartar id repetido, faça o processamento depender do estado e não do evento: "marcar a assinatura como cancelada" pode rodar duas vezes sem problema, "mandar o e-mail de cancelamento" precisa conferir se já foi mandado.

Ordem dos eventos

O Vipter não garante a ordem de chegada. Entregas são feitas em paralelo, e uma entrega que falhou volta horas depois, quando eventos mais novos já chegaram. Um subscription.renewed pode chegar antes do order.paid da renovação, e um order.refunded pode chegar antes do order.paid do mesmo pedido, se o order.paid falhou na primeira tentativa.

Para não sobrescrever um estado novo com um antigo:

  • Compare data.object.updated_at com o que você já tem gravado e ignore o evento se ele for mais antigo.
  • Ou, ao receber qualquer evento de um pedido ou assinatura, trate o status do objeto como a verdade naquele momento, e não o tipo do evento.

O que fazer a seguir

Nesta página