Dashboard

Delete Lead

Permanently remove a lead from your workspace

DELETE
3 min read

⚠️ Permanent Action

This action cannot be undone. The lead and all associated data will be permanently deleted.

What gets deleted:

  • • Lead's personal information (name, email, phone)
  • • All custom metadata and notes
  • • Lead history and timestamps
  • • Any integrations or webhooks associated with this lead

💡 Consider alternatives:

  • • Update status to "lost" instead of deleting
  • • Archive leads by adding metadata flags
  • • Export lead data before deletion for backup

Endpoint Details

Permanently delete a lead by ID

HTTP Method & URL

DELETE ${baseUrl}/api/v1/leads/{leadId}

Path Parameters

leadId

The unique identifier of the lead to delete (required)

string

Response

Confirmation of successful deletion

Success Response (200 OK)

{
  "success": true,
  "message": "Lead deleted successfully",
  "data": {
    "id": "lead_1234567890abcdef",
    "deletedAt": "2024-01-16T15:45:00.000Z"
  }
}

Response Fields

id

ID of the deleted lead

deletedAt

ISO timestamp of deletion

After Deletion

Lead cannot be retrieved
All data is permanently removed
ID cannot be reused

Code Examples

Safe implementation patterns for lead deletion

cURL

curl -X DELETE "https://your-domain.com/api/v1/leads/lead_1234567890abcdef" \
  -H "Authorization: Bearer sk-workspace_your_api_key"

JavaScript (with confirmation)

