Fetch Webhook

The Fetch Webhook endpoint retrieves detailed information about a specific webhook configuration by its unique identifier. This endpoint provides comprehensive webhook details including delivery statistics, configuration settings, and current status.

Endpoint DetailsCopied!

  • URL: /api/v0/webhooks/{id}

  • Method: GET

  • Authentication: Required (API Key Authentication with Scopes)

  • Content-Type: application/json

  • Required Scope: webhook:read

AuthenticationCopied!

This endpoint requires API key authentication with specific scopes:

Required Headers

x-client-key: your-client-key
x-client-secret: your-client-secret

Required Scope

Your API key must have the webhook:read scope to access this endpoint.

Path ParametersCopied!

Required Parameters

Parameter

Type

Description

Validation

id

string

Unique webhook identifier

Must be a valid webhook ID (typically prefixed with wh_)

Request ExamplesCopied!

Basic Request

curl -X GET https://api.devdraft.com/api/v0/webhooks/wh_123456789 \
  -H "x-client-key: your-client-key" \
  -H "x-client-secret: your-client-secret"

JavaScript/Fetch

const webhookId = "wh_123456789";

const response = await fetch(`/api/v0/webhooks/${webhookId}`, {
  headers: {
    'x-client-key': 'your-client-key',
    'x-client-secret': 'your-client-secret'
  }
});

const webhook = await response.json();

cURL with Response Headers

curl -X GET https://api.devdraft.com/api/v0/webhooks/wh_123456789 \
  -H "x-client-key: your-client-key" \
  -H "x-client-secret: your-client-secret" \
  -i

ResponseCopied!

Success Response (200 OK)

Returns detailed webhook information with delivery statistics:

{
  "id": "wh_123456789",
  "name": "Payment Notifications",
  "url": "https://api.example.com/webhooks/payments",
  "isActive": true,
  "encrypted": false,
  "created_at": "2024-03-20T12:00:00.000Z",
  "updated_at": "2024-03-20T12:00:00.000Z",
  "delivery_stats": {
    "total_events": 150,
    "successful_deliveries": 145,
    "failed_deliveries": 5,
    "last_delivery": "2024-03-20T11:55:00.000Z"
  }
}

Error Responses

401 Unauthorized - Missing Credentials
{
  "statusCode": 401,
  "message": "Client key or secret missing",
  "error": "Unauthorized",
  "details": "Please provide both x-client-key and x-client-secret headers"
}
401 Unauthorized - Invalid Credentials
{
  "statusCode": 401,
  "message": "Invalid client app credentials",
  "error": "Unauthorized",
  "details": "The provided API key or secret is invalid"
}
403 Forbidden - Missing Scope
{
  "statusCode": 403,
  "message": "Missing required scope",
  "error": "Forbidden",
  "details": "API key does not have the required webhook:read scope"
}
403 Forbidden - Inactive API Key
{
  "statusCode": 403,
  "message": "API key is inactive",
  "error": "Forbidden",
  "details": "The provided API key has been deactivated"
}
404 Not Found
{
  "statusCode": 404,
  "message": "Webhook not found",
  "error": "Not Found"
}
400 Bad Request - Invalid ID Format
{
  "statusCode": 400,
  "message": "Invalid webhook ID format",
  "error": "Bad Request"
}

Response FieldsCopied!

Webhook Object Fields

Field

Type

Description

id

string

Unique webhook identifier (prefixed with wh_)

name

string

Human-readable webhook name

url

string

Endpoint URL where webhook events are sent

isActive

boolean

Whether the webhook is currently active

encrypted

boolean

Whether webhook payloads are encrypted

created_at

string

ISO 8601 timestamp of webhook creation

updated_at

string

ISO 8601 timestamp of last modification

delivery_stats

object

Comprehensive delivery performance metrics

Delivery Statistics Object

Field

Type

Description

total_events

number

Total number of events sent to this webhook

successful_deliveries

number

Number of successful deliveries (HTTP 2xx responses)

failed_deliveries

number

Number of failed deliveries (non-2xx responses)

last_delivery

string | null

ISO 8601 timestamp of most recent delivery attempt

Use CasesCopied!

1. Webhook Status Verification

Check the current status and health of a specific webhook:

