Artigos sobre: Dashboard (Área do Administrador)

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ção
  • X-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


  1. Obtenha o corpo bruto da requisição (JSON sem qualquer modificação).
  2. Calcule o HMAC-SHA256 utilizando o client_token como chave.
  3. Gere o hash em formato hexadecimal.
  4. 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


Histórico: Também é possível visualizar todo o seu histórico de envios clicando em ver histórico. Dentro do histórico, você pode clicar em Ver payload e ter acesso à todo o corpo de requisição enviado, como na imagem demonstrativa abaixo.




Considerações Finais: Os webhooks permitem integrações robustas e em tempo real com sistemas externos. Seguindo as boas práticas de segurança e performance, é possível construir integrações confiáveis, escaláveis e seguras.

Atualizado em: 19/06/2026