import { createHmac } from 'crypto';
import { NextResponse } from 'next/server';
const WEBHOOK_SECRET = process.env.MP_WEBHOOK_SECRET;
const MP_ACCESS_TOKEN = process.env.MP_ACCESS_TOKEN;
function validateWebhookSignature(
signature: string,
requestId: string,
resourceId: string,
): boolean {
try {
if (!WEBHOOK_SECRET) {
console.error('WEBHOOK_SECRET não configurado');
return false;
}
// Extrair timestamp e assinatura
const [timestampPart, signaturePart] = signature.split(',');
const timestamp = timestampPart.replace('ts=', '');
const receivedSignature = signaturePart.replace('v1=', '');
// Criar manifesto
const manifest = `id:${resourceId};request-id:${requestId};ts:${timestamp};`;
// Gerar assinatura
const generatedSignature = createHmac('sha256', WEBHOOK_SECRET)
.update(manifest)
.digest('hex');
// Comparar assinaturas
return receivedSignature === generatedSignature;
} catch (error) {
console.error('Erro na validação da assinatura:', error);
return false;
}
}
export async function POST(request: Request) {
try {
if (!MP_ACCESS_TOKEN) {
console.error('MP_ACCESS_TOKEN não configurado');
return NextResponse.json({ success: false });
}
// Obter headers necessários
const signature = request.headers.get('x-signature');
const requestId = request.headers.get('x-request-id');
const body = await request.json();
// Verifica se é uma notificação de pagamento
if (body.type === 'payment' && body.data.id) {
const paymentId = body.data.id.toString();
// Validar assinatura do webhook
if (!signature || !requestId) {
console.error('Headers de assinatura ausentes');
return NextResponse.json(
{ error: 'Headers de assinatura ausentes' },
{ status: 401 }
);
}
if (!validateWebhookSignature(signature, requestId, paymentId)) {
console.error('Assinatura do webhook inválida');
return NextResponse.json(
{ error: 'Assinatura inválida' },
{ status: 401 }
);
}
// Verifica o status do pagamento no Mercado Pago
const mpResponse = await fetch(`https://api.mercadopago.com/v1/payments/${paymentId}`, {
headers: {
'Authorization': `Bearer ${MP_ACCESS_TOKEN}`
}
});
if (!mpResponse.ok) {
console.error('Erro ao consultar status do pagamento no Mercado Pago');
return NextResponse.json(
{ error: 'Erro ao consultar status do pagamento' },
{ status: 500 }
);
}
const mpData = await mpResponse.json();
if (mpData.status === 'approved') {
try {
console.log("Pagamento aprovado.");
} catch (error) {
console.error('Erro ao processar licença:', error);
}
}
return NextResponse.json({ success: true });
}
return NextResponse.json({ success: true });
} catch (error) {
console.error('Erro no webhook:', error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Erro interno do servidor' },
{ status: 500 }
);
}
}
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter