import { NextResponse } from 'next/server'; import jwt from 'jsonwebtoken'; import { z } from 'zod'; import { enhanceRouteHandler } from '@kit/next/routes'; import { getLogger } from '@kit/shared/logger'; interface MontonioOrderToken { uuid: string; accessKey: string; merchantReference: string; merchantReferenceDisplay: string; paymentStatus: | 'PAID' | 'FAILED' | 'CANCELLED' | 'PENDING' | 'EXPIRED' | 'REFUNDED'; paymentMethod: string; grandTotal: number; currency: string; senderIban?: string; senderName?: string; paymentProviderName?: string; paymentLinkUuid: string; iat: number; exp: number; } const BodySchema = z.object({ token: z.string(), }); export const POST = enhanceRouteHandler( async ({ request }) => { const logger = await getLogger(); const body = await request.json(); const namespace = 'montonio.verify-token'; const activeCartId = request.cookies.get('_medusa_cart_id')?.value; console.info('cart id', activeCartId); try { const { token } = BodySchema.parse(body); const secretKey = process.env.MONTONIO_SECRET_KEY as string; if (!secretKey) { logger.error( { name: namespace, }, `Missing MONTONIO_SECRET_KEY`, ); throw new Error('Server misconfiguration.'); } const decoded = jwt.verify(token, secretKey, { algorithms: ['HS256'], }) as MontonioOrderToken; const [, cartId] = decoded.merchantReferenceDisplay.split(':'); console.info('active cart id parsed', {cartId, activeCartId, decoded:decoded.merchantReferenceDisplay}); if (cartId !== activeCartId) { throw new Error('Invalid cart id'); } logger.info( { name: namespace, status: decoded.paymentStatus, orderId: decoded.uuid, }, `Successfully verified Montonio token.`, ); return NextResponse.json({ status: decoded.paymentStatus, }); } catch (error) { logger.error( { name: namespace, error, }, `Failed to verify Montonio token`, ); const message = error instanceof Error ? error.message : 'Invalid token'; return NextResponse.json( { error: message, }, { status: 400, }, ); } }, { auth: false, }, );