Como configurar webhooks na Área de Membros / Plataforma
Os webhooks permitem que sistemas externos recebam notificações em tempo real sobre eventos importantes da área de membros, como conclusão de aulas, publicação de conteúdo, emissão de certificados, inatividade de usuários, aprovação ou reprovação em avaliações.
Acesse a documentação completa em - Webhook - Área de Membros
Visão Geral
A plataforma TheMembers envia requisições HTTP POST para os endpoints de webhook configurados pelo cliente sempre que um evento ocorre.
Características principais:
- Protocolo: HTTP POST
- Formato: JSON
- Autenticação: HMAC-SHA256
- Timeout: 30 segundos
- Tentativas: até 3 em caso de falha
- Intervalo entre tentativas: 30s, 60s e 120s
PASSO 1.
Para realizar o acesso ao Painel no Dashboard vá em Plataformas - Configurações - Webhook

- Após isso clique no botão de **Criar Webhook **para realizar a criação das configurações


Autenticação e Segurança
Todas as requisições de webhook incluem um mecanismo de autenticação baseado em HMAC-SHA256, garantindo a integridade e a autenticidade do payload recebido.
Cabeçalhos enviados:
X-Webhook-Signature: assinatura HMAC-SHA256 do corpo da requisiçãoX-Webhook-Event: nome do evento disparado
A assinatura é gerada a partir do corpo bruto do JSON, utilizando o client_token do cliente como chave secreta.
Como validar a assinatura
- Obtenha o corpo bruto da requisição (JSON sem qualquer modificação).
- Calcule o HMAC-SHA256 utilizando o
client_tokencomo chave. - Gere o hash em formato hexadecimal.
- Compare o resultado com o valor enviado no cabeçalho
X-Webhook-Signature.
⚠️ Importante: a validação só funcionará corretamente se o JSON for serializado exatamente conforme o padrão abaixo:
- Barras (
/) não são escapadas - Caracteres Unicode não são escapados (ex:
áao invés de\u00e1)
Exemplo em PHP
<?php
$body = file_get_contents('php://input');
$clientToken = 'seu_client_token_aqui';
$expectedSignature = hash_hmac('sha256', $body, $clientToken);
$providedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expectedSignature, $providedSignature)) {
http_response_code(401);
exit('Assinatura inválida');
}
$payload = json_decode($body, true);
Exemplo em Node.js
const crypto = require('crypto');
const express = require('express');
const app = express();
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString('utf8');
}
}));
app.post('/webhook', (req, res) => {
const clientToken = 'seu_client_token_aqui';
const providedSignature = req.headers['x-webhook-signature'];
const expectedSignature = crypto
.createHmac('sha256', clientToken)
.update(req.rawBody)
.digest('hex');
if (expectedSignature !== providedSignature) {
return res.status(401).send('Assinatura inválida');
}
console.log('Evento recebido:', req.body.event);
res.status(200).send('OK');
});
Exemplo de Assinatura
Abaixo está um exemplo de corpo de requisição de webhook e o valor esperado para o cabeçalho X-Webhook-Signature, assumindo que o client_token seja mySecretKey123.
Corpo da Requisição de Exemplo:
{
"type": "class_history",
"event": "class.completed",
"created": "2025-01-13T14:30:00.000000Z",
"data": {
"datetime": "2025-01-13T14:25:00.000000Z",
"platform_id": 1,
"platform_name": "Minha Plataforma",
"student": {
"id": 12345,
"reference_id": "EXT-001",
"name": "João da Silva",
"email": "joao@exemplo.com",
"phone": "+5511999999999",
"document": "12345678900",
"gender": "male"
},
"course": {
"id": 100,
"name": "Curso de Programação",
"module": {
"id": 10,
"name": "Módulo 1 - Fundamentos",
"class": {
"id": 1,
"name": "Introdução ao PHP"
}
}
}
}
}
Assinatura Esperada
Para o corpo acima e client_token mySecretKey123, o valor do cabeçalho X-Webhook-Signature será (exemplo ilustrativo):
4a3d8c1e2f5b6a7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c
Nota: A assinatura acima é ilustrativa. O valor real dependerá da serialização exata do JSON e da chave secreta.
Importante: A assinatura só corresponderá se o JSON for serializado exatamente como acima, sem barras ou unicode escapados.
Eventos Disponíveis
Conclusão de Aula (class.completed)
Disparado quando o aluno conclui uma aula (progresso 100% ou aula finalizada).
- Tipo:
class_history - Evento:
class.completed
Inclui dados da plataforma, aluno, curso, módulo e aula.
{
"type": "class_history",
"event": "class.completed",
"created": "2025-01-13T14:30:00.000000Z",
"data": {
"datetime": "2025-01-13T14:25:00.000000Z",
"platform_id": 1,
"platform_name": "Minha Plataforma",
"student": {
"id": 12345,
"reference_id": "EXT-001",
"name": "João da Silva",
"email": "joao@exemplo.com",
"phone": "+5511999999999",
"document": "12345678900",
"gender": "male"
},
"course": {
"id": 100,
"name": "Curso de Programação",
"module": {
"id": 10,
"name": "Módulo 1 - Fundamentos",
"class": {
"id": 1,
"name": "Introdução ao PHP"
}
}
}
}
}
Publicação de Aula (class.published)
Enviado quando uma aula é criada ou publicada manualmente na plataforma.
- Tipo:
class - Evento:
class.published
Inclui dados do curso, módulo e aula publicada.
{
"type": "class",
"event": "class.published",
"created": "2025-01-13T14:30:00.000000Z",
"data": {
"datetime": "2025-01-13T14:30:00.000000Z",
"platform_id": 1,
"platform_name": "Minha Plataforma",
"course": {
"id": 100,
"name": "Curso de Programação",
"module": {
"id": 10,
"name": "Módulo 1 - Fundamentos",
"class": {
"id": 1,
"name": "Introdução ao PHP"
}
}
}
}
}
Certificado Emitido (certificate.issued)
Disparado no momento da emissão de um certificado para um aluno.
- Tipo:
certificate - Evento:
certificate.issued
Inclui dados do aluno, curso e certificado emitido.
{
"type": "certificate",
"event": "certificate.issued",
"created": "2025-01-13T14:30:00.000000Z",
"data": {
"datetime": "2025-01-13T14:30:00.000000Z",
"platform_id": 1,
"platform_name": "Minha Plataforma",
"student": {
"id": 12345,
"reference_id": "EXT-001",
"name": "João da Silva",
"email": "joao@exemplo.com",
"phone": "+5511999999999",
"document": "12345678900",
"gender": "male"
},
"course": {
"id": 100,
"name": "Curso de Programação"
},
"certificate": {
"id": 50,
"name": "Certificado de Conclusão"
}
}
}
Usuário Inativo por 7 Dias (user.inactive_for_7_days)
Enviado quando um usuário permanece exatamente 7 dias sem login.
📌 Observação: enquanto o usuário continuar inativo, o evento será reenviado a cada 7 dias.
- Tipo:
login_history - Evento:
user.inactive_for_7_days
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "login_history",
"event": "user.inactive_for_7_days",
"created": "2025-01-13T14:30:00.000000Z",
"data": {
"datetime": "2025-01-06T14:30:00.000000Z",
"inactive_days": 7,
"platform_id": 1,
"platform_name": "Minha Plataforma",
"student": {
"id": 12345,
"reference_id": "EXT-001",
"name": "João da Silva",
"email": "joao@exemplo.com",
"phone": "+5511999999999",
"document": "12345678900",
"gender": "female"
}
}
}
Aluno finalizou o quiz (quiz.completed)
Enviado quando o aluno finaliza uma avaliação.
- Listener: DispatchQuizWebhooksListener
- Trigger: QuizUserAnswerService após salvar respostas
{
"id": "uuid",
"type": "quiz",
"event": "quiz.completed",
"created": "2026-06-19T12:02:00.000000Z",
"data": {
"datetime": "2026-06-19T12:02:00.000000Z",
"platform_id": 2654,
"platform_name": "Nome da Plataforma",
"student": {
"id": 12345,
"reference_id": "ID-EXTERNO",
"name": "João da Silva",
"email": "joao@exemplo.com",
"phone": "+5511999999999",
"document": "12345678900",
"gender": "male"
},
"quiz": {
"id": 1,
"name": "Nome do Quiz",
"type": "tipo-do-quiz",
"approved": true,
"performance": 85.5,
"awaiting_evaluation": false,
"class_id": 50
},
"course": {
"id": 100,
"name": "Nome do Curso",
"course_type": "livre",
"module": {
"id": 10,
"name": "Nome do Módulo",
"class": {
"id": 50,
"name": "Nome da Aula"
}
}
Aluno aprovado (quiz.approved)
Enviado quando o aluno é aprovado em uma avaliação.
- Quando dispara: junto com quiz.completed, quando o aluno atinge a nota mínima
- Payload: mesmo formato do quiz.completed, com "event": "quiz.approved" e "approved": true
Aluno reprovado (quiz.reproved)
Enviado quando o aluno é reprovado em uma avaliação.
- Quando dispara: junto com quiz.completed, quando o aluno não atinge a nota mínima
- Payload: mesmo formato do quiz.completed, com "event": "quiz.reproved" e "approved": false
Regra dos 3 eventos de quiz:
- Sempre dispara quiz.completed
- Se tem nota de corte: dispara também quiz.approved ou quiz.reproved
- Se não tem nota de corte: só quiz.completed
Curso criado (course.created)
Enviado quando um novo curso é adicionado na plataforma.
- Listener: DispatchCourseCreatedWebhooksListener
- Trigger: Evento CourseCreatedEvent no created do model Courses
{
"id": "uuid",
"type": "course",
"event": "course.created",
"created": "2026-06-19T12:00:00.000000Z",
"data": {
"datetime": "2026-06-19T12:00:00.000000Z",
"platform_id": 2654,
"platform_name": "Nome da Plataforma",
"course": {
"id": 100,
"name": "Nome do Curso",
"course_type": "livre | extensao | pos_graduacao",
"status": "published | unpublished"
}
}
Módulo criado (module.created)
Enviado quando um novo módulo é adicionado na plataforma
- Listener: DispatchModuleCreatedWebhooksListener
- Trigger: evento ModuleCreatedEvent no created do model Modules
Obs.: 1 webhook por disciplina — não vem array no course.created
{
"id": "uuid",
"type": "module",
"event": "module.created",
"created": "2026-06-19T12:01:00.000000Z",
"data": {
"datetime": "2026-06-19T12:01:00.000000Z",
"platform_id": 2654,
"platform_name": "Nome da Plataforma",
"course": {
"id": 100,
"name": "Nome do Curso",
"course_type": "pos_graduacao",
"status": "published",
"module": {
"id": 10,
"name": "Nome da Disciplina",
"status": "published"
}
}
Formato do Payload
Content-Type: application/json- Datas no padrão ISO 8601
- Campos podem retornar
null - Telefones no padrão E.164 (ex:
+5511999999999) - CPF/CNPJ enviados apenas com números
Boas Práticas
Segurança
- Valide sempre a assinatura HMAC antes de processar o evento
- Não compartilhe o
client_token - Utilize HTTPS no endpoint de webhook
Performance e Resposta
- Responda rapidamente com HTTP 200
- Evite processamentos pesados na requisição
- Utilize filas e processamento assíncrono
Confiabilidade
- Implemente idempotência (eventos podem ser reenviados)
- Registre logs para auditoria e troubleshooting
Tratamento de Erros
- Até 3 tentativas automáticas em caso de falha
- Intervalos: 30s, 60s e 120s
- Após falha definitiva, o evento não será reenviado

Atualizado em: 19/06/2026
