In NestJS apps, it's common to use global route prefixes and versioning like /api/v1. But sometimes you need a public-facing endpoint β such as a payment gateway callback β that must live outside those constraints.
Hereβs how to expose routes like /payment/callback without the global /api/v1 prefix.
π§ Problem
You're using global prefixing and versioning like this:
main.ts:
app.setGlobalPrefix('api');
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: '1',
});
β Resulting in routes like:
/api/v1/auth/login
/api/v1/user/profile
β But now you need /payment/callback to be exposed at:
http://localhost:3000/payment/callback
Instead of:
http://localhost:3000/api/v1/payment/callback
β
Solution Overview
You need to do two things:
β Exclude the route from the global prefix
β Mark the route as version-neutral
- Exclude the Route from Global Prefix Update main.ts:
import { RequestMethod } from '@nestjs/common';
app.setGlobalPrefix('api', {
exclude: [{ path: 'payment/callback', method: RequestMethod.GET }],
});
This tells NestJS to ignore prefixing for GET /payment/callback
π« No leading slash in path (correct: payment/callback)
- Mark Route as Version-Neutral Update your controller:
import { Controller, Get, Version, VERSION_NEUTRAL } from '@nestjs/common';
@Controller('payment')
export class PaymentController {
@Get('callback')
@Version(VERSION_NEUTRAL)
callback() {
return 'Payment callback hit!';
}
}
β VERSION_NEUTRAL tells NestJS: βdo not apply any version prefixβ
π§ͺ Final Result
http://localhost:3000/payment/callback
β
http://localhost:3000/api/v1/payment/callback
β
All other routes still work normally under /api/v1.
π§΅ Conclusion
NestJS makes it easy to maintain clean API versioning β but when you need an exception like a public payment callback, it only takes
two steps:
- Exclude the path in setGlobalPrefix()
- Add @version(VERSION_NEUTRAL) to the controller
Top comments (0)