Documentation Index
Fetch the complete documentation index at: https://docs.naturalead.ai/llms.txt
Use this file to discover all available pages before exploring further.
Python Examples
These examples use therequests library. Install it with pip install requests.
Setup
import os
import requests
API_KEY = os.environ["NATURALEAD_API_KEY"]
BASE_URL = "https://api.naturalead.ai/api"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
}
Lead Management
List all leads
response = requests.get(f"{BASE_URL}/leads", headers=headers)
leads = response.json()
for lead in leads:
print(f"#{lead['id']} {lead['name']} ({lead['status']})")
Create a lead
response = requests.post(
f"{BASE_URL}/leads",
headers=headers,
json={
"name": "Jane Smith",
"phone": "+14155551234",
"email": "[email protected]",
"tags": ["inbound", "demo"],
},
)
if response.status_code == 201:
lead = response.json()
print(f"Created lead #{lead['id']}")
elif response.status_code == 409:
print("Lead with this phone already exists")
else:
print(f"Error: {response.json()['error']}")
Search leads
response = requests.get(
f"{BASE_URL}/leads/search",
headers=headers,
params={"q": "john", "limit": 10},
)
results = response.json()
print(f"Found {len(results['leads'])} leads")
Bulk sync from CRM
response = requests.post(
f"{BASE_URL}/leads/sync",
headers=headers,
json={
"leads": [
{
"lead_id": "crm-001",
"name": "Alice Johnson",
"phone": "+14155551111",
"email": "[email protected]",
"custom_fields": {"company": "Acme Corp", "deal_size": "50000"},
},
{
"lead_id": "crm-002",
"name": "Bob Wilson",
"phone": "+14155552222",
},
]
},
)
result = response.json()
print(f"Created: {result['created']}, Updated: {result['updated']}, Failed: {result['failed']}")
if result["errors"]:
for error in result["errors"]:
print(f" Error for {error['lead_id']}: {error['error']}")
Conversations
Start a conversation
response = requests.post(
f"{BASE_URL}/conversations/start",
headers=headers,
json={"leadId": 1, "channel": "whatsapp"},
)
if response.status_code == 201:
conversation = response.json()
print(f"Conversation started: {conversation['_id']}")
elif response.status_code == 503:
print("Messaging not configured. Set up integration first.")
List active conversations
response = requests.get(
f"{BASE_URL}/conversations",
headers=headers,
params={"status": "active"},
)
conversations = response.json()
for conv in conversations:
print(f"{conv['_id']}: {conv['status']} ({len(conv.get('messages', []))} messages)")
Campaigns
Create and launch a campaign
# Create
response = requests.post(
f"{BASE_URL}/campaigns",
headers=headers,
json={
"name": "Q1 Outreach",
"agentConfigId": "AGENT_ID",
"channel": "whatsapp",
"leadFilter": {"statuses": ["new"], "tags": ["inbound"]},
"schedule": {
"rateLimit": 10,
"activeHours": {"start": "09:00", "end": "17:00", "timezone": "America/New_York"},
"activeDays": [1, 2, 3, 4, 5], # Monday-Friday
},
},
)
campaign = response.json()
campaign_id = campaign["_id"]
# Launch
response = requests.post(f"{BASE_URL}/campaigns/{campaign_id}/launch", headers=headers)
print(f"Campaign launched: {response.json()['status']}")
CSV Import
Two-step CSV import
csv_content = """Name,Phone,Email,Company
Jane Smith,+14155551234,[email protected],Acme Corp
Bob Jones,+14155555678,[email protected],Widget Inc"""
# Step 1: Preview
response = requests.post(
f"{BASE_URL}/leads/upload/preview",
headers=headers,
json={"content": csv_content},
)
preview = response.json()
print(f"Headers: {preview['headers']}")
print(f"Total rows: {preview['totalRows']}")
# Step 2: Confirm with mapping
response = requests.post(
f"{BASE_URL}/leads/upload/confirm",
headers=headers,
json={
"content": csv_content,
"mapping": {
"Name": "name",
"Phone": "phone",
"Email": "email",
"Company": "companyName", # becomes custom field
},
"tags": ["csv-import", "q1-2026"],
},
)
result = response.json()
print(f"Imported: {result['imported']}, Duplicates skipped: {result['duplicatesSkipped']}")
Rate Limit Handling
import time
def safe_request(method, path, max_retries=3, **kwargs):
for attempt in range(max_retries):
response = requests.request(
method,
f"{BASE_URL}{path}",
headers=headers,
**kwargs,
)
if response.status_code != 429:
return response
retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
print(f"Rate limited. Waiting {retry_after}s...")
time.sleep(retry_after)
raise Exception("Max retries exceeded")