Documentação para desenvolvedores
Webhooks & API
O Appmax Edu 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 Appmax Edu 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 Gestão → 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 */ }
}Cabeçalhos: X-AppmaxEdu-Signature (HMAC), X-AppmaxEdu-Timestamp (Unix ms) e Idempotency-Key (igual ao id do envelope — use para deduplicar re-entregas).
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
lead.won— Lead virou cliente (compra concluída)lead.stage_changed— Lead mudou de estágio no funillead.offer_dispatched— Oferta enviada ao leadinvoice.paid— Fatura pagainvoice.overdue— Fatura venceu sem pagamentoinvoice.refunded— Fatura estornadaenrollment.activated— Matrícula ativada (faturas geradas)enrollment.canceled— Matrícula cancelada
Exemplos do conteúdo de data por evento:
// invoice.paid / invoice.refunded
{ "invoice_id": "...", "status": "paid", "amount_cents": 150000,
"due_date": "2026-08-10", "paid_at": "2026-06-15T13:00:00.000Z",
"kind": "tuition", "installment_number": 1, "installment_total": 12,
"enrollment_ref": "...", "payer_ref": "..." }
// invoice.overdue
{ "invoice_id": "..." }
// lead.won
{ "lead_id": "...", "stage": "ganho", "invoice_ref": "..." }
// lead.stage_changed
{ "lead_id": "...", "from": "tentou", "to": "contato" }
// lead.offer_dispatched
{ "lead_id": "...", "channel": "email", "plan_slug": "curso-x" }
// enrollment.activated
{ "enrollment_id": "...", "status": "active", "academic_period": "2026",
"plan_ref": "...", "invoice_refs": ["...", "..."] }
// enrollment.canceled
{ "enrollment_id": "...", "status": "canceled", "reason": "...",
"canceled_invoice_refs": ["..."] }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
Os payloads são minimizados: carregam ids, valores em centavos, status e datas — nunca dados pessoais de alunos menores (nome, CPF, nascimento). Apenas eventos adultos/financeiros saem nesta versão.
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.