Skip to main content
Glama
Hookflo
by Hookflo

verify_signature

Verify webhook signatures and diagnose failures with static header/body analysis or live endpoint testing to identify and fix verification issues.

Instructions

Verify and debug webhook signatures. Two modes: (1) Static — pass raw headers, body and secret, get exact error with fix. (2) Live — pass your endpoint URL, Tern sends a real signed test payload and diagnoses exactly why it failed.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
platformYesWebhook provider platform
secretNoWebhook signing secret. Leave empty for fal.ai.
headersNoRaw request headers — for static verification mode
bodyNoRaw request body string — for static verification mode
endpointUrlNoYour live webhook endpoint URL — for live diagnosis mode

Implementation Reference

  • The primary handler function 'verifySignature' for the tool. It either performs a live diagnosis by hitting an endpoint or verifies headers/body against a secret using WebhookVerificationService.
    export async function verifySignature(input: VerifySignatureInput) {
      if (input.endpointUrl) {
        try {
          const body = getTestPayload(input.platform)
          const headers = await buildSignedRequest(input.platform, input.secret, body)
    
          const response = await fetch(input.endpointUrl, {
            method: 'POST',
            headers,
            body,
          })
    
          const responseText = await response.text().catch(() => '')
    
          if (response.ok) {
            return {
              mode: 'live_endpoint',
              valid: true,
              statusCode: response.status,
              endpoint: input.endpointUrl,
              message: `✓ Endpoint verified successfully. ${input.platform} webhook signature accepted.`,
              response: responseText,
            }
          }
    
          const diagnosis: Record<number, string> = {
            400: 'Endpoint returned 400 — signature verification is failing. Most likely cause: raw body is being parsed before verification.',
            401: 'Endpoint returned 401 — unauthorized. Secret mismatch or missing signature header.',
            403: 'Endpoint returned 403 — forbidden. Signature rejected. Check your secret matches the platform dashboard.',
            404: 'Endpoint returned 404 — route not found. Check your webhook URL path is correct.',
            500: 'Endpoint returned 500 — server error in your handler. Check your application logs.',
          }
    
          return {
            mode: 'live_endpoint',
            valid: false,
            statusCode: response.status,
            endpoint: input.endpointUrl,
            diagnosis: diagnosis[response.status] ?? `Unexpected status ${response.status}`,
            response: responseText,
            fix: response.status === 400 || response.status === 403
              ? 'Add raw body parsing before your verification step. See tern.hookflo.com for framework-specific guides.'
              : null,
          }
        } catch (error) {
          return {
            mode: 'live_endpoint',
            valid: false,
            error: (error as Error).message,
            diagnosis: 'Could not reach endpoint. Check the URL is publicly accessible and your server is running.',
          }
        }
      }
    
      if (!input.headers || !input.body) {
        return {
          valid: false,
          error: 'Provide either headers + body for static verification, or endpointUrl for live diagnosis.',
        }
      }
    
      try {
        const request = new Request('https://tern-mcp.local/webhook', {
          method: 'POST',
          headers: input.headers,
          body: input.body,
        })
    
        const result = await WebhookVerificationService.verifyWithPlatformConfig(
          request,
          input.platform,
          input.secret,
        )
    
        if (result.isValid) {
          return {
            mode: 'static',
            valid: true,
            platform: result.platform,
            eventId: result.eventId,
            payload: result.payload,
            message: `✓ Signature verified for ${input.platform}`,
          }
        }
    
        return {
          mode: 'static',
          valid: false,
          platform: result.platform,
          errorCode: result.errorCode,
          error: result.error,
          explanation: ERROR_EXPLANATIONS[result.errorCode ?? ''] ?? 'Unknown error. Check secret and headers.',
          debugTips: DEBUG_TIPS[result.errorCode ?? ''] ?? [],
        }
      } catch (error) {
        return {
          mode: 'static',
          valid: false,
          error: (error as Error).message,
          explanation: 'Verification threw unexpected error. Check your inputs.',
        }
      }
    }
  • Zod schema defining the input parameters for the 'verify_signature' tool.
    export const verifySignatureSchema = z.object({
      platform: z.enum([
        'stripe', 'github', 'clerk', 'shopify', 'polar', 'workos',
        'dodopayments', 'paddle', 'lemonsqueezy', 'gitlab', 'sentry',
        'grafana', 'doppler', 'sanity', 'falai', 'replicateai',
      ]).describe('The webhook provider platform'),
      secret: z.string()
        .optional()
        .default('')
        .describe('Webhook signing secret. Leave empty for fal.ai (auto JWKS)'),
    
      headers: z.record(z.string())
        .optional()
        .describe('Raw request headers as key-value object'),
      body: z.string()
        .optional()
        .describe('Raw request body as string — must be raw, not parsed JSON'),
    
      endpointUrl: z.string()
        .optional()
        .describe('Your webhook endpoint URL. If provided, Tern sends a real signed test payload and diagnoses the response.'),
    })
    
    export type VerifySignatureInput = z.infer<typeof verifySignatureSchema>

Tool Definition Quality

Score is being calculated. Check back soon.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Hookflo/tern-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server