async function checkWebhookHealth(webhookId) {
  try {
    const webhook = await fetchWebhook(webhookId);
    
    const stats = webhook.delivery_stats;
    const successRate = stats.total_events > 0 
      ? (stats.successful_deliveries / stats.total_events * 100).toFixed(1)
      : 'N/A';
    
    return {
      id: webhook.id,
      name: webhook.name,
      isActive: webhook.isActive,
      isHealthy: webhook.isActive && (stats.failed_deliveries / Math.max(stats.total_events, 1)) < 0.1,
      successRate: `${successRate}%`,
      totalEvents: stats.total_events,
      failedDeliveries: stats.failed_deliveries,
      lastDelivery: stats.last_delivery 
        ? new Date(stats.last_delivery).toLocaleString()
        : 'Never',
      needsAttention: stats.failed_deliveries > 0 && webhook.isActive
    };
  } catch (error) {
    console.error(`Failed to check webhook ${webhookId}:`, error);
    throw error;
  }
}

2. Webhook Configuration Display

Fetch webhook details for configuration management:

async function getWebhookConfiguration(webhookId) {
  const webhook = await fetchWebhook(webhookId);
  
  return {
    basicInfo: {
      id: webhook.id,
      name: webhook.name,
      url: webhook.url,
      status: webhook.isActive ? 'Active' : 'Inactive',
      encrypted: webhook.encrypted ? 'Yes' : 'No'
    },
    timestamps: {
      created: new Date(webhook.created_at).toLocaleDateString(),
      lastUpdated: new Date(webhook.updated_at).toLocaleDateString()
    },
    performance: {
      totalEvents: webhook.delivery_stats.total_events,
      successRate: webhook.delivery_stats.total_events > 0 
        ? `${((webhook.delivery_stats.successful_deliveries / webhook.delivery_stats.total_events) * 100).toFixed(1)}%`
        : '0%',
      recentActivity: webhook.delivery_stats.last_delivery 
        ? `Last delivery: ${new Date(webhook.delivery_stats.last_delivery).toRelativeTimeString()}`
        : 'No recent activity'
    }
  };
}

3. Performance Monitoring

Monitor webhook performance and detect issues:

async function analyzeWebhookPerformance(webhookId) {
  const webhook = await fetchWebhook(webhookId);
  const stats = webhook.delivery_stats;
  
  const analysis = {
    id: webhookId,
    name: webhook.name,
    isActive: webhook.isActive,
    metrics: {
      totalEvents: stats.total_events,
      successfulDeliveries: stats.successful_deliveries,
      failedDeliveries: stats.failed_deliveries,
      successRate: stats.total_events > 0 
        ? (stats.successful_deliveries / stats.total_events * 100)
        : 0,
      failureRate: stats.total_events > 0 
        ? (stats.failed_deliveries / stats.total_events * 100)
        : 0
    },
    status: 'unknown',
    recommendations: []
  };
  
  // Determine status and recommendations
  if (!webhook.isActive) {
    analysis.status = 'inactive';
    analysis.recommendations.push('Webhook is inactive - activate to receive events');
  } else if (stats.total_events === 0) {
    analysis.status = 'no_activity';
    analysis.recommendations.push('No events sent yet - webhook is ready but unused');
  } else if (analysis.metrics.failureRate > 20) {
    analysis.status = 'critical';
    analysis.recommendations.push('High failure rate detected - check endpoint health');
    analysis.recommendations.push('Verify webhook URL is accessible and returning 2xx responses');
  } else if (analysis.metrics.failureRate > 5) {
    analysis.status = 'warning';
    analysis.recommendations.push('Moderate failure rate - monitor endpoint performance');
  } else {
    analysis.status = 'healthy';
    analysis.recommendations.push('Webhook is performing well');
  }
  
  return analysis;
}

4. Webhook Troubleshooting

Gather information for troubleshooting webhook issues:

