What happens
POST /v1/paymentLink/integrations/kucoin/webhook/cancel exists in the source but is never
registered as a route, so a caller receives a 404.
src/subdomains/core/payment-link/controllers/c2b-payment-link.controller.ts:69-70:
@Post('integrations/kucoin/webhook/success')
@Post('integrations/kucoin/webhook/cancel')
@ApiExcludeEndpoint()
@HttpCode(200)
@UseGuards(KucoinPayWebhookGuard)
async kucoinPayWebhook(@Body() dto: any): Promise<{ returnCode: string; returnMessage: string }> {
Two routing decorators sit on the same handler. Nest stores a single path per handler
(PATH_METADATA is one value, not a list), so the decorator applied last wins and only
.../webhook/success ends up registered. This is confirmed by the routes the framework maps at
startup: .../webhook/success appears, .../webhook/cancel does not.
How severe this is — honestly, unclear
The route is definitely missing. Whether that costs anything depends on facts not visible in
this repo:
- The webhook URL is never sent to the provider from our code — there is no
webhook reference
in src/integration/kucoin-pay/, only credentials in config. The callback URLs appear to be
configured on the provider side, so whether cancel notifications are addressed to
.../cancel at all cannot be answered here.
- Even if they were delivered, the handler ignores the path and dispatches purely on the body,
and its switch only acts on C2BPaymentStatus.COMPLETED. A cancel event would be
acknowledged with 200 and otherwise do nothing.
So the realistic impact is that the provider may be receiving 404s for cancel callbacks —
possibly triggering retries on their side — rather than payments being mishandled. Someone with
access to the provider configuration should confirm which URLs are registered.
Fix options
- If the provider only ever calls
.../success: drop the second decorator, the dead path
disappears.
- If both URLs are configured: give cancel its own handler method, or register the paths as an
array on one decorator.
Either way the endpoint inventory in docs/endpoints.md should be updated with it.
How this surfaced
Building the endpoint inventory (#4551) included a cross-check of the decorator-derived list
against the routes registered at startup. Every one of the 526 distinct method/path pairs
matched except this one, which exists only in the source.
What happens
POST /v1/paymentLink/integrations/kucoin/webhook/cancelexists in the source but is neverregistered as a route, so a caller receives a 404.
src/subdomains/core/payment-link/controllers/c2b-payment-link.controller.ts:69-70:Two routing decorators sit on the same handler. Nest stores a single path per handler
(
PATH_METADATAis one value, not a list), so the decorator applied last wins and only.../webhook/successends up registered. This is confirmed by the routes the framework maps atstartup:
.../webhook/successappears,.../webhook/canceldoes not.How severe this is — honestly, unclear
The route is definitely missing. Whether that costs anything depends on facts not visible in
this repo:
webhookreferencein
src/integration/kucoin-pay/, only credentials in config. The callback URLs appear to beconfigured on the provider side, so whether cancel notifications are addressed to
.../cancelat all cannot be answered here.and its
switchonly acts onC2BPaymentStatus.COMPLETED. A cancel event would beacknowledged with 200 and otherwise do nothing.
So the realistic impact is that the provider may be receiving 404s for cancel callbacks —
possibly triggering retries on their side — rather than payments being mishandled. Someone with
access to the provider configuration should confirm which URLs are registered.
Fix options
.../success: drop the second decorator, the dead pathdisappears.
array on one decorator.
Either way the endpoint inventory in
docs/endpoints.mdshould be updated with it.How this surfaced
Building the endpoint inventory (#4551) included a cross-check of the decorator-derived list
against the routes registered at startup. Every one of the 526 distinct method/path pairs
matched except this one, which exists only in the source.