Skip to main content

Overview

When receiving webhooks from Inbound, it’s important to verify that requests are legitimate. Inbound includes a verification token in the X-Webhook-Verification-Token header for each webhook request.

Webhook Verification

Every webhook request includes security headers that allow you to verify the request authenticity:
HeaderDescription
X-Webhook-Verification-TokenUnique verification token for your endpoint
X-Endpoint-IDID of the endpoint that triggered this webhook
X-Webhook-EventEvent type (e.g., email.received)
X-Webhook-TimestampISO 8601 timestamp of when the webhook was sent

Using the SDK Verification Helper

The SDK provides a verifyWebhook helper function that automatically fetches your endpoint configuration and compares the verification token:
  • Next.js
  • Express.js
  • Manual Verification
app/api/webhook/route.ts
import { Inbound, verifyWebhookFromHeaders } from '@inboundemail/sdk'

const inbound = new Inbound(process.env.INBOUND_API_KEY!)

export async function POST(request: Request) {
  // Verify webhook authenticity
  const isValid = await verifyWebhookFromHeaders(request.headers, inbound)
  
  if (!isValid) {
    return new Response('Unauthorized', { status: 401 })
  }
  
  // Process webhook payload
  const payload = await request.json()
  const email = payload.email
  
  // Your webhook handling logic here
  console.log('Received email:', email.subject)
  
  return new Response('OK', { status: 200 })
}

How Verification Works

  1. Verification Token: Each endpoint has a unique verification token stored in its configuration
  2. Header Transmission: Inbound sends this token in the X-Webhook-Verification-Token header with every webhook request
  3. SDK Verification: The verifyWebhook function fetches your endpoint config via the API and compares tokens
  4. Security: If tokens don’t match, the request should be rejected
Always verify webhook requests in production to prevent unauthorized access to your endpoints.
The verification token is automatically generated when you create an endpoint. You can view it in your endpoint configuration via the API.

Manual Verification (Without SDK)

If you’re not using the SDK, you can manually verify webhooks by fetching the endpoint configuration:
async function verifyWebhookManually(
  endpointId: string,
  verificationToken: string,
  apiKey: string
): Promise<boolean> {
  // Fetch endpoint from API
  const response = await fetch(`https://inbound.new/api/v2/endpoints/${endpointId}`, {
    headers: {
      'Authorization': `Bearer ${apiKey}`
    }
  })
  
  if (!response.ok) {
    return false
  }
  
  const endpoint = await response.json()
  const config = typeof endpoint.config === 'string' 
    ? JSON.parse(endpoint.config) 
    : endpoint.config
  
  // Compare tokens
  return config.verificationToken === verificationToken
}

Getting Your Verification Token

You can retrieve the verification token for your endpoint via the API:
import { Inbound } from '@inboundemail/sdk'

const inbound = new Inbound(process.env.INBOUND_API_KEY!)

// Get endpoint configuration
const { data: endpoint } = await inbound.endpoint.get('your-endpoint-id')

if (endpoint) {
  const config = typeof endpoint.config === 'string' 
    ? JSON.parse(endpoint.config) 
    : endpoint.config
  
  console.log('Verification token:', config.verificationToken)
}

Best Practices

Always Verify in Production

Never skip webhook verification in production environments. Unverified webhooks can expose your application to security risks.

Handle Verification Failures

Always return appropriate error responses when verification fails:
if (!isValid) {
  // Log the failed attempt for monitoring
  console.warn('Webhook verification failed', {
    endpointId: request.headers.get('X-Endpoint-ID'),
    timestamp: new Date().toISOString()
  })
  
  // Return 401 Unauthorized
  return new Response('Unauthorized', { status: 401 })
}

Store API Keys Securely

Never hardcode API keys or commit them to version control:
  • Use environment variables
  • Use secrets management services in production
  • Rotate API keys regularly

Next Steps