Skip to main content

Delete Webhook

Permanently delete a webhook subscription and stop all event deliveries to the specified endpoint.

Endpoint

HTTP Request

DELETE /webhooks/{webhook_id}
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Path Parameters

webhook_id

  • Type: String
  • Description: Unique identifier of the webhook to delete
  • Example: webhook_1234567890

Response Format

Success Response (200 OK)

{
  "id": "webhook_1234567890",
  "status": "deleted",
  "message": "Webhook deleted successfully",
  "deleted_at": "2024-01-15T10:30:00Z",
  "final_statistics": {
    "total_deliveries": 1250,
    "total_failures": 3,
    "success_rate": 99.76,
    "last_delivery_at": "2024-01-15T10:25:00Z"
  }
}

Error Response (404 Not Found)

{
  "error": "Webhook not found",
  "code": 404,
  "details": {
    "webhook_id": "webhook_invalid_id"
  },
  "timestamp": "2024-01-15T10:30:00Z",
  "requestId": "req_1234567890"
}

Error Response (409 Conflict)

{
  "error": "Webhook cannot be deleted while processing events",
  "code": 409,
  "details": {
    "reason": "Webhook has pending events",
    "retry_after": 30
  },
  "timestamp": "2024-01-15T10:30:00Z",
  "requestId": "req_1234567890"
}

Implementation Examples

JavaScript (Node.js)

const axios = require("axios");

async function deleteWebhook(apiKey, webhookId) {
  try {
    const response = await axios.delete(`https://scrape.st/webhooks/${webhookId}`, {
      headers: {
        "x-api-key": apiKey,
        "Content-Type": "application/json",
      },
    });

    const result = response.data;
    console.log(`Webhook ${webhookId} deleted successfully`);

    // Log final statistics
    logWebhookStatistics(webhookId, result.final_statistics);

    return result;
  } catch (error) {
    console.error(`Failed to delete webhook ${webhookId}:`, error.response?.data || error.message);
    throw error;
  }
}

function logWebhookStatistics(webhookId, stats) {
  console.log(`\n=== Final Statistics for ${webhookId} ===`);
  console.log(`Total Deliveries: ${stats.total_deliveries}`);
  console.log(`Total Failures: ${stats.total_failures}`);
  console.log(`Success Rate: ${stats.success_rate.toFixed(2)}%`);
  console.log(`Last Delivery: ${new Date(stats.last_delivery_at).toLocaleString()}`);
}

// Usage
deleteWebhook("your_api_key_here", "webhook_1234567890");

Python

import requests
from datetime import datetime

def delete_webhook(api_key, webhook_id):
    url = f"https://scrape.st/webhooks/{webhook_id}"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    try:
        response = requests.delete(url, headers=headers)
        response.raise_for_status()
        result = response.json()

        print(f"Webhook {webhook_id} deleted successfully")

        # Log final statistics
        log_webhook_statistics(webhook_id, result["final_statistics"])

        return result
    except requests.exceptions.RequestException as error:
        print(f"Failed to delete webhook {webhook_id}: {error}")
        if error.response:
            print(f"Error details: {error.response.text}")
        raise

def log_webhook_statistics(webhook_id, stats):
    print(f"\n=== Final Statistics for {webhook_id} ===")
    print(f"Total Deliveries: {stats['total_deliveries']}")
    print(f"Total Failures: {stats['total_failures']}")
    print(f"Success Rate: {stats['success_rate']:.2f}%")
    print(f"Last Delivery: {datetime.fromisoformat(stats['last_delivery_at'].replace('Z', '+00:00')).strftime('%Y-%m-%d %H:%M:%S')}")

# Usage
delete_webhook("your_api_key_here", "webhook_1234567890")

cURL

curl -X DELETE https://scrape.st/webhooks/webhook_1234567890 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Bulk Deletion

Delete Multiple Webhooks

async function deleteMultipleWebhooks(apiKey, webhookIds) {
  const results = [];

  for (const webhookId of webhookIds) {
    try {
      const result = await deleteWebhook(apiKey, webhookId);
      results.push({ webhookId, status: "success", result });
    } catch (error) {
      results.push({ webhookId, status: "error", error: error.message });
    }
  }

  return results;
}

// Usage
const webhookIds = ["webhook_123", "webhook_456", "webhook_789"];
const deletionResults = await deleteMultipleWebhooks("your_api_key_here", webhookIds);

console.log("Deletion Results:");
deletionResults.forEach((result) => {
  const status = result.status === "success" ? "✅" : "❌";
  console.log(`${status} ${result.webhookId}: ${result.status}`);
});

Conditional Deletion

async function deleteInactiveWebhooks(apiKey, inactiveDays = 30) {
  // First, list all webhooks
  const webhooks = await listWebhooks(apiKey);
  const cutoffDate = new Date(Date.now() - inactiveDays * 24 * 60 * 60 * 1000);

  const inactiveWebhooks = webhooks.data.filter((webhook) => {
    const lastDelivery = new Date(webhook.last_delivery_at);
    return !webhook.active || lastDelivery < cutoffDate;
  });

  console.log(`Found ${inactiveWebhooks.length} inactive webhooks`);

  // Delete inactive webhooks
  const results = await deleteMultipleWebhooks(
    apiKey,
    inactiveWebhooks.map((w) => w.id),
  );

  return results;
}

// Usage
deleteInactiveWebhooks("your_api_key_here", 30); // Delete webhooks inactive for 30+ days

Safety Measures

Confirmation Before Deletion

