Back to API Overview

Real-time Webhooks

Receive instant notifications when email verifications complete. Push results directly to your systems without polling.

How Webhooks Work

When you enable webhooks, ValidMail will send an HTTP POST request to your specified URL immediately after each verification completes. This allows real-time integration without polling our API.

Setting Up Webhooks

  1. Go to Dashboard → Settings → Notifications
  2. Navigate to the "Webhook" tab
  3. Enable webhooks and enter your endpoint URL
  4. Optionally add a signing secret for request verification
  5. Enable "Real-time Verification Results" under Alert Types
  6. Save your settings

Webhook Payload

Each verification result webhook includes the following payload:

{
  "event": "verification.completed",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "data": {
    "email": "user@example.com",
    "status": "valid",
    "score": 95,
    "verdict": "Email verified with high confidence",
    "isCatchAll": false,
    "checks": {
      "syntax": { "valid": true },
      "dns": {
        "valid": true,
        "mxRecords": ["mx1.example.com"]
      },
      "smtp": {
        "valid": true,
        "catchAll": false
      },
      "disposable": false,
      "roleBased": false,
      "freeProvider": false
    },
    "typoSuggestion": {
      "original": "user@gmial.com",
      "suggested": "user@gmail.com",
      "confidence": 95,
      "reason": "Common domain typo"
    },
    "responseTimeMs": 234
  },
  "meta": {
    "apiKeyId": "key_abc123",
    "organizationId": "org_xyz789"
  }
}

Field Reference

FieldTypeDescription
eventstringAlways "verification.completed"
timestampstringISO 8601 timestamp
data.emailstringThe verified email address
data.statusstringvalid | invalid | risky | unknown
data.scorenumberDeliverability score (0-100)
data.isCatchAllboolean | nullWhether domain accepts all emails
data.checksobjectDetailed verification checks
meta.apiKeyIdstringID of the API key used

Verifying Webhook Signatures

When you configure a signing secret, we sign each webhook request using HMAC-SHA256. The signature is included in the X-ValidMail-Signature header.

Node.js Example

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-validmail-signature'];
  const payload = req.body.toString();

  if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(payload);

  if (event.event === 'verification.completed') {
    console.log('Email verified:', event.data.email, event.data.status);
    // Process the verification result
  }

  res.status(200).send('OK');
});

Python Example

import hmac
import hashlib

def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-ValidMail-Signature')
    payload = request.get_data()

    if not verify_webhook_signature(payload, signature, WEBHOOK_SECRET):
        return 'Invalid signature', 401

    event = request.get_json()

    if event['event'] == 'verification.completed':
        print(f"Email verified: {event['data']['email']} - {event['data']['status']}")
        # Process the verification result

    return 'OK', 200

Delivery & Retry Policy

  • Webhooks are delivered within milliseconds of verification completion
  • We use a 5-second timeout for webhook delivery
  • Failed webhooks are not retried to maintain real-time performance
  • Your endpoint should return a 2xx status code to acknowledge receipt
  • Webhook delivery does not block the API response

Best Practices

  • Always verify signatures - Use the signing secret to validate that webhooks are from ValidMail
  • Respond quickly - Return a 200 response immediately and process asynchronously if needed
  • Handle duplicates - Use the email and timestamp to deduplicate if your endpoint receives the same event twice
  • Use HTTPS - Always use HTTPS endpoints for webhook URLs
  • Monitor failures - Set up logging to track webhook delivery issues

Request Headers

Each webhook request includes these headers:

HeaderDescription
Content-Typeapplication/json
X-ValidMail-Eventverification.completed
X-ValidMail-SignatureHMAC-SHA256 signature (if secret configured)