POST /api/webhook/payment
Recebe notificações de pagamento do app-front, verificadas via assinatura HMAC SHA256.
URL: https://sso.easygoal.com.br/api/webhook/payment
Headers:
Payload
{
"event": "subscription.activated",
"data": {
"subscription_id": "550e8400-e29b-41d4-a716-446655440000",
"product_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"product_name": "Club EasyGoal",
"user_email": "usuario@email.com",
"user_name": "João Silva",
"amount": 9900,
"frequency": "MONTHLY",
"started_at": "2026-02-22T10:00:00.000Z",
"is_test": false
},
"timestamp": "2026-02-22T10:00:00.000Z",
"signature": "a3f8b2c1d4e5f6..."
}
Campos do payload:
Tipo do evento. Atualmente: subscription.activated.
UUID da assinatura ativada.
Email do usuário que assinou.
Valor da assinatura em centavos (ex: 9900 = R$ 99,00).
Se true, o webhook é um teste. Não provisionar acesso real.
Assinatura HMAC SHA256 do payload (sem o campo signature) codificada em hex.
Como o app-front assina o webhook
// app-front → utilitário de webhook
import { createHmac } from 'crypto';
function signWebhook(payload: object, secret: string): string {
return createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
}
// Enviando o webhook
const body = { event, data, timestamp };
const signature = signWebhook(body, process.env.SSO_WEBHOOK_SECRET!);
await fetch(process.env.SSO_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...body, signature }),
});
Como o SSO verifica a assinatura
import { createHmac, timingSafeEqual } from 'crypto';
const { signature, ...bodyWithoutSignature } = payload;
const expectedSignature = createHmac('sha256', process.env.APP_WEBHOOK_SECRET!)
.update(JSON.stringify(bodyWithoutSignature))
.digest('hex');
const sigBuffer = Buffer.from(signature, 'hex');
const expectedBuffer = Buffer.from(expectedSignature, 'hex');
const isValid =
sigBuffer.length === expectedBuffer.length &&
timingSafeEqual(sigBuffer, expectedBuffer);
Use sempre timingSafeEqual para comparar assinaturas. Comparações diretas com === são vulneráveis a timing attacks.
Respostas
true quando o webhook foi processado com sucesso.
// 200 OK
{ "received": true }
// 400 Bad Request
{ "error": "Payload invalido" }
// 401 Unauthorized
{ "error": "Assinatura ausente" }
{ "error": "Assinatura invalida" }
Testar o Webhook
No painel admin do app-front, acesse a seção de configuração do produto e clique em “Testar Webhook”. Isso envia um payload com is_test: true para o SSO, sem provisionar acesso real.
Ao receber is_test: true, o SSO deve registrar o evento mas não liberar acesso ao usuário. Use isso para validar a configuração do endpoint antes de ir para produção.