Webhooks
Conecte qualquer área de membros ao Destpay. Avisamos o seu sistema quando o aluno deve ganhar ou perder acesso — sem você precisar consultar nada.
Esta página descreve os webhooks de saída (Destpay → seu sistema).
Configurar
- No painel, vá em Integrações → Área de membros → Configurar webhook.
- Informe a URL que vai receber os avisos e escolha os eventos e produtos que interessam. Deixar em branco significa todos.
- Guarde o secret gerado. Ele aparece uma única vez e serve para você conferir que a chamada veio mesmo de nós.
- Use o botão Testar para receber um ping e validar a integração antes de ir para produção.
Enviamos um POST com corpo JSON. Se o seu sistema responder 2xx, a entrega é concluída. Qualquer outra resposta — ou timeout de 10 segundos — entra em reentrega automática.
Validar a assinatura
Todo request traz estes cabeçalhos:
| Cabeçalho | Conteúdo |
|---|---|
| x-destpay-event | Nome do evento (ex.: aluno.liberado) |
| x-destpay-timestamp | Unix timestamp, em segundos, de quando assinamos |
| x-destpay-signature | HMAC-SHA256 em hexadecimal |
| x-destpay-delivery | ID da entrega — use para idempotência e suporte |
A assinatura é o HMAC-SHA256 de timestamp + "." + corpo, usando o secret do seu endpoint como chave.
Assine o corpo cru, exatamente como recebido — não o JSON reserializado. Reserializar muda espaços e ordem de chaves, e a assinatura não bate. É o erro mais comum nesse tipo de integração.
import crypto from 'node:crypto'
function validar(req, secret) {
const ts = req.headers['x-destpay-timestamp']
const assinatura = req.headers['x-destpay-signature']
const corpoCru = req.rawBody // string, não req.body já parseado
const esperado = crypto
.createHmac('sha256', secret)
.update(`${ts}.${corpoCru}`)
.digest('hex')
// comparação em tempo constante evita vazar informação por timing
const ok = crypto.timingSafeEqual(
Buffer.from(esperado),
Buffer.from(assinatura),
)
// rejeita requisições antigas (proteção contra replay)
const recente = Math.abs(Date.now() / 1000 - Number(ts)) < 300
return ok && recente
}
$ts = $_SERVER['HTTP_X_DESTPAY_TIMESTAMP'];
$sig = $_SERVER['HTTP_X_DESTPAY_SIGNATURE'];
$body = file_get_contents('php://input');
$esperado = hash_hmac('sha256', $ts . '.' . $body, $secret);
$valido = hash_equals($esperado, $sig) && abs(time() - (int)$ts) < 300;
import hmac, hashlib, time
def validar(headers, corpo_cru: bytes, secret: str) -> bool:
ts = headers["x-destpay-timestamp"]
sig = headers["x-destpay-signature"]
esperado = hmac.new(
secret.encode(), f"{ts}.".encode() + corpo_cru, hashlib.sha256
).hexdigest()
return hmac.compare_digest(esperado, sig) and abs(time.time() - int(ts)) < 300
Formato do envelope
Todo evento chega no mesmo formato:
{
"event": "aluno.bloqueado",
"enviado_em": "2026-07-31T03:05:05.178Z",
"dados": { }
}
event— qual evento aconteceuenviado_em— quando o aviso foi montado (ISO 8601, UTC)dados— o conteúdo, que varia por evento
Ciclo do aluno
Estes são os eventos que a área de membros precisa. Todos carregam o mesmo bloco dados.
| Evento | Quando dispara | O que fazer |
|---|---|---|
| aluno.liberado | Pagou a 1ª parcela e virou cliente ativo | Liberar acesso |
| aluno.bloqueado | Uma parcela venceu e não foi paga | Bloquear acesso |
| aluno.reativado | O inadimplente regularizou | Devolver acesso |
| aluno.concluido | Pagou todas as parcelas | Manter acesso; marcar como concluído |
| aluno.cancelado | O parcelamento foi cancelado | Revogar acesso |
Exemplo de payload
{
"event": "aluno.bloqueado",
"enviado_em": "2026-07-31T03:05:05.178Z",
"dados": {
"cliente": {
"id": "e65436b7-5fc0-44cf-a9ff-a5841e3482ae",
"nome": "Ana Paula Ferreira",
"email": "ana@example.com",
"cpf": "39053344705",
"telefone": "11988887777",
"status": "inadimplente",
"status_anterior": "ativo"
},
"produto": {
"campanha_id": "38965ec9-2981-4bef-bdc9-6a513a77fab4",
"campanha": "Turma Webhook",
"nome": "Mentoria Premium"
},
"empresa_id": "c7c4ca4b-e184-4a2f-a557-e5ccdf9f69c2"
}
}
Como identificar o aluno: use cliente.email ou cliente.cpf. O cliente.id é estável e único no Destpay — se puder guardá-lo do seu lado, é a chave mais segura.
Como saber qual produto liberar: use produto.campanha_id (estável) ou produto.nome.
Status do cliente
| Status | Significado |
|---|---|
| iniciado | Começou o checkout, não concluiu |
| pendente_assinatura | Falta assinar o contrato |
| pendente_pagamento | Assinou, aguardando a 1ª parcela |
| ativo | Pagou a 1ª parcela — tem acesso |
| inadimplente | Tem parcela vencida — sem acesso |
| quitado | Pagou tudo |
| cancelado | Parcelamento cancelado |
Regra de negócio do Destpay: o aluno só vira cliente ativo quando a 1ª parcela é paga. Antes disso ele existe no sistema, mas não deve ter acesso.
Ping de teste
Disparado pelo botão Testar do painel. Serve para validar URL e assinatura antes de ir para produção.
{
"event": "ping",
"enviado_em": "2026-07-31T03:00:00.000Z",
"dados": { "mensagem": "Teste de configuracao do webhook Destpay." }
}
Reentrega
Se a sua URL não responder 2xx — ou passar de 10 segundos — a entrega volta para a fila.
| Tentativa | Espera até a próxima |
|---|---|
| 1ª | 1 minuto |
| 2ª | 5 minutos |
| 3ª | 15 minutos |
| 4ª | 1 hora |
| 5ª | 3 horas |
| 6ª | 6 horas |
Depois da 6ª tentativa a entrega é marcada como falhou e fica no painel para reenvio manual.
Boas práticas
Responda rápido
Devolva 200 assim que receber e processe depois. O timeout é de 10 segundos; se estourar, tratamos como falha e reenviamos.
Seja idempotente
Uma reentrega pode chegar depois de você já ter processado — por exemplo, se a sua resposta se perdeu no caminho. Use x-destpay-delivery para ignorar duplicatas.
Não confie na ordem
Com rede instável, um aluno.bloqueado reentregue pode chegar depois de um aluno.reativado. Compare enviado_em ou confie no campo cliente.status, que sempre reflete o estado no momento do envio.
Trate evento desconhecido
Podemos acrescentar eventos novos. Ignore o que não conhecer e responda 200 — devolver erro só gera reentrega desnecessária.
Acompanhar envios
No painel, em Integrações → Área de membros, cada envio aparece com evento, horário, código HTTP e número de tentativas. Falhas mostram o erro e podem ser reenviadas manualmente.