Skip to main content

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 the requests 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")