Webhooks
Receba em tempo real os eventos das suas vendas no PrincipiaPay, com a lista de eventos, o payload e as regras de reenvio.
Webhooks notificam o seu sistema, em tempo real, sobre o que acontece com cada venda: carrinho abandonado, pagamento gerado, compra confirmada, cancelamento e outros. Com eles você automatiza réguas de recuperação, liberação de acesso e atualização do seu cadastro.
Configurar
Você pode configurar pelo painel ou pela API. Dá para ter mais de uma configuração, cada uma com a sua URL e os seus eventos.
Pelo painel
Entre no painel do parceiro com perfil Admin ou Superadmin e abra Configurações > Integrações > Webhooks.
Clique em Criar webhook e preencha: nome da configuração, URL para envio, token de autorização (opcional) e os eventos desejados.
Salve. Na tela de confirmação, use Teste de configuração > Enviar teste para disparar um envio de cada evento selecionado, com dados fictícios.
Na lista de configurações você busca pelo nome, ativa ou inativa, edita ou exclui cada uma.
Pela API
| Ação | Rota |
|---|---|
| Criar | POST /webhooks |
| Listar | GET /webhooks |
| Alterar ou inativar | PATCH /webhooks/{id} |
| Excluir | DELETE /webhooks/{id} |
| Testar | POST /webhooks/test/{id} |
{
"webhookUrl": "https://suaempresa.com.br/suaurlretorno",
"enabledEvents": [
{ "name": "purchaseConfirmed" },
{ "name": "purchaseCancelled" },
{ "name": "invoiceCreated" }
],
"configurationName": "Webhook - Integração",
"authorizationToken": "seu_token_secreto"
}configurationName, webhookUrl e enabledEvents são obrigatórios; authorizationToken é opcional. Para receber todos os eventos, envie "enabledEvents": [{ "name": "all" }].
Não cadastre a mesma URL duas vezes
Cada POST /webhooks cria uma configuração nova, mesmo que a URL já esteja cadastrada. Com duas configurações ativas para a mesma URL e o mesmo evento, você recebe esse evento duas vezes. Antes de criar, consulte GET /webhooks; para mudar eventos, token ou reativar, use PATCH /webhooks/{id}.
O teste (POST /webhooks/test/{id}) só funciona com uma configuração ativa e com eventos habilitados.
Como os eventos chegam
Todo evento é enviado com POST e corpo JSON, com estes headers:
Content-Type: application/json
authorization: seu_token_secretoO header authorization leva o authorizationToken da configuração, exatamente como você cadastrou, e só é enviado quando a configuração tem um token. Não há assinatura (HMAC) do corpo: cadastre um token longo e aleatório e valide esse valor no seu endpoint para garantir que o envio veio do PrincipiaPay.
Eventos
| Evento | Nome no payload | Quando é enviado |
|---|---|---|
| Carrinho abandonado | cartAbandonment | O comprador parou no checkout sem finalizar a compra. |
| Aguardando pagamento | invoiceCreated | Foi gerado um Pix, um boleto à vista ou a fatura de entrada do financiamento. |
| Pagamento expirado | invoiceExpired | O Pix ou o boleto à vista venceu sem pagamento. |
| Pagamento recusado | paymentDeclined | Uma tentativa de pagamento no cartão de crédito foi recusada. |
| Financiamento negado | financingDenied | O financiamento (boleto parcelado) foi negado por crédito ou risco de fraude. |
| Avalista necessário | guarantorNeeded | O avalista precisa fazer o aceite e assinar o contrato. |
| Compra confirmada | purchaseConfirmed | A compra foi efetivada: houve um pagamento reconhecido. |
| Compra cancelada | purchaseCancelled | A compra foi cancelada depois de confirmada, inclusive por estorno ou contestação (chargeback) do cartão. |
Só pagamentos do checkout
invoiceCreated, invoiceExpired e paymentDeclined valem só para pagamentos do checkout (boleto e Pix à vista, ou a entrada do financiamento). As parcelas do financiamento não geram esses eventos.
Detalhes de cada evento
Carrinho abandonado (cartAbandonment). Chega depois que o comprador fica pelo menos 30 minutos sem interagir com o checkout, e só se ele tiver preenchido telefone ou e-mail. É enviado no máximo uma vez por venda, só para vendas com atividade nos últimos 90 minutos, e só enquanto o comprador segue pelo boleto parcelado (financiamento) ou ainda não escolheu a forma de pagamento. Não é enviado quando o comprador:
- gerou um boleto, um Pix ou a fatura de entrada do financiamento;
- tentou pagar no cartão sem sucesso;
- indicou um avalista que ainda não começou o aceite;
- teve o financiamento negado;
- ou o avalista depende de análise manual de crédito ou risco.
Aguardando pagamento (invoiceCreated). Enviado quando o comprador gera o QR Code do Pix, gera o boleto à vista, ou é aprovado no boleto parcelado e chega à etapa de pagamento da entrada.
Pagamento expirado (invoiceExpired). O Pix ou o boleto à vista não foi pago até o vencimento. O comprador pode gerar um novo pagamento ou escolher outra forma.
Pagamento recusado (paymentDeclined). O pagamento no cartão não foi aprovado. É enviado a cada tentativa recusada; o comprador pode tentar de novo ou escolher outra forma.
Financiamento negado (financingDenied). O boleto parcelado foi negado por risco de crédito ou de fraude. Se houver outra forma disponível, o comprador pode escolhê-la.
Avalista necessário (guarantorNeeded). No boleto parcelado com avalista exigido, o comprador indicou o avalista e o CPF foi aprovado para o crédito. Enquanto o avalista não começar o fluxo dele, não há evento de carrinho abandonado.
Compra confirmada (purchaseConfirmed). O comprador pagou o boleto à vista, o Pix, o cartão de crédito ou a entrada do financiamento.
Compra cancelada (purchaseCancelled). O comprador ou o parceiro pediu o cancelamento e o pedido foi processado, ou um pagamento no cartão foi estornado ou contestado pelo comprador junto ao banco (chargeback).
financingDenied, guarantorNeeded, purchaseConfirmed e purchaseCancelled são gerados no máximo uma vez por venda. Os demais podem se repetir (por exemplo, paymentDeclined a cada tentativa recusada).
Payload
Propriedades
| Propriedade | Tipo | Descrição |
|---|---|---|
event | texto | Nome do evento (ex.: cartAbandonment). |
buyer | objeto | Dados do comprador. |
buyer.name | texto | Nome. |
buyer.email | texto | E-mail. |
buyer.phone | texto | Telefone com DDD, sem DDI. |
buyer.personalDocument | texto | Número do documento. |
buyer.personalDocumentType | texto | Tipo do documento (hoje, só CPF). |
buyer.address | objeto | Endereço: city, state (UF), number, street, zipCode, district, complement. |
checkout | objeto | Dados da venda. |
checkout.price | texto | Valor total da venda. |
checkout.checkoutUrl | texto | URL para o comprador concluir a compra. |
checkout.saleId | número | ID da venda no PrincipiaPay. |
checkout.seller | texto | E-mail do vendedor vinculado à venda. |
checkout.createdAt | data e hora | Criação da venda, no horário de Brasília (veja Datas). |
checkout.updatedAt | data e hora | Última atualização, no horário de Brasília. |
checkout.canceledAt | data e hora | Cancelamento, no horário de Brasília. |
checkout.madeEffectiveAt | data e hora | Efetivação, no horário de Brasília. |
checkout.paymentMethods | lista | Formas de pagamento oferecidas: bankSlip (boleto à vista), pix (Pix à vista), creditCard (cartão), creditAsAService (crédito educacional dinâmico), antecipatedFinancing (crédito educacional antecipado). |
checkout.products | lista | Produtos da venda: productId, productSku, productName, variantId, variantSku, variantName, variantPrice. No painel, produto é Curso e variação é Turma. Hoje a lista traz um item, mesmo em vendas com mais de um produto: para saber tudo o que foi vendido, use o saleId para chegar à venda no seu sistema. |
checkout.financingDetails | objeto | Só no boleto parcelado (financiamento). |
checkout.financingDetails.currentStep | texto ou null | Etapa atual. Veja os valores em Etapas do financiamento. |
checkout.financingDetails.deniedReason | texto ou null | Motivo da negativa do financiamento. |
payment | objeto | Dados do pagamento. |
payment.paymentMethod | texto | Forma de pagamento escolhida. |
payment.url | texto | URL para pagar. |
payment.dueDate | texto | Vencimento. |
payment.digitableLine | texto | Linha digitável do boleto. |
payment.pix.pixQrCode | texto | URL do QR Code do Pix. |
payment.pix.pixQrCodeText | texto | Pix "copia e cola". |
payment.creditCard.cardBrand | texto | Bandeira do cartão, quando disponível. |
payment.creditCard.lastFourDigits | texto | Últimos 4 dígitos, quando disponível. |
payment.creditCard.numberOfInstallments | número | Número de parcelas. |
payment.declinedReason | texto | Motivo da recusa no cartão. |
payment.financing.IOF | texto | IOF do contrato. |
payment.financing.pmt | texto | Valor base da parcela. |
payment.financing.takenAmount | texto | Valor total financiado (sem a entrada, com o IOF diluído nas parcelas). |
payment.financing.upfrontAmount | texto | Valor da entrada, com a taxa de cadastro. |
payment.financing.monthlyInterest | texto | Juros mensal, em percentual. |
payment.financing.userRegistrationFee | texto | Taxa de cadastro. |
payment.financing.numberOfInstallments | número | Número de parcelas do financiamento. |
guarantor | objeto | Dados do avalista: name, email, phone, personalDocument, personalDocumentType e address (mesmos campos do comprador). |
Quando cada objeto vem
| Objeto | Em quais eventos |
|---|---|
payment | Aguardando pagamento, Pagamento expirado, Pagamento recusado, Compra confirmada e Compra cancelada. Pode vir null quando não há pagamento associado. Não vem em Carrinho abandonado, Financiamento negado nem Avalista necessário. |
payment.financing | Compra confirmada e Compra cancelada, quando a venda é pelo boleto parcelado (financiamento). |
guarantor | A chave vem em todos os eventos, menos em Pagamento recusado. Fica null quando não há avalista. |
checkout.financingDetails | Todos os eventos de vendas pelo boleto parcelado (financiamento). currentStep e deniedReason podem vir null. |
Etapas do financiamento
Valores possíveis de checkout.financingDetails.currentStep. Compare sem diferenciar maiúsculas de minúsculas, porque a mesma etapa pode chegar com grafias diferentes:
| Valor | Etapa |
|---|---|
Informações básicas do aluno | Dados pessoais do aluno. |
Indicação do avalista | O aluno precisa indicar um avalista. |
Documentos do aluno | Documentos do aluno. |
Documentos do avalista ou Documentos do Avalista | Documentos do avalista. |
Assinatura do contrato | Assinatura do contrato. |
Pagamento da entrada | Pagamento da entrada. |
null | Sem etapa definida para o evento (por exemplo, em cancelamentos). |
Trate valores fora desta lista sem quebrar.
Datas
As datas de checkout (createdAt, updatedAt, canceledAt, madeEffectiveAt) vêm no formato ISO 8601 com o sufixo Z, mas o valor está no horário de Brasília (UTC-3), não em UTC. Por exemplo, "2025-01-01T21:53:04.230Z" significa 21:53 em Brasília (00:53 UTC do dia seguinte). Para converter para UTC, some 3 horas; não converta como se fosse UTC.
Exemplo
{
"event": "purchaseConfirmed",
"buyer": {
"name": "JOHN DOE",
"email": "johndoe@gmail.com",
"phone": "11999999999",
"address": {
"city": "São Paulo",
"state": "SP",
"number": "1855",
"street": "Av. Dr. Cardoso de Melo",
"zipCode": "04548005",
"district": "Vila Olimpia",
"complement": "11º andar"
},
"personalDocument": "12345678900",
"personalDocumentType": "CPF"
},
"checkout": {
"price": "1999.00",
"seller": null,
"products": [
{
"productId": 1234,
"productSku": "01946620-fba3-74c7-8473-38337b3f08b1",
"productName": "Light Saber 101",
"variantId": 3456,
"variantSku": "01946621-1706-7cc4-8e7e-67dbd3d9ab6e",
"variantName": "Light Saber 101 - Lançamento 1",
"variantPrice": "1999.00"
}
],
"createdAt": "2025-01-01T21:53:04.230Z",
"updatedAt": "2025-01-01T21:56:43.045Z",
"canceledAt": null,
"saleId": 1582131,
"checkoutUrl": "https://pay.principia.net/checkout/parceiro",
"paymentMethods": ["bankSlip", "creditCard", "pix", "creditAsAService", "antecipatedFinancing"],
"madeEffectiveAt": null,
"financingDetails": { "currentStep": "Pagamento da entrada", "deniedReason": null }
},
"guarantor": null,
"payment": {
"pix": {
"pixQrCode": "https://pay.principia.net/fatura/52026bce-9f97-4c39-83f9-6bffea600303-08cc/qr_code",
"pixQrCodeText": "00020126360014BR.GOV.BCB.PIX0114999999999999995204000053039865407199900"
},
"url": "https://pay.principia.net/fatura/52026bce-9f97-4c39-83f9-6bffea600303-08cc",
"dueDate": "2025-01-05",
"digitableLine": "00000000000000000000000000000000000000000000000",
"paymentMethod": "antecipatedFinancing",
"financing": {
"IOF": "35.36",
"pmt": "194.77",
"takenAmount": "1834.45",
"upfrontAmount": "219.89",
"monthlyInterest": "3.99",
"userRegistrationFee": "19.99",
"numberOfInstallments": 12
}
}
}Reenvio
O primeiro envio sai cerca de 15 segundos depois do evento. Um envio conta como sucesso quando a sua URL responde com um status 2XX (ex.: 200 OK). São 4 tentativas no total: o envio original e mais 3 reenvios.
| Tentativa | Quando |
|---|---|
| 1ª (original) | Cerca de 15 segundos depois do evento |
| 2ª | 2 minutos depois da falha da 1ª |
| 3ª | 5 minutos depois da falha da 2ª |
| 4ª | 15 minutos depois da falha da 3ª |
Depois da quarta tentativa sem sucesso, o evento não é mais enviado. O histórico de envios é guardado, mas ainda não dá para consultá-lo pelo painel nem pela API.
Boas práticas
- Valide o header
authorizationem todo envio. - Responda 2XX rápido e processe o evento depois (em fila, por exemplo), para não estourar o tempo e cair no reenvio.
- Processe os eventos de forma idempotente: por causa do reenvio (ou de duas configurações com a mesma URL), o mesmo evento pode chegar mais de uma vez, e receber o mesmo
purchaseConfirmedduas vezes não pode, por exemplo, liberar o acesso duas vezes. Lembre quepaymentDeclinedchega uma vez por tentativa recusada. - Trate as datas como horário de Brasília (veja Datas).
- Guarde os eventos recebidos no seu lado, para auditoria.
Webhooks legado
Se a sua conta também tem configurações do sistema antigo (rotas /webhook/..., versões 1.0 e 2.0) ou vendas criadas com notification_url, esses envios continuam acontecendo em paralelo aos webhooks descritos nesta página. Com os dois sistemas configurados, você recebe os dois formatos para a mesma venda. Ao migrar, inative as configurações antigas.