Skip to main content
POST
/
api
/
v1
/
master-inbox
/
sent
curl -X POST "https://server.smartlead.ai/api/v1/master-inbox/sent?api_key=YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "offset": 0,
    "limit": 20,
    "filters": {
      "emailStatus": ["Replied", "Opened"],
      "campaignId": [12345, 12346],
      "leadCategories": {
        "categoryIdsIn": [1]
      },
      "replyTimeBetween": ["2025-01-01T00:00:00Z", "2025-01-31T23:59:59Z"]
    },
    "sortBy": "REPLY_TIME_DESC"
  }'
{
  "messages": [
    {
      "id": "msg_abc123",
      "campaign_lead_map_id": "2433664091",
      "lead": {
        "email": "john@company.com",
        "first_name": "John",
        "last_name": "Doe",
        "company": "ACME Corp"
      },
      "campaign": {
        "id": 12345,
        "name": "Q1 2025 Outreach"
      },
      "email_account": {
        "id": 789,
        "email": "sales@yourcompany.com"
      },
      "last_message": {
        "subject": "Partnership Opportunity",
        "sent_at": "2025-01-15T10:00:00Z",
        "opened_at": "2025-01-15T10:30:00Z",
        "replied_at": "2025-01-15T14:00:00Z"
      },
      "email_status": "Replied",
      "category": {
        "id": 1,
        "name": "Interested"
      },
      "assigned_to": {
        "id": 456,
        "name": "Jane Smith"
      },
      "stats": {
        "opens": 2,
        "clicks": 1,
        "replies": 1
      }
    }
  ],
  "total_count": 1,
  "offset": 0,
  "limit": 20
}
Track all sent emails across your campaigns. Monitor delivery, opens, clicks, and replies. Essential for campaign performance tracking and follow-up management.

Overview

Retrieves all sent emails from your account with comprehensive filtering options. This endpoint provides a unified view of all outreach activity across campaigns. Key Features:
  • Unified view of all sent emails across campaigns
  • Track email engagement (opens, clicks, replies)
  • Filter by campaign, email account, team member, tags, clients
  • Advanced lead category filtering
  • Date range filtering for reply tracking
  • Pagination and custom sorting
Common Use Cases:
  • Performance monitoring: Track which emails receive replies
  • Follow-up management: Find emails that haven’t received responses
  • Campaign analysis: Compare performance across campaigns
  • Team reporting: Filter by team member to track individual activity
  • Client reporting: Segment by client for account-specific insights

Query Parameters

api_key
string
required
Your SmartLead API key

Request Body

offset
number
default:"0"
Number of records to skip for pagination. Must be non-negative.
limit
number
default:"20"
Number of records to return per page. Must be between 1 and 20.
filters
object
Advanced filtering options to segment your sent emails
sortBy
string
default:"REPLY_TIME_DESC"
Sort order for results
  • REPLY_TIME_DESC: Most recent replies first (default, best for active conversations)
  • SENT_TIME_DESC: Most recently sent emails first (best for tracking recent outreach)
curl -X POST "https://server.smartlead.ai/api/v1/master-inbox/sent?api_key=YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "offset": 0,
    "limit": 20,
    "filters": {
      "emailStatus": ["Replied", "Opened"],
      "campaignId": [12345, 12346],
      "leadCategories": {
        "categoryIdsIn": [1]
      },
      "replyTimeBetween": ["2025-01-01T00:00:00Z", "2025-01-31T23:59:59Z"]
    },
    "sortBy": "REPLY_TIME_DESC"
  }'

Response Codes

200
Success
Request successful - sent emails retrieved
400
Bad Request
Invalid request parameters or malformed request body
401
Unauthorized
Invalid or missing API key. Check your authentication.
422
Validation Error
Request validation failed. Common issues:
  • limit > 20
  • Invalid emailStatus value
  • Array exceeds maximum length
  • Invalid date format in replyTimeBetween
500
Internal Server Error
Server error occurred. Please try again or contact support if the issue persists.
{
  "messages": [
    {
      "id": "msg_abc123",
      "campaign_lead_map_id": "2433664091",
      "lead": {
        "email": "john@company.com",
        "first_name": "John",
        "last_name": "Doe",
        "company": "ACME Corp"
      },
      "campaign": {
        "id": 12345,
        "name": "Q1 2025 Outreach"
      },
      "email_account": {
        "id": 789,
        "email": "sales@yourcompany.com"
      },
      "last_message": {
        "subject": "Partnership Opportunity",
        "sent_at": "2025-01-15T10:00:00Z",
        "opened_at": "2025-01-15T10:30:00Z",
        "replied_at": "2025-01-15T14:00:00Z"
      },
      "email_status": "Replied",
      "category": {
        "id": 1,
        "name": "Interested"
      },
      "assigned_to": {
        "id": 456,
        "name": "Jane Smith"
      },
      "stats": {
        "opens": 2,
        "clicks": 1,
        "replies": 1
      }
    }
  ],
  "total_count": 1,
  "offset": 0,
  "limit": 20
}

Common Workflows

Daily Reply Check

# Get all replies received today
from datetime import datetime

today_start = datetime.now().replace(hour=0, minute=0, second=0).isoformat() + 'Z'
now = datetime.now().isoformat() + 'Z'

payload = {
    "filters": {
        "emailStatus": "Replied",
        "replyTimeBetween": [today_start, now]
    },
    "sortBy": "REPLY_TIME_DESC"
}

Find Follow-up Opportunities

# Emails opened but not replied in last 3 days
three_days_ago = (datetime.now() - timedelta(days=3)).isoformat() + 'Z'

payload = {
    "filters": {
        "emailStatus": ["Opened", "Clicked"],
        "replyTimeBetween": [three_days_ago, now],
        "leadCategories": {
            "unassigned": True  # Not yet categorized
        }
    }
}

Campaign Performance Audit

# Get all campaign activity with engagement metrics
payload = {
    "filters": {
        "campaignId": [12345, 12346],
        "emailStatus": ["Replied", "Opened", "Clicked"]
    },
    "limit": 20
}

response = get_sent_emails(payload)

# Calculate metrics
total = response['total_count']
replied = len([m for m in response['messages'] 
               if m['email_status'] == 'Replied'])
reply_rate = (replied / total * 100) if total > 0 else 0

print(f"Reply rate: {reply_rate:.2f}%")

Team Member Activity

# Track individual team member performance
def get_member_sent_stats(member_id, start_date, end_date):
    payload = {
        "filters": {
            "campaignTeamMemberId": member_id,
            "replyTimeBetween": [start_date, end_date]
        },
        "limit": 20
    }
    
    response = get_sent_emails(payload)
    messages = response.get('messages', [])
    
    return {
        'total_sent': len(messages),
        'replied': len([m for m in messages if m['email_status'] == 'Replied']),
        'opened': len([m for m in messages if m['email_status'] in ['Opened', 'Clicked']])
    }

Filtering Best Practices

1. Start Broad, Then Narrow

# Step 1: Get all sent emails in campaign
basic_filter = {"campaignId": 12345}

# Step 2: Add engagement filter
engagement_filter = {
    "campaignId": 12345,
    "emailStatus": ["Replied", "Opened"]
}

# Step 3: Add category filter
interested_filter = {
    "campaignId": 12345,
    "emailStatus": ["Replied", "Opened"],
    "leadCategories": {"categoryIdsIn": [1]}
}

2. Combine Inclusion and Exclusion

# Get engaged leads, excluding "Do Not Contact"
filters = {
    "emailStatus": ["Replied", "Opened", "Clicked"],
    "leadCategories": {
        "categoryIdsNotIn": [4]  # Exclude Do Not Contact
    }
}

3. Use Date Ranges Effectively

# Rolling 30-day window
end_date = datetime.now()
start_date = end_date - timedelta(days=30)

filters = {
    "replyTimeBetween": [
        start_date.isoformat() + 'Z',
        end_date.isoformat() + 'Z'
    ]
}

4. Paginate Large Results

def get_all_sent_emails(filters):
    """Fetch all results across multiple pages"""
    all_messages = []
    offset = 0
    limit = 20
    
    while True:
        payload = {
            "filters": filters,
            "offset": offset,
            "limit": limit
        }
        
        response = get_sent_emails(payload)
        messages = response.get('messages', [])
        
        if not messages:
            break
            
        all_messages.extend(messages)
        offset += limit
        
        # Stop if we've fetched all records
        if offset >= response.get('total_count', 0):
            break
    
    return all_messages

Performance Optimization

  1. Use appropriate limits: Default of 20 balances speed and data volume
  2. Filter strategically: More specific filters = faster queries
  3. Avoid very large date ranges: Break into smaller chunks
  4. Cache results: Store frequently accessed data client-side
  5. Use specific campaign/account filters: Reduces query scope

Email Status Reference

StatusMeaningFollow-up Action
AcceptedEmail accepted by serverWait for open/reply
OpenedRecipient opened emailConsider follow-up
ClickedClicked link in emailHigh engagement - prioritize
RepliedSent a responseTake action immediately
Not RepliedOpened but no replySchedule follow-up
BouncedEmail failed to deliverVerify/remove address
UnsubscribedOpted outDo not contact