curl -X POST https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": "YOUR_CAMPAIGN_ID",
"leads": [
{ "externalId": "CRM_001" },
{ "externalId": "CRM_002" },
{ "externalId": "CRM_003" }
]
}'
const response = await fetch('https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
campaignId: 'YOUR_CAMPAIGN_ID',
leads: [
{ externalId: 'CRM_001' },
{ externalId: 'CRM_002' },
{ externalId: 'CRM_003' }
]
})
});
const data = await response.json();
import requests
response = requests.post(
'https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete',
headers={
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'campaignId': 'YOUR_CAMPAIGN_ID',
'leads': [
{'externalId': 'CRM_001'},
{'externalId': 'CRM_002'},
{'externalId': 'CRM_003'}
]
}
)
print(response.json())
{
"success": true,
"data": {
"deleted": 3,
"notFound": 0,
"deletedIdentifiers": [
"CRM_001",
"CRM_002",
"CRM_003"
],
"notFoundIdentifiers": []
},
"error": null
}
{
"success": true,
"data": {
"deleted": 2,
"notFound": 1,
"deletedIdentifiers": [
"CRM_001",
"+15555555678"
],
"notFoundIdentifiers": [
"CRM_003"
]
},
"error": null
}
{
"success": false,
"data": null,
"error": "leads[2]: At least one of phoneNumber or externalId is required"
}
Leads
Bulk Delete Leads
Delete multiple leads in a single request
POST
/
api
/
v1
/
leads
/
bulk-delete
curl -X POST https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": "YOUR_CAMPAIGN_ID",
"leads": [
{ "externalId": "CRM_001" },
{ "externalId": "CRM_002" },
{ "externalId": "CRM_003" }
]
}'
const response = await fetch('https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
campaignId: 'YOUR_CAMPAIGN_ID',
leads: [
{ externalId: 'CRM_001' },
{ externalId: 'CRM_002' },
{ externalId: 'CRM_003' }
]
})
});
const data = await response.json();
import requests
response = requests.post(
'https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete',
headers={
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'campaignId': 'YOUR_CAMPAIGN_ID',
'leads': [
{'externalId': 'CRM_001'},
{'externalId': 'CRM_002'},
{'externalId': 'CRM_003'}
]
}
)
print(response.json())
{
"success": true,
"data": {
"deleted": 3,
"notFound": 0,
"deletedIdentifiers": [
"CRM_001",
"CRM_002",
"CRM_003"
],
"notFoundIdentifiers": []
},
"error": null
}
{
"success": true,
"data": {
"deleted": 2,
"notFound": 1,
"deletedIdentifiers": [
"CRM_001",
"+15555555678"
],
"notFoundIdentifiers": [
"CRM_003"
]
},
"error": null
}
{
"success": false,
"data": null,
"error": "leads[2]: At least one of phoneNumber or externalId is required"
}
Endpoint Alias: You can also use
/api/v1/records/bulk-delete instead of /api/v1/leads/bulk-delete. Both endpoints are functionally identical - use whichever naming convention fits your integration.Why POST? This endpoint uses POST instead of DELETE because DELETE requests with a body are not universally supported by all HTTP clients and proxies.
Lead Lookup
Leads are identified byexternalId or phoneNumber, not internal IDs. Each entry in the leads array must have at least one identifier.
Each lead must have at least one of
phoneNumber or externalId. If both are provided, externalId takes priority for the lookup.Authentication
string
required
Your API key with
write scopeRequest Body
string
required
The ID of the campaign these leads belong to
array
required
Response
boolean
Whether the request was successful
object
string | null
Error message if request failed
Examples
- By External IDs
- By Phone Numbers
- Mixed
Delete multiple leads by external CRM references:
curl -X POST https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": "YOUR_CAMPAIGN_ID",
"leads": [
{ "externalId": "CRM_001" },
{ "externalId": "CRM_002" },
{ "externalId": "CRM_003" }
]
}'
const response = await fetch('https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
campaignId: 'YOUR_CAMPAIGN_ID',
leads: [
{ externalId: 'CRM_001' },
{ externalId: 'CRM_002' },
{ externalId: 'CRM_003' }
]
})
});
const data = await response.json();
import requests
response = requests.post(
'https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete',
headers={
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'campaignId': 'YOUR_CAMPAIGN_ID',
'leads': [
{'externalId': 'CRM_001'},
{'externalId': 'CRM_002'},
{'externalId': 'CRM_003'}
]
}
)
print(response.json())
Delete multiple leads by phone numbers:
curl -X POST https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": "YOUR_CAMPAIGN_ID",
"leads": [
{ "phoneNumber": "+15555551234" },
{ "phoneNumber": "+15555555678" },
{ "phoneNumber": "+15555559012" }
]
}'
const response = await fetch('https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
campaignId: 'YOUR_CAMPAIGN_ID',
leads: [
{ phoneNumber: '+15555551234' },
{ phoneNumber: '+15555555678' },
{ phoneNumber: '+15555559012' }
]
})
});
const data = await response.json();
import requests
response = requests.post(
'https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete',
headers={
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'campaignId': 'YOUR_CAMPAIGN_ID',
'leads': [
{'phoneNumber': '+15555551234'},
{'phoneNumber': '+15555555678'},
{'phoneNumber': '+15555559012'}
]
}
)
print(response.json())
Delete leads using a mix of identifiers:
curl -X POST https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": "YOUR_CAMPAIGN_ID",
"leads": [
{ "externalId": "CRM_001" },
{ "phoneNumber": "+15555555678" },
{ "externalId": "CRM_003", "phoneNumber": "+15555559012" }
]
}'
const response = await fetch('https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
campaignId: 'YOUR_CAMPAIGN_ID',
leads: [
{ externalId: 'CRM_001' },
{ phoneNumber: '+15555555678' },
{ externalId: 'CRM_003', phoneNumber: '+15555559012' }
]
})
});
const data = await response.json();
import requests
response = requests.post(
'https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads/bulk-delete',
headers={
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'campaignId': 'YOUR_CAMPAIGN_ID',
'leads': [
{'externalId': 'CRM_001'},
{'phoneNumber': '+15555555678'},
{'externalId': 'CRM_003', 'phoneNumber': '+15555559012'}
]
}
)
print(response.json())
{
"success": true,
"data": {
"deleted": 3,
"notFound": 0,
"deletedIdentifiers": [
"CRM_001",
"CRM_002",
"CRM_003"
],
"notFoundIdentifiers": []
},
"error": null
}
{
"success": true,
"data": {
"deleted": 2,
"notFound": 1,
"deletedIdentifiers": [
"CRM_001",
"+15555555678"
],
"notFoundIdentifiers": [
"CRM_003"
]
},
"error": null
}
{
"success": false,
"data": null,
"error": "leads[2]: At least one of phoneNumber or externalId is required"
}
Limits
Maximum Size: You can delete up to 1000 leads per bulk request. For larger deletions, make multiple requests.
Partial Success Handling
The bulk delete endpoint handles missing leads gracefully:- Validates campaign access - Ensures API key has write access to the specified campaign
- Processes each lead - Looks up by externalId first, then phoneNumber
- Tracks results - Records which leads were deleted vs not found
- Returns details - Provides identifiers for both outcomes
No Partial Rollback: If some leads are not found, the ones that exist will still be deleted. The operation does not fail entirely.
This makes bulk delete safe to retry - if a previous request partially succeeded, you can safely send the same request again without issues.
Notes
Permanent Deletion: This action cannot be undone. Leads will be permanently deleted.
Need the lead data? The delete response only returns identifiers and counts—not the full lead details. If you need lead information (metadata, status, etc.) before deletion, fetch the leads first using
GET /api/v1/leads, then delete them.Campaign Scope: All leads must belong to the specified campaign. Leads from other campaigns will appear in
notFoundIdentifiers.Common Errors
| Error | Cause | Solution |
|---|---|---|
campaignId is required | Missing campaignId | Include campaignId in request body |
leads array is required | Missing or invalid leads | Include leads array in request body |
leads array cannot be empty | Empty leads array | Add at least one lead to the array |
Maximum 1000 leads per bulk delete request | Too many leads | Split into multiple requests |
leads[N]: At least one of phoneNumber or externalId is required | Lead missing both identifiers | Each lead needs phoneNumber or externalId |
Invalid or inactive API key | Wrong API key | Check your API key |
Forbidden | API key doesn’t have campaign access | Verify campaignId and API key scope |
Best Practices
Batch Size
Batch Size
- Use 100-500 leads per request for optimal performance
- Don’t max out at 1000 unless necessary
- Monitor response times and adjust
Identifier Choice
Identifier Choice
- Use
externalIdwhen available - it’s more specific - Use
phoneNumberas fallback for leads without external IDs - Don’t mix identifiers for the same lead across requests
Error Handling
Error Handling
- Check the
deletedvsnotFoundcounts - Log
notFoundIdentifiersfor investigation - Retry failed requests with exponential backoff
Cleanup
Cleanup
- Consider archiving leads instead of deleting if audit trail is important
- Use bulk delete for cleaning up test data
- Run bulk deletes during off-peak hours for large datasets