async function troubleshootWebhook(webhookId) {
  try {
    const webhook = await fetchWebhook(webhookId);
    
    const troubleshooting = {
      webhook: {
        id: webhook.id,
        name: webhook.name,
        url: webhook.url,
        isActive: webhook.isActive,
        encrypted: webhook.encrypted
      },
      issues: [],
      suggestions: []
    };
    
    // Check for common issues
    if (!webhook.isActive) {
      troubleshooting.issues.push('Webhook is disabled');
      troubleshooting.suggestions.push('Enable webhook to receive events');
    }
    
    if (webhook.delivery_stats.failed_deliveries > 0) {
      const failureRate = (webhook.delivery_stats.failed_deliveries / webhook.delivery_stats.total_events) * 100;
      troubleshooting.issues.push(`${webhook.delivery_stats.failed_deliveries} failed deliveries (${failureRate.toFixed(1)}% failure rate)`);
      troubleshooting.suggestions.push('Check if webhook endpoint is accessible');
      troubleshooting.suggestions.push('Verify endpoint returns 2xx HTTP status codes');
      troubleshooting.suggestions.push('Check for network connectivity issues');
    }
    
    if (!webhook.url.startsWith('https://')) {
      troubleshooting.issues.push('Webhook URL is not using HTTPS');
      troubleshooting.suggestions.push('Use HTTPS for webhook URLs in production');
    }
    
    // Check if webhook hasn't received events recently
    if (webhook.delivery_stats.last_delivery) {
      const lastDelivery = new Date(webhook.delivery_stats.last_delivery);
      const hoursSinceLastDelivery = (Date.now() - lastDelivery.getTime()) / (1000 * 60 * 60);
      
      if (hoursSinceLastDelivery > 24) {
        troubleshooting.issues.push(`No events delivered in ${Math.floor(hoursSinceLastDelivery)} hours`);
        troubleshooting.suggestions.push('Check if events are being triggered in your application');
      }
    }
    
    return troubleshooting;
  } catch (error) {
    return {
      webhook: null,
      issues: [`Failed to fetch webhook: ${error.message}`],
      suggestions: ['Verify webhook ID is correct', 'Check API credentials and permissions']
    };
  }
}

Integration ExamplesCopied!

React Component

import React, { useState, useEffect } from 'react';

