Catálogo de eventos
Os 20 tipos de evento que o Vipter envia por webhook, quando cada um dispara e o que vem em data.object, com um exemplo completo de pedido, assinatura, cliente e checkout abandonado.
Todo evento chega no mesmo envelope. O tipo está em type e no cabeçalho Vipter-Event-Type, e o objeto em data.object. Cada tipo pertence a uma família, e a família define o formato do objeto:
| Família | Tipos | data.object.object |
|---|---|---|
| Pedidos | order.* (5) | "order" |
| Assinaturas | subscription.* (11) | "subscription" |
| Clientes | customer.* (2) | "customer" |
| Checkout abandonado | checkout.* (2) | "checkout_abandonment" |
Regras que valem para todas as famílias:
- Todos os campos listados nas tabelas vêm sempre no objeto. Quando não há valor, o campo vem
null, nunca ausente. A exceção é o evento de teste. - Valores em dinheiro vêm em centavos, como número inteiro:
19700é R$ 197,00. A moeda está no campocurrencydo mesmo objeto. - Datas dentro de
data.objectsão texto ISO 8601. Ocreateddo envelope é outro formato: segundos Unix. - Os IDs dos exemplos são fictícios. Trate todo ID como texto opaco e não dependa do prefixo nem do tamanho.
- Um endpoint recebe só os tipos marcados nele. Sem nenhum marcado, recebe todos, inclusive os tipos criados no futuro. Ignore com 2xx os tipos que o seu sistema não usa.
Pedidos
| Evento | Quando é enviado |
|---|---|
order.paid | O pagamento de um pedido foi aprovado: compra no checkout (cartão aprovado ou PIX pago), renovação de assinatura, upsell de um clique, venda no cartão salvo feita pelo painel, cobrança extra numa assinatura, ou pedido marcado como pago pela equipe. |
order.failed | A cobrança de um pedido foi recusada. Sai uma vez por pedido: novas recusas no mesmo pedido não geram outro evento. |
order.refunded | O pedido foi reembolsado por inteiro, pelo painel, pelo provedor ou marcado como reembolsado pela equipe. |
order.partially_refunded | Parte do pedido foi reembolsada. Pode chegar mais de uma vez para o mesmo pedido, uma para cada reembolso parcial. |
order.charged_back | O comprador contestou a compra no banco do cartão (chargeback). |
Detalhes que o código garante:
- Renovações chegam como
order.paidcomrecurrence: "subsequent"esubscription_idpreenchido, além dosubscription.renewedda assinatura. - Status manual. Quando alguém da equipe marca o pedido como pago ou reembolsado, o evento sai com
status_source: "manual". Depois disso, mudanças que o provedor informar sobre esse pedido não geram eventos. Veja status manual. - O status do objeto é o atual. Um pedido que o Vipter só conhece depois, pela sincronização periódica, pode gerar
order.paidjá com outrostatus, comorefunded. Leiastatusem vez de deduzir pelo tipo do evento. - O pedido não traz UTMs, origem da campanha nem vendedor. Esses dados ficam no painel.
O objeto order
| Campo | Tipo | Conteúdo |
|---|---|---|
object | texto | Sempre "order". |
id | texto | ID do pedido. |
customer_id | texto ou null | ID do cliente. |
customer_email | texto ou null | E-mail do comprador. |
subscription_id | texto ou null | Assinatura que gerou o pedido, nas renovações e cobranças extras. |
status | texto | pending, pre_authorized, authorized, failed, canceled, refund_pending, partially_refunded, refunded ou charged_back. Veja status de pedido. |
total_amount | inteiro | Total cobrado, em centavos. |
currency | texto | Código ISO 4217, como BRL. |
refunded_amount | inteiro ou null | Total já devolvido, em centavos. |
order_type | texto ou null | checkout, renewal, api, trial_setup ou card_setup. |
recurrence | texto ou null | none (compra avulsa), initial (primeira cobrança de uma assinatura), subsequent (renovação) ou unscheduled. |
offer_id | texto ou null | Oferta do primeiro item. |
payment_method | texto ou null | credit_card, debit_card, pix, boleto ou wallet. |
provider_slug | texto ou null | Provedor que processou o pagamento, como pagarme. |
paid_at | data ou null | Quando o pagamento foi aprovado. |
items | lista | Os itens do pedido. Veja abaixo. |
external_order_id | texto ou null | Referência externa do pedido, quando existe. |
status_source | texto | manual quando a equipe definiu o status no painel, provider nos outros casos. |
created_at, updated_at | data ou null | Criação e última alteração do pedido. |
downloads | lista | Só em order.paid que não é renovação. Os links de download do comprador. Lista vazia quando o pedido não tem produto com arquivos. |
Cada item de items traz estes campos. Trate campos a mais como opcionais:
| Campo | Tipo | Conteúdo |
|---|---|---|
offer_id, offer_name | texto ou null | Oferta vendida. |
product_id, product_name | texto ou null | Produto da oferta. |
billing_cycle | texto ou null | Ciclo da oferta. none para venda avulsa. |
quantity | inteiro | Unidades. Num pacote de 3, vem 3. |
unit_amount, total_amount | inteiro | Preço por unidade e total da linha, em centavos. |
currency | texto | Moeda da linha. |
installments | inteiro ou null | Número de parcelas. |
role | texto | Quando existe: main para o produto principal, bump para um order bump. Um item sem role é o produto principal. |
pack_label | texto | Quando existe: o nome do pacote vendido. |
bump_id | texto | Quando existe: o order bump que gerou a linha. |
Cada entrada de downloads traz product_id, product_name, expires_at (data ou null) e files, uma lista de { "name", "url" }. Os links abrem no domínio do checkout da loja e deixam de funcionar depois de um reembolso ou chargeback. Veja arquivos para download.
Exemplo: 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",
"customer_id": "cus_8b2d4f6a1c3e5a7b9d0f2e4c",
"customer_email": "ana.souza@example.com",
"subscription_id": null,
"status": "authorized",
"total_amount": 19700,
"currency": "BRL",
"refunded_amount": null,
"order_type": "checkout",
"recurrence": "none",
"offer_id": "ofr_a3454b7c008d455fbc5c3fc436c1879d",
"payment_method": "credit_card",
"provider_slug": "pagarme",
"paid_at": "2026-09-28T14:03:09.000Z",
"items": [
{
"offer_id": "ofr_a3454b7c008d455fbc5c3fc436c1879d",
"offer_name": "Acesso vitalício",
"product_id": "prd_5df6381e9a0b4c2d8e7f6a5b4c3d2e1f",
"product_name": "Curso de Fotografia",
"billing_cycle": "none",
"quantity": 1,
"unit_amount": 19700,
"total_amount": 19700,
"currency": "BRL",
"installments": 1
}
],
"external_order_id": null,
"status_source": "provider",
"created_at": "2026-09-28T14:02:51.000Z",
"updated_at": "2026-09-28T14:03:09.000Z",
"downloads": [
{
"product_id": "prd_5df6381e9a0b4c2d8e7f6a5b4c3d2e1f",
"product_name": "Curso de Fotografia",
"expires_at": null,
"files": [
{
"name": "Apostila.pdf",
"url": "https://pay.vipter.com/d/EXEMPLO-TOKEN/0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a"
}
]
}
]
}
}
}Assinaturas
| Evento | Quando é enviado |
|---|---|
subscription.created | Uma assinatura foi criada, normalmente pela compra de uma oferta recorrente no checkout. |
subscription.renewed | A assinatura foi renovada. A cobrança da renovação chega em separado, como order.paid. |
subscription.dunning | A cobrança da renovação falhou e a assinatura entrou em recuperação (status: "dunning"). |
subscription.reactivated | A assinatura voltou a ficar ativa: saiu da recuperação de cobrança, ou foi reativada pela equipe ou pelo assinante. |
subscription.upgraded | O assinante mudou de plano, para um valor maior ou igual ao anterior. |
subscription.downgraded | O assinante mudou de plano, para um valor menor que o anterior. |
subscription.payment_method_changed | O cartão usado nas cobranças da assinatura foi trocado. |
subscription.paused | A assinatura foi pausada. |
subscription.resumed | A assinatura pausada voltou a ficar ativa. |
subscription.cancelled | A assinatura foi cancelada. |
subscription.expired | A assinatura terminou (status: "expired"). |
Detalhes que o código garante:
- Mudanças feitas pela equipe no painel (cancelar, pausar, retomar, reativar, trocar de plano) e pelo assinante na área do cliente (cancelar, reativar, trocar de plano) geram o evento na hora. O aviso do provedor sobre a mesma mudança pode gerar outro evento do mesmo tipo, com outro
id. Veja idempotência. - Agendar o cancelamento para o fim do período não gera evento no momento do agendamento. O objeto passa a ter
cancel_at_period_end: truee aparece no próximo evento da assinatura. - Nas trocas de plano pelo painel e pela área do cliente, o Vipter compara
current_amountantes e depois: maior ou igual virasubscription.upgraded, menor virasubscription.downgraded.
O objeto subscription
| Campo | Tipo | Conteúdo |
|---|---|---|
object | texto | Sempre "subscription". |
id | texto | ID da assinatura. |
customer_id, customer_email, customer_name | texto ou null | O assinante. |
status | texto | trialing, active, dunning, paused, cancelled ou expired. |
current_offer_id, offer_name | texto ou null | Plano atual. Muda numa troca de plano. |
product_id, product_name | texto ou null | Produto do plano. |
billing_cycle | texto ou null | daily, biweekly, monthly, quarterly, half_yearly, yearly ou custom. |
currency | texto ou null | Moeda das cobranças. |
current_amount | inteiro ou null | Valor de cada cobrança, em centavos. |
current_period_start, current_period_end | data ou null | Período pago atual. |
next_billing_at | data ou null | Próxima cobrança. |
trial_start, trial_end | data ou null | Período de teste grátis, quando houve. |
cycles_completed | inteiro ou null | Ciclos já cobrados. |
cycle_limit | inteiro ou null | Número máximo de ciclos, ou null se não há limite. |
cancel_at_period_end | booleano ou null | true quando o cancelamento está agendado para o fim do período. |
cancelled_at | data ou null | Quando a assinatura foi cancelada. |
cancellation_reason | texto ou null | Motivo informado no cancelamento. |
payment_instrument_id | texto ou null | ID do cartão salvo usado nas cobranças. |
created_at, updated_at | data ou null | Criação e última alteração da assinatura. |
Exemplo: subscription.renewed
{
"id": "evt_7d0b2e4f6a8c1e3b5d7f9a0c",
"object": "event",
"type": "subscription.renewed",
"created": 1790611502,
"livemode": true,
"api_version": "2026-09-01",
"data": {
"object": {
"object": "subscription",
"id": "sub_23e6db9f0a1b4c5d8e7f6a5b4c3d2e1f",
"customer_id": "cus_8b2d4f6a1c3e5a7b9d0f2e4c",
"customer_email": "ana.souza@example.com",
"customer_name": "Ana Souza",
"status": "active",
"current_offer_id": "ofr_0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f",
"offer_name": "Plano mensal",
"product_id": "prd_1a2b3c4d5e6f4a7b8c9d0e1f2a3b4c5d",
"product_name": "Clube de Receitas",
"billing_cycle": "monthly",
"currency": "BRL",
"current_amount": 4990,
"current_period_start": "2026-09-28T16:05:00.000Z",
"current_period_end": "2026-10-28T16:05:00.000Z",
"next_billing_at": "2026-10-28T16:05:00.000Z",
"trial_start": null,
"trial_end": null,
"cycles_completed": 4,
"cycle_limit": null,
"cancel_at_period_end": false,
"cancelled_at": null,
"cancellation_reason": null,
"payment_instrument_id": "pi_4e6a8c0b2d4f6a8c0e2b4d6f",
"created_at": "2026-05-28T16:05:00.000Z",
"updated_at": "2026-09-28T16:05:02.000Z"
}
}
}Clientes
| Evento | Quando é enviado |
|---|---|
customer.created | O Vipter registrou um cliente novo: cadastrado pela equipe no painel, ou visto pela primeira vez numa assinatura ou na sincronização periódica com o provedor. |
customer.updated | Alguém da equipe editou o cliente no painel. Cada vez que o formulário é salvo, sai um evento. |
Não conte com customer.created para saber de cada comprador novo: ele não sai em todos os caminhos de compra. Para reagir a uma compra, use order.paid, que traz customer_id e customer_email. Mudanças que o comprador faz na área do cliente, como nome e telefone, não geram customer.updated.
O objeto customer
| Campo | Tipo | Conteúdo |
|---|---|---|
object | texto | Sempre "customer". |
id | texto | ID do cliente. |
email | texto | E-mail. |
name | texto ou null | Nome. |
phone | texto ou null | Telefone, como +5511987654321. |
document_type | texto ou null | cpf, cnpj, passport ou tax_id. O número do documento não vem no evento. |
metadata | objeto ou null | Metadados do cliente. |
created_at, updated_at | data ou null | Criação e última alteração. |
Exemplo: customer.created
{
"id": "evt_1c3e5a7b9d0f2e4c6a8b0d2f",
"object": "event",
"type": "customer.created",
"created": 1790604190,
"livemode": true,
"api_version": "2026-09-01",
"data": {
"object": {
"object": "customer",
"id": "cus_8b2d4f6a1c3e5a7b9d0f2e4c",
"email": "ana.souza@example.com",
"name": "Ana Souza",
"phone": "+5511987654321",
"document_type": "cpf",
"metadata": null,
"created_at": "2026-09-28T14:02:50.000Z",
"updated_at": "2026-09-28T14:02:50.000Z"
}
}
}O evento de teste
O botão Enviar evento de teste cria um customer.created com um objeto reduzido. Ele tem só estes campos e "test": true:
{
"object": "customer",
"id": "cust_test",
"email": "test@example.com",
"name": "Test Customer",
"test": true,
"created_at": "2026-09-28T14:10:00.000Z"
}Descarte eventos com data.object.test === true antes de gravar qualquer coisa. Cada clique cria um evento novo, com outro id. Veja Tentativas, desativação e reenvio.
Checkout abandonado
| Evento | Quando é enviado |
|---|---|
checkout.abandoned | O comprador preencheu o e-mail no checkout, não tentou pagar e ficou sem atividade. O registro nasce depois de 15 minutos parado, e o evento sai 60 minutos depois do registro, se ele não comprou nesse meio-tempo. A verificação roda a cada 10 minutos, então o horário real varia. Sai uma vez por registro. |
checkout.recovered | Um checkout abandonado cujo checkout.abandoned já tinha saído terminou em compra paga do mesmo comprador e do mesmo produto, até 7 dias depois do abandono. |
Um cartão recusado e um PIX gerado e não pago não contam como abandono. Várias visitas do mesmo comprador ao mesmo produto viram um registro só, com session_count maior que 1. As regras completas estão em Recuperação de checkout abandonado.
O objeto checkout_abandonment
| Campo | Tipo | Conteúdo |
|---|---|---|
object | texto | Sempre "checkout_abandonment". |
id | texto | ID do registro de abandono. É o mesmo nos dois eventos. |
customer | objeto | id (null se o comprador ainda não é cliente), email, name, phone e country. |
offer_id, offer_name | texto ou null | Oferta do checkout. |
product_id, product_name | texto ou null | Produto da oferta. |
quantity | inteiro | Unidades: o tamanho do pacote, ou 1. |
pack_label | texto ou null | Nome do pacote, quando o link era de um pacote. |
amount | inteiro ou null | Valor do produto que o comprador viu, com o preço do pacote, antes de cupons e frete. Em centavos. |
currency | texto ou null | Moeda do checkout. |
locale | texto ou null | Idioma em que o checkout estava, como pt. |
utm | objeto ou null | Os parâmetros utm_source, utm_medium, utm_campaign, utm_content, utm_term e utm_id que vieram com o comprador. |
referrer | texto ou null | Página de onde o comprador chegou. |
checkout_session_id | texto | Sessão de checkout mais recente. |
session_count | inteiro | Quantas visitas foram juntadas neste registro. |
recovery_url | texto | Link que reabre o checkout com os dados do comprador preenchidos. Veja link de recuperação. |
first_seen_at | data | Início da primeira visita. |
abandoned_at | data | Quando o abandono foi registrado. |
checkout.recovered traz o mesmo objeto e mais quatro campos:
| Campo | Tipo | Conteúdo |
|---|---|---|
resolution | texto | Sempre "recovered". |
order_id | texto | O pedido pago que fechou o abandono. |
resolved_at | data | Quando o abandono foi fechado. |
recovered_by_link | booleano | true se o comprador abriu o recovery_url antes de comprar. |
Exemplo: checkout.abandoned
{
"id": "evt_9e1a3c5e7b9d0f2a4c6e8b0d",
"object": "event",
"type": "checkout.abandoned",
"created": 1790609400,
"livemode": true,
"api_version": "2026-09-01",
"data": {
"object": {
"object": "checkout_abandonment",
"id": "6f1d2c3b-4a5e-4f6a-9b8c-7d6e5f4a3b2c",
"customer": {
"id": null,
"email": "bruno.lima@example.com",
"name": "Bruno Lima",
"phone": "+5521998765432",
"country": "BR"
},
"offer_id": "ofr_7b8c9d0e1f2a4b3c8d7e6f5a4b3c2d1e",
"offer_name": "Kit 3 unidades",
"product_id": "prd_9f8e7d6c5b4a4f3e8d2c1b0a9f8e7d6c",
"product_name": "Chá Detox",
"quantity": 3,
"pack_label": "Kit com 3",
"amount": 24900,
"currency": "BRL",
"locale": "pt",
"utm": {
"utm_source": "instagram",
"utm_medium": "stories",
"utm_campaign": "black-friday"
},
"referrer": "https://l.instagram.com/",
"checkout_session_id": "cs_2b4d6f8a0c2e4a6b8d0f2a4c",
"session_count": 2,
"recovery_url": "https://pay.vipter.com/kit-cha?pack=3&rec=EXEMPLO-TOKEN",
"first_seen_at": "2026-09-28T13:12:40.000Z",
"abandoned_at": "2026-09-28T13:40:05.000Z"
}
}
}O que fazer a seguir
- Entenda os campos do envelope e como tratar repetições.
- Verifique a assinatura antes de processar qualquer evento.
Visão geral para desenvolvedores
O que dá para integrar com o Vipter hoje (webhooks assinados, parâmetros de URL do checkout, script de UTMs e esta documentação em Markdown), o que não existe e por onde começar.
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.