diff --git a/apps/sim/app/api/webhooks/trigger/[path]/route.ts b/apps/sim/app/api/webhooks/trigger/[path]/route.ts index 549ce6a78..9cdff87dc 100644 --- a/apps/sim/app/api/webhooks/trigger/[path]/route.ts +++ b/apps/sim/app/api/webhooks/trigger/[path]/route.ts @@ -5,6 +5,7 @@ import { checkWebhookPreprocessing, findWebhookAndWorkflow, handleProviderChallenges, + handleProviderReachabilityTest, parseWebhookBody, queueWebhookExecution, verifyProviderAuth, @@ -123,6 +124,11 @@ export async function POST( return authError } + const reachabilityResponse = handleProviderReachabilityTest(foundWebhook, body, requestId) + if (reachabilityResponse) { + return reachabilityResponse + } + let preprocessError: NextResponse | null = null try { preprocessError = await checkWebhookPreprocessing(foundWorkflow, foundWebhook, requestId) diff --git a/apps/sim/lib/webhooks/processor.ts b/apps/sim/lib/webhooks/processor.ts index b197a8ef1..96cf01b8f 100644 --- a/apps/sim/lib/webhooks/processor.ts +++ b/apps/sim/lib/webhooks/processor.ts @@ -121,6 +121,34 @@ export async function handleProviderChallenges( return null } +/** + * Handle provider-specific reachability tests that occur AFTER webhook lookup. + * + * @param webhook - The webhook record from the database + * @param body - The parsed request body + * @param requestId - Request ID for logging + * @returns NextResponse if this is a verification request, null to continue normal flow + */ +export function handleProviderReachabilityTest( + webhook: any, + body: any, + requestId: string +): NextResponse | null { + const provider = webhook?.provider + + if (provider === 'grain') { + const isVerificationRequest = !body || Object.keys(body).length === 0 || !body.type + if (isVerificationRequest) { + logger.info( + `[${requestId}] Grain reachability test detected - returning 200 for webhook verification` + ) + return NextResponse.json({ status: 'ok', message: 'Webhook endpoint verified' }) + } + } + + return null +} + export async function findWebhookAndWorkflow( options: WebhookProcessorOptions ): Promise<{ webhook: any; workflow: any } | null> {