function WebhookDetails({ webhookId }) {
  const [webhook, setWebhook] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (webhookId) {
      loadWebhook();
    }
  }, [webhookId]);

  const loadWebhook = async () => {
    try {
      setLoading(true);
      setError(null);
      
      const response = await fetch(`/api/v0/webhooks/${webhookId}`, {
        headers: {
          'x-client-key': process.env.REACT_APP_CLIENT_KEY,
          'x-client-secret': process.env.REACT_APP_CLIENT_SECRET
        }
      });

      if (!response.ok) {
        if (response.status === 404) {
          throw new Error('Webhook not found');
        }
        throw new Error(`Failed to load webhook: ${response.statusText}`);
      }

      const webhookData = await response.json();
      setWebhook(webhookData);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const getStatusColor = (isActive) => {
    return isActive ? '#28a745' : '#6c757d';
  };

  const getSuccessRate = (stats) => {
    if (stats.total_events === 0) return 'N/A';
    return `${((stats.successful_deliveries / stats.total_events) * 100).toFixed(1)}%`;
  };

  const getHealthStatus = (webhook) => {
    if (!webhook.isActive) return { status: 'Inactive', color: '#6c757d' };
    
    const stats = webhook.delivery_stats;
    if (stats.total_events === 0) return { status: 'No Activity', color: '#ffc107' };
    
    const failureRate = stats.failed_deliveries / stats.total_events;
    if (failureRate > 0.1) return { status: 'Unhealthy', color: '#dc3545' };
    if (failureRate > 0.05) return { status: 'Warning', color: '#fd7e14' };
    
    return { status: 'Healthy', color: '#28a745' };
  };

  if (loading) return <div className="loading">Loading webhook details...</div>;
  if (error) return <div className="error">Error: {error}</div>;
  if (!webhook) return <div className="not-found">Webhook not found</div>;

  const health = getHealthStatus(webhook);

  return (
    <div className="webhook-details">
      <div className="webhook-header">
        <h2>{webhook.name}</h2>
        <div className="status-badges">
          <span 
            className="status-badge"
            style={{ backgroundColor: getStatusColor(webhook.isActive) }}
          >
            {webhook.isActive ? 'Active' : 'Inactive'}
          </span>
          <span 
            className="health-badge"
            style={{ backgroundColor: health.color }}
          >
            {health.status}
          </span>
        </div>
      </div>

      <div className="webhook-info">
        <div className="info-section">
          <h3>Configuration</h3>
          <div className="info-grid">
            <div className="info-item">
              <label>ID:</label>
              <span className="monospace">{webhook.id}</span>
            </div>
            <div className="info-item">
              <label>URL:</label>
              <span className="url">{webhook.url}</span>
            </div>
            <div className="info-item">
              <label>Encrypted:</label>
              <span>{webhook.encrypted ? 'Yes' : 'No'}</span>
            </div>
            <div className="info-item">
              <label>Created:</label>
              <span>{new Date(webhook.created_at).toLocaleString()}</span>
            </div>
            <div className="info-item">
              <label>Last Updated:</label>
              <span>{new Date(webhook.updated_at).toLocaleString()}</span>
            </div>
          </div>
        </div>

        <div className="info-section">
          <h3>Delivery Statistics</h3>
          <div className="stats-grid">
            <div className="stat-item">
              <div className="stat-value">{webhook.delivery_stats.total_events}</div>
              <div className="stat-label">Total Events</div>
            </div>
            <div className="stat-item">
              <div className="stat-value">{webhook.delivery_stats.successful_deliveries}</div>
              <div className="stat-label">Successful</div>
            </div>
            <div className="stat-item">
              <div className="stat-value">{webhook.delivery_stats.failed_deliveries}</div>
              <div className="stat-label">Failed</div>
            </div>
            <div className="stat-item">
              <div className="stat-value">{getSuccessRate(webhook.delivery_stats)}</div>
              <div className="stat-label">Success Rate</div>
            </div>
            <div className="stat-item">
              <div className="stat-value">
                {webhook.delivery_stats.last_delivery 
                  ? new Date(webhook.delivery_stats.last_delivery).toLocaleDateString()
                  : 'Never'
                }
              </div>
              <div className="stat-label">Last Delivery</div>
            </div>
          </div>
        </div>
      </div>

      <div className="webhook-actions">
        <button onClick={loadWebhook} className="btn-secondary">
          Refresh
        </button>
        <button 
          onClick={() => window.open(`/webhooks/${webhook.id}/edit`, '_blank')}
          className="btn-primary"
        >
          Edit Webhook
        </button>
      </div>
    </div>
  );
}

Python Service

import requests
from typing import Dict, Any, Optional
from datetime import datetime, timedelta

class WebhookInspector:
    def __init__(self, client_key: str, client_secret: str, base_url: str):
        self.client_key = client_key
        self.client_secret = client_secret
        self.base_url = base_url
        
    def _get_headers(self) -> Dict[str, str]:
        return {
            'x-client-key': self.client_key,
            'x-client-secret': self.client_secret
        }
    
    def get_webhook(self, webhook_id: str) -> Optional[Dict[str, Any]]:
        """Fetch a specific webhook by ID"""
        try:
            response = requests.get(
                f"{self.base_url}/api/v0/webhooks/{webhook_id}",
                headers=self._get_headers()
            )
            
            if response.status_code == 200:
                return response.json()
            elif response.status_code == 404:
                return None
            else:
                response.raise_for_status()
                
        except requests.exceptions.RequestException as e:
            print(f"Error fetching webhook {webhook_id}: {e}")
            raise
    
    def analyze_webhook_health(self, webhook_id: str) -> Dict[str, Any]:
        """Analyze webhook health and performance"""
        webhook = self.get_webhook(webhook_id)
        
        if not webhook:
            return {
                'webhook_id': webhook_id,
                'status': 'not_found',
                'health_score': 0,
                'issues': ['Webhook not found'],
                'recommendations': ['Verify webhook ID is correct']
            }
        
        stats = webhook['delivery_stats']
        issues = []
        recommendations = []
        health_score = 100  # Start with perfect score
        
        # Check if webhook is active
        if not webhook['isActive']:
            issues.append('Webhook is inactive')
            recommendations.append('Activate webhook to receive events')
            health_score -= 50
        
        # Check delivery success rate
        if stats['total_events'] > 0:
            failure_rate = stats['failed_deliveries'] / stats['total_events']
            
            if failure_rate > 0.2:  # > 20% failure rate
                issues.append(f"High failure rate: {failure_rate*100:.1f}%")
                recommendations.append('Check endpoint availability and response codes')
                health_score -= 30
            elif failure_rate > 0.05:  # > 5% failure rate
                issues.append(f"Moderate failure rate: {failure_rate*100:.1f}%")
                recommendations.append('Monitor endpoint performance')
                health_score -= 15
        
        # Check for recent activity
        if stats['last_delivery']:
            last_delivery = datetime.fromisoformat(stats['last_delivery'].replace('Z', '+00:00'))
            hours_since_last = (datetime.now().astimezone() - last_delivery).total_seconds() / 3600
            
            if hours_since_last > 48:
                issues.append(f"No activity for {int(hours_since_last)} hours")
                recommendations.append('Verify events are being triggered')
                health_score -= 10
        
        # Check URL security
        if not webhook['url'].startswith('https://'):
            issues.append('Using insecure HTTP protocol')
            recommendations.append('Use HTTPS for webhook URLs')
            health_score -= 10
        
        # Determine overall status
        if health_score >= 90:
            status = 'excellent'
        elif health_score >= 70:
            status = 'good'
        elif health_score >= 50:
            status = 'warning'
        else:
            status = 'critical'
        
        return {
            'webhook_id': webhook_id,
            'webhook_name': webhook['name'],
            'status': status,
            'health_score': max(0, health_score),
            'is_active': webhook['isActive'],
            'encrypted': webhook['encrypted'],
            'total_events': stats['total_events'],
            'success_rate': (stats['successful_deliveries'] / max(stats['total_events'], 1)) * 100,
            'failure_rate': (stats['failed_deliveries'] / max(stats['total_events'], 1)) * 100,
            'last_delivery': stats['last_delivery'],
            'issues': issues,
            'recommendations': recommendations
        }
    
    def get_webhook_summary(self, webhook_id: str) -> Dict[str, Any]:
        """Get a summary of webhook information"""
        webhook = self.get_webhook(webhook_id)
        
        if not webhook:
            return {
                'found': False,
                'webhook_id': webhook_id
            }
        
        stats = webhook['delivery_stats']
        
        return {
            'found': True,
            'webhook_id': webhook['id'],
            'name': webhook['name'],
            'url': webhook['url'],
            'is_active': webhook['isActive'],
            'encrypted': webhook['encrypted'],
            'created_at': webhook['created_at'],
            'updated_at': webhook['updated_at'],
            'performance': {
                'total_events': stats['total_events'],
                'successful_deliveries': stats['successful_deliveries'],
                'failed_deliveries': stats['failed_deliveries'],
                'success_rate_percent': (stats['successful_deliveries'] / max(stats['total_events'], 1)) * 100,
                'last_delivery': stats['last_delivery']
            }
        }

# Usage
inspector = WebhookInspector('your-key', 'your-secret', 'https://api.devdraft.com')

# Get webhook details
webhook = inspector.get_webhook('wh_123456789')
if webhook:
    print(f"Webhook: {webhook['name']}")
    print(f"Status: {'Active' if webhook['isActive'] else 'Inactive'}")
    print(f"Total Events: {webhook['delivery_stats']['total_events']}")

# Analyze webhook health
health = inspector.analyze_webhook_health('wh_123456789')
print(f"Health Score: {health['health_score']}/100")
print(f"Status: {health['status']}")
if health['issues']:
    print("Issues:", ', '.join(health['issues']))

Node.js/Express Utility

const axios = require('axios');

class WebhookInspector {
  constructor(clientKey, clientSecret, baseUrl) {
    this.clientKey = clientKey;
    this.clientSecret = clientSecret;
    this.baseUrl = baseUrl;
  }

  async getWebhook(webhookId) {
    try {
      const response = await axios.get(
        `${this.baseUrl}/api/v0/webhooks/${webhookId}`,
        {
          headers: {
            'x-client-key': this.clientKey,
            'x-client-secret': this.clientSecret
          }
        }
      );

      return response.data;
    } catch (error) {
      if (error.response?.status === 404) {
        return null;
      }
      throw new Error(`Failed to fetch webhook: ${error.response?.data?.message || error.message}`);
    }
  }

  async validateWebhookEndpoint(webhook) {
    try {
      // Attempt to reach the webhook endpoint
      const response = await axios.head(webhook.url, {
        timeout: 10000,
        validateStatus: () => true // Don't throw on non-2xx status
      });

      return {
        reachable: response.status < 500,
        statusCode: response.status,
        responseTime: response.headers['x-response-time'] || 'unknown'
      };
    } catch (error) {
      return {
        reachable: false,
        error: error.code || error.message,
        statusCode: null
      };
    }
  }

  async getWebhookDiagnostics(webhookId) {
    const webhook = await this.getWebhook(webhookId);
    
    if (!webhook) {
      return {
        found: false,
        webhookId,
        error: 'Webhook not found'
      };
    }

    const stats = webhook.delivery_stats;
    const endpointCheck = await this.validateWebhookEndpoint(webhook);
    
    // Calculate metrics
    const totalEvents = stats.total_events;
    const successRate = totalEvents > 0 ? (stats.successful_deliveries / totalEvents) * 100 : 0;
    const failureRate = totalEvents > 0 ? (stats.failed_deliveries / totalEvents) * 100 : 0;
    
    // Determine health status
    let healthStatus = 'unknown';
    if (!webhook.isActive) {
      healthStatus = 'inactive';
    } else if (totalEvents === 0) {
      healthStatus = 'no-activity';
    } else if (failureRate > 20) {
      healthStatus = 'critical';
    } else if (failureRate > 5) {
      healthStatus = 'warning';
    } else {
      healthStatus = 'healthy';
    }

    return {
      found: true,
      webhook: {
        id: webhook.id,
        name: webhook.name,
        url: webhook.url,
        isActive: webhook.isActive,
        encrypted: webhook.encrypted,
        createdAt: webhook.created_at,
        updatedAt: webhook.updated_at
      },
      performance: {
        totalEvents,
        successfulDeliveries: stats.successful_deliveries,
        failedDeliveries: stats.failed_deliveries,
        successRate: Math.round(successRate * 100) / 100,
        failureRate: Math.round(failureRate * 100) / 100,
        lastDelivery: stats.last_delivery
      },
      health: {
        status: healthStatus,
        endpointReachable: endpointCheck.reachable,
        endpointStatus: endpointCheck.statusCode,
        lastChecked: new Date().toISOString()
      },
      recommendations: this.generateRecommendations(webhook, stats, endpointCheck)
    };
  }

  generateRecommendations(webhook, stats, endpointCheck) {
    const recommendations = [];

    if (!webhook.isActive) {
      recommendations.push('Activate webhook to start receiving events');
    }

    if (!endpointCheck.reachable) {
      recommendations.push('Webhook endpoint is not reachable - check URL and network connectivity');
    }

    if (stats.failed_deliveries > 0 && webhook.isActive) {
      const failureRate = (stats.failed_deliveries / stats.total_events) * 100;
      if (failureRate > 10) {
        recommendations.push('High failure rate detected - verify endpoint returns 2xx status codes');
      }
    }

    if (!webhook.url.startsWith('https://')) {
      recommendations.push('Use HTTPS for webhook URLs in production environments');
    }

    if (!webhook.encrypted && webhook.url.startsWith('https://')) {
      recommendations.push('Consider enabling payload encryption for additional security');
    }

    if (stats.last_delivery) {
      const lastDelivery = new Date(stats.last_delivery);
      const hoursSince = (Date.now() - lastDelivery.getTime()) / (1000 * 60 * 60);
      
      if (hoursSince > 24 && webhook.isActive) {
        recommendations.push('No recent activity - verify events are being triggered');
      }
    }

    if (recommendations.length === 0) {
      recommendations.push('Webhook is configured correctly and performing well');
    }

    return recommendations;
  }
}

module.exports = WebhookInspector;

// Usage example
const inspector = new WebhookInspector(
  process.env.CLIENT_KEY,
  process.env.CLIENT_SECRET,
  'https://api.devdraft.com'
);

// Express endpoint for webhook diagnostics
app.get('/webhooks/:id/diagnostics', async (req, res) => {
  try {
    const diagnostics = await inspector.getWebhookDiagnostics(req.params.id);
    res.json(diagnostics);
  } catch (error) {
    console.error('Webhook diagnostics error:', error);
    res.status(500).json({ error: error.message });
  }
});

Security ConsiderationsCopied!

Access Control

  • Only webhooks belonging to your authenticated application are accessible

  • API key scoping ensures proper authorization

  • No cross-application webhook access

Data Protection

  • Webhook delivery statistics don't include sensitive payload data

  • Signing secrets are not returned in API responses

  • Encrypted webhook configuration is indicated but encryption keys are not exposed

Best Practices

  • Always validate webhook ID format before making requests

  • Implement proper error handling for different response scenarios

  • Use HTTPS for webhook endpoints in production

  • Monitor webhook health regularly using this endpoint

Rate LimitingCopied!

This endpoint is subject to the standard API rate limits:

  • Production: 1000 requests per hour per API key

  • Development: 100 requests per hour per API key

Common Integration PatternsCopied!

1. Webhook Health Dashboard

Regular health checks for monitoring dashboards

2. Troubleshooting Tools

Detailed webhook inspection for support and debugging

3. Performance Analytics

Historical performance tracking and trend analysis

4. Configuration Management