async function deleteWebhookWithConfirmation(apiKey, webhookId) {
  // Get webhook details first
  const webhooks = await listWebhooks(apiKey);
  const webhook = webhooks.data.find((w) => w.id === webhookId);

  if (!webhook) {
    throw new Error(`Webhook ${webhookId} not found`);
  }

  // Show webhook details for confirmation
  console.log(`\n=== Webhook Details ===`);
  console.log(`ID: ${webhook.id}`);
  console.log(`URL: ${webhook.url}`);
  console.log(`Events: ${webhook.events.join(", ")}`);
  console.log(`Status: ${webhook.status}`);
  console.log(`Deliveries: ${webhook.delivery_count}`);
  console.log(`Failures: ${webhook.failure_count}`);

  // Ask for confirmation (in interactive environments)
  const readline = require("readline");
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  return new Promise((resolve, reject) => {
    rl.question(`\nAre you sure you want to delete this webhook? (y/N): `, async (answer) => {
      rl.close();

      if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
        try {
          const result = await deleteWebhook(apiKey, webhookId);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      } else {
        console.log("Deletion cancelled");
        resolve({ cancelled: true });
      }
    });
  });
}

Backup Before Deletion

async function deleteWebhookWithBackup(apiKey, webhookId) {
  // Get webhook details before deletion
  const webhooks = await listWebhooks(apiKey);
  const webhook = webhooks.data.find((w) => w.id === webhookId);

  if (!webhook) {
    throw new Error(`Webhook ${webhookId} not found`);
  }

  // Create backup
  const backup = {
    webhook: webhook,
    deleted_at: new Date().toISOString(),
    deleted_by: "api_call",
  };

  // Store backup (implement your storage logic)
  await storeWebhookBackup(webhookId, backup);

  console.log(`Backup created for webhook ${webhookId}`);

  // Delete webhook
  return await deleteWebhook(apiKey, webhookId);
}

async function storeWebhookBackup(webhookId, backup) {
  // Implement your backup storage logic here
  // Could be database, file system, cloud storage, etc.
  console.log(`Storing backup for ${webhookId}...`);
  // Example: await db.collection('webhook_backups').insertOne(backup);
}

Error Handling

Conflict Resolution

async function deleteWebhookWithRetry(apiKey, webhookId, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await deleteWebhook(apiKey, webhookId);
    } catch (error) {
      if (error.response?.status === 409) {
        const retryAfter = error.response.data?.details?.retry_after || 30;
        console.log(`Webhook has pending events, waiting ${retryAfter} seconds...`);
        await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
        continue;
      }

      if (error.response?.status === 404) {
        throw new Error(`Webhook ${webhookId} not found`);
      }

      if (attempt === maxRetries) {
        throw error;
      }

      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
}

Graceful Error Handling

async function safeDeleteWebhook(apiKey, webhookId) {
  try {
    const result = await deleteWebhook(apiKey, webhookId);
    console.log(`✅ Webhook ${webhookId} deleted successfully`);
    return result;
  } catch (error) {
    if (error.response?.status === 404) {
      console.log(`ℹ️ Webhook ${webhookId} not found (may already be deleted)`);
      return { notFound: true };
    }

    if (error.response?.status === 409) {
      console.log(`⚠️ Webhook ${webhookId} cannot be deleted right now`);
      return { conflict: true, error: error.message };
    }

    console.error(`❌ Failed to delete webhook ${webhookId}:`, error.message);
    throw error;
  }
}

Monitoring and Auditing

Deletion Audit Log

class WebhookAuditLogger {
  constructor() {
    this.deletionLog = [];
  }

  logDeletion(webhookId, result, deletedBy = "api") {
    const logEntry = {
      webhookId,
      deletedAt: new Date().toISOString(),
      deletedBy,
      success: result.status === "deleted",
      finalStatistics: result.final_statistics,
      error: result.error || null,
    };

    this.deletionLog.push(logEntry);

    // Store in persistent storage
    this.storeAuditLog(logEntry);

    console.log(`Audit log: Webhook ${webhookId} deletion logged`);
  }

  async storeAuditLog(logEntry) {
    // Implement your audit storage logic
    // Could be database, logging service, etc.
    console.log("Storing audit log entry:", logEntry);
  }

  getDeletionHistory(webhookId = null) {
    if (webhookId) {
      return this.deletionLog.filter((entry) => entry.webhookId === webhookId);
    }
    return this.deletionLog;
  }
}

// Usage
const auditLogger = new WebhookAuditLogger();

async function deleteWebhookWithAudit(apiKey, webhookId) {
  try {
    const result = await deleteWebhook(apiKey, webhookId);
    auditLogger.logDeletion(webhookId, result);
    return result;
  } catch (error) {
    auditLogger.logDeletion(webhookId, { error: error.message, status: "failed" });
    throw error;
  }
}

Best Practices

Before Deletion

  • Verify Webhook: Confirm webhook ID and current status
  • Check Dependencies: Ensure no processes depend on the webhook
  • Backup Data: Create backup of webhook configuration and statistics
  • Notify Teams: Inform relevant teams about planned deletion

During Deletion

  • Handle Conflicts: Implement retry logic for temporary conflicts
  • Log Operations: Maintain audit trail of all deletions
  • Monitor Impact: Watch for any system impact from deletion
  • Grace Period: Consider soft deletion before permanent removal

After Deletion

  • Verify Cleanup: Confirm all webhook data is removed
  • Update Documentation: Update any documentation referencing the webhook
  • Monitor Systems: Watch for unexpected behavior after deletion
  • Review Patterns: Analyze deletion patterns for optimization
Next: Tracking Introduction