Skip to main content

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:
Content-Type
string
required
application/json

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:
event
string
required
Tipo do evento. Atualmente: subscription.activated.
data.subscription_id
string
required
UUID da assinatura ativada.
data.product_name
string
required
Nome do produto SaaS.
data.user_email
string
required
Email do usuário que assinou.
data.amount
number
required
Valor da assinatura em centavos (ex: 9900 = R$ 99,00).
data.is_test
boolean
required
Se true, o webhook é um teste. Não provisionar acesso real.
signature
string
required
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

received
boolean
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.