const deleteLead = async (leadId, confirmationRequired = true) => {
  // Optional: Get lead info first for confirmation
  if (confirmationRequired) {
    try {
      const leadResponse = await fetch(`https://your-domain.com/api/v1/leads/${leadId}`, {
        headers: {
          'Authorization': 'Bearer sk-workspace_your_api_key',
          'Content-Type': 'application/json'
        }
      });
      
      if (!leadResponse.ok) {
        throw new Error('Lead not found');
      }
      
      const leadData = await leadResponse.json();
      const lead = leadData.data;
      
      // Show confirmation dialog
      const confirmed = confirm(
        `Are you sure you want to delete lead "${lead.name}" (${lead.email})? \n\n` +
        `This action cannot be undone.`
      );
      
      if (!confirmed) {
        return null;
      }
    } catch (error) {
      console.error('Error fetching lead for confirmation:', error);
      throw error;
    }
  }
  
  // Proceed with deletion
  try {
    const response = await fetch(`https://your-domain.com/api/v1/leads/${leadId}`, {
      method: 'DELETE',
      headers: {
        'Authorization': 'Bearer sk-workspace_your_api_key',
        'Content-Type': 'application/json'
      }
    });

    if (!response.ok) {
      if (response.status === 404) {
        throw new Error('Lead not found or already deleted');
      }
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const result = await response.json();
    return result.data;
  } catch (error) {
    console.error('Error deleting lead:', error);
    throw error;
  }
};

// Usage examples
const leadId = "lead_1234567890abcdef";

// With confirmation
deleteLead(leadId, true);

// Without confirmation (for bulk operations)
deleteLead(leadId, false);

// Bulk deletion with error handling
const bulkDeleteLeads = async (leadIds) => {
  const results = { success: [], failed: [] };
  
  for (const leadId of leadIds) {
    try {
      await deleteLead(leadId, false);
      results.success.push(leadId);
    } catch (error) {
      results.failed.push({ leadId, error: error.message });
    }
  }
  return results;
};

Python (with backup)

import requests
import json
from datetime import datetime
from typing import Dict, Optional

def backup_lead_data(api_key: str, lead_id: str) -> Optional[Dict]:
    """Backup lead data before deletion."""
    url = f"https://your-domain.com/api/v1/leads/{lead_id}"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    
    try:
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            lead_data = response.json()['data']
            
            # Save to backup file
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"lead_backup_{lead_id}_{timestamp}.json"
            
            with open(filename, 'w') as f:
                json.dump(lead_data, f, indent=2)
            
            print(f"Lead data backed up to: {filename}")
            return lead_data
        else:
            print(f"Could not backup lead {lead_id}: {response.status_code}")
            return None
    except Exception as e:
        print(f"Backup failed: {e}")
        return None

def delete_lead(api_key: str, lead_id: str, backup_first: bool = True) -> bool:
    """
    Delete a lead with optional backup.
    
    Args:
        api_key: Your API key
        lead_id: The lead's unique identifier
        backup_first: Whether to backup data before deletion
        
    Returns:
        bool: True if deletion was successful
    """
    # Backup first if requested
    if backup_first:
        backup_data = backup_lead_data(api_key, lead_id)
        if backup_data:
            print(f"Backed up lead: {backup_data['name']} ({backup_data['email']})")
    
    url = f"https://your-domain.com/api/v1/leads/{lead_id}"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    
    try:
        response = requests.delete(url, headers=headers)
        
        if response.status_code == 404:
            print(f"Lead {lead_id} not found or already deleted")
            return False
            
        response.raise_for_status()
        
        result = response.json()
        print(f"Lead deleted successfully: {result['data']['id']}")
        print(f"Deleted at: {result['data']['deletedAt']}")
        
        return True
    except requests.exceptions.RequestException as e:
        print(f"Error deleting lead: {e}")
        return False

def delete_leads_by_status(api_key: str, status: str, confirm: bool = True) -> Dict:
    """Delete all leads with a specific status."""
    if confirm:
        response = input(f"Delete ALL leads with status '{status}'? (yes/no): ")
        if response.lower() != 'yes':
            print("Operation cancelled")
            return {"deleted": 0, "errors": []}
    
    # First, get all leads with the status
    list_url = f"https://your-domain.com/api/v1/leads?status={status}&limit=100"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    
    try:
        response = requests.get(list_url, headers=headers)
        response.raise_for_status()
        
        leads_data = response.json()['data']
        leads = leads_data['leads']
        
        print(f"Found {len(leads)} leads with status '{status}'")
        
        results = {"deleted": 0, "errors": []}
        
        for lead in leads:
            try:
                if delete_lead(api_key, lead['id'], backup_first=True):
                    results["deleted"] += 1
            except Exception as e:
                results["errors"].append({
                    "lead_id": lead['id'],
                    "error": str(e)
                })
        
        print(f"Bulk deletion complete: {results['deleted']} deleted, {len(results['errors'])} errors")
        return results
        
    except Exception as e:
        print(f"Error in bulk deletion: {e}")
        return {"deleted": 0, "errors": [str(e)]}

# Usage examples
api_key = "sk-workspace_your_api_key"
lead_id = "lead_1234567890abcdef"

# Delete single lead with backup
delete_lead(api_key, lead_id, backup_first=True)

# Delete without backup
delete_lead(api_key, lead_id, backup_first=False)

# Bulk delete lost leads
delete_leads_by_status(api_key, "lost", confirm=True)

Deletion Best Practices

Safe and responsible lead deletion strategies

✓ Before Deleting

Confirm with user:

Show lead details and ask for confirmation

Backup data:

Export or save lead information locally

Check dependencies:

Verify no active campaigns or processes depend on this lead

💡 Alternatives

Status update:

Change status to "lost" instead of deleting

Archive flag:

Add archived: true to metadata

Data anonymization:

Remove PII while keeping analytics data

Archiving Alternative

Instead of deletion, you can archive leads by updating their metadata:

// Archive instead of delete
const archiveLead = async (leadId) => {
  const response = await fetch(`https://your-domain.com/api/v1/leads/${leadId}`, {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer sk-workspace_your_api_key',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      status: 'lost',
      metadata: {
        archived: true,
        archived_at: new Date().toISOString(),
        archived_reason: 'No longer interested'
      }
    })
  });
  
  return response.json();
};

Error Scenarios

Handle deletion errors gracefully

404 Not Found

{
  "success": false,
  "error": "Lead not found",
  "code": "LEAD_NOT_FOUND",
  "details": {
    "leadId": "lead_nonexistent123",
    "message": "No lead found with this ID in your workspace"
  }
}
This could mean: Lead doesn't exist, already deleted, belongs to different workspace, or invalid ID format.

⚠️ Handle Carefully

404 may indicate already deleted
Don't retry deletion on 404
Log deletion attempts for audit

⚠️ Safety Checks

Verify lead exists first
Implement undo period if possible
Consider soft deletes for compliance
    PollyBot.ai - Smart Conversations, Seamless Automation