Documentação para desenvolvedores
Webhooks & API
O Proa Pay envia eventos da escola (lead ganho, fatura paga, matrícula) para o sistema que você quiser — CRM, planilha, automação. Cada entrega é um POST JSON assinado, com re-tentativas automáticas. Conecte direto ou via Make, Pluga, Zapier e n8n.
Visão geral
O fluxo é simples: um fato acontece na escola → o Proa Pay enfileira o evento → um worker entrega via HTTPS POST ao seu endpoint, assinado. Você valida a assinatura, responde 2xx e processa. Se o seu endpoint cair, re-tentamos com backoff.
Nesta primeira versão a saída é somente de eventos (webhooks-out). Uma API de leitura (REST) e conectores nativos vêm a seguir.
Configurar um endpoint
No painel admin, em Conta → Integrações → Criar webhook: informe um nome, a URL HTTPS do seu endpoint e marque os eventos desejados. Ao salvar, enviamos um evento ping de verificação — se ele responder 2xx, o endpoint fica ativo.
Você recebe um segredo de assinatura (whsec_…) uma única vez — guarde-o com segurança; é com ele que você valida cada entrega. Pode pausar, re-verificar e ver o histórico de entregas a qualquer momento.
Formato do evento
Toda entrega tem o mesmo envelope, com os campos específicos em data:
POST https://seu-endpoint.com/webhook
Content-Type: application/json
X-AppmaxEdu-Signature: sha256=<hmac-hex>
X-AppmaxEdu-Timestamp: 1781524667000
Idempotency-Key: 3f1c…(= id do envelope)
{
"id": "3f1c2b6e-...", // único por evento — use como chave de dedupe
"event": "invoice.paid",
"api_version": "v1",
"occurred_at": "2026-06-15T13:00:00.000Z",
"tenant_id": "a03bb4a7-...", // a escola (estabelecimento)
"data": { /* payload mínimo do evento — ver catálogo */ }
}Campos fixos do envelope (iguais em todo evento):
id— ID único do envelope (UUID) — repetido no header Idempotency-Keyevent— tipo do evento (ex.: 'invoice.paid')api_version— versão do contrato de saída (ex.: 'v1')occurred_at— quando o evento ocorreu (ISO 8601, UTC)tenant_id— ID opaco do estabelecimento que originou o eventodata— objeto com os campos específicos do evento (detalhados por evento abaixo)
Cabeçalhos HTTP de cada entrega (POST application/json):
content-type— sempre application/jsonX-AppmaxEdu-Signature— sha256=<HMAC-SHA256 de "{timestamp}.{corpo}" usando o segredo do endpoint>X-AppmaxEdu-Timestamp— momento do envio (Unix ms); entra na assinatura — rejeite se diferir mais de 5 min do agoraIdempotency-Key— igual ao id do envelope — use para deduplicar reentregas de um mesmo evento
Verificar a assinatura
A assinatura é HMAC-SHA256 sobre `${timestamp}.${corpo}`, com o timestamp também no cabeçalho. Rejeite requisições fora de uma janela de 5 minutos — isso previne ataques de replay. Compare em tempo constante.
import crypto from 'node:crypto';
// Em cada request, valide assinatura + janela de 5 min ANTES de processar.
function verificar(rawBody, headers, secret) {
const sig = headers['x-appmaxedu-signature'];
const ts = Number(headers['x-appmaxedu-timestamp']);
if (!Number.isFinite(ts) || Math.abs(Date.now() - ts) > 5 * 60 * 1000) {
return false; // fora da janela → possível replay
}
const esperado =
'sha256=' +
crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
const a = Buffer.from(esperado);
const b = Buffer.from(sig ?? '');
return a.length === b.length && crypto.timingSafeEqual(a, b); // tempo constante
}Catálogo de eventos
Cada evento carrega no data apenas os campos abaixo — o mesmo contrato que você marca na tela de criação do webhook. Esta lista é gerada a partir do catálogo do sistema: quando um evento novo entra, ele aparece aqui automaticamente.
lead.wonLead ganho (compra concluída)Um lead converte — a primeira fatura do checkout é paga.
lead_id— ID opaco do leadstage— estágio do lead (sempre 'ganho')invoice_ref— ID da fatura gerada (ou null)
lead.stage_changedLead mudou de estágioO estágio do lead muda no funil (ex.: novo → em contato).
lead_id— ID opaco do leadfrom— estágio anteriorto— novo estágio
lead.offer_dispatchedOferta enviada ao leadUma oferta/link de checkout é disparada para o lead.
lead_id— ID opaco do leadchannel— canal do disparo (ex.: email/whatsapp)plan_slug— slug do produto ofertado
lead.payment_failedPagamento do lead não concluídoUm lead tenta pagar e não conclui (cartão recusado, Pix ou boleto não pago).
lead_id— ID opaco do leadreason— motivo (ex.: cartão recusado, aguardando pagamento)payment_method— método tentado (pix/cartão/boleto)plan_ref— ID do produto de interesse
invoice.paidFatura pagaUma fatura é confirmada como paga (após o re-fetch na Appmax).
invoice_id— ID opaco da faturastatus— status da fatura (ex.: 'paid')amount_cents— valor em centavos (inteiro)due_date— vencimento (YYYY-MM-DD)paid_at— data/hora do pagamento (ISO) ou nullkind— tipo (tuition/extra/agreement/down_payment)installment_number— número da parcela (ou null)installment_total— total de parcelas (ou null)enrollment_ref— ID opaco da matrículapayer_ref— ID opaco do pagador (adulto)
invoice.overdueFatura vencidaUma fatura passa do vencimento sem pagamento.
invoice_id— ID opaco da fatura
invoice.refundedFatura estornadaUma fatura paga é estornada.
invoice_id— ID opaco da faturastatus— status da fatura (ex.: 'refunded')amount_cents— valor em centavos (inteiro)due_date— vencimento (YYYY-MM-DD)paid_at— data/hora do pagamento original (ISO) ou nullkind— tipo (tuition/extra/agreement/down_payment)installment_number— número da parcela (ou null)installment_total— total de parcelas (ou null)enrollment_ref— ID opaco da matrículapayer_ref— ID opaco do pagador (adulto)
enrollment.activatedMatrícula ativadaUma matrícula sai do rascunho e passa a gerar faturas.
enrollment_id— ID opaco da matrículastatus— status (ex.: 'active')academic_period— período letivoplan_ref— ID opaco do produto/planoinvoice_refs— lista de IDs das faturas geradas
enrollment.canceledMatrícula canceladaUma matrícula é cancelada.
enrollment_id— ID opaco da matrículastatus— status (sempre 'canceled')reason— motivo do cancelamento (ou null)canceled_invoice_refs— lista de IDs das faturas canceladas
Enriquecimento opcional (dados do pagador). Em invoice.paid e invoice.refunded, o dono da escola pode ativar no endpoint o envio dos dados de contato do pagador (adulto) — mediante aceite de tratamento de dados (DPA). Quando ativo, data traz também:
payer_document— CPF do pagador (adulto), só dígitos — chave de conciliação; só quando o enriquecimento está ativo no endpointpayer_email— e-mail do pagador (adulto) — só quando o enriquecimento está ativo no endpointpayer_name— nome do pagador (adulto) — só quando o enriquecimento está ativo no endpoint
Use payer_document (CPF, só dígitos) como chave estável para casar a compra com o cadastro da sua ferramenta. Esses campos nunca incluem dados do aluno/menor.
Entregas e re-tentativas
Consideramos entregue qualquer resposta 2xx em até 10s. Em falha (timeout, 4xx/5xx), re-tentamos com backoff exponencial + jitter (até 16 tentativas, ~72h). Esgotadas as tentativas, a entrega vai para não-entregue e você pode reenviar manualmente pelo painel.
As entregas são at-least-once: o mesmo evento pode chegar mais de uma vez (ex.: você respondeu 2xx mas demorou). Deduplique pelo Idempotency-Key / id do envelope. Cada (evento, endpoint) é entregue com sucesso no máximo uma vez.
Segurança e LGPD
Por padrão os payloads são minimizados: carregam ids, valores em centavos, status e datas. Dados de contato do pagador (adulto) — CPF, e-mail e nome — só saem quando o dono da escola ativa explicitamente o enriquecimento no endpoint, com aceite de tratamento de dados (DPA). Dados pessoais de alunos menores (nome, CPF, nascimento) nunca são enviados.
Só aceitamos endpoints HTTPS com IP público (bloqueamos redes internas — proteção SSRF), validado a cada envio. Registramos cada entrega (o que saiu, para qual endpoint, quando) para atender pedidos de titular e auditoria.