curl -X POST "https://server.smartlead.ai/api/v1/master-inbox/unread-replies?api_key=YOUR_KEY&fetch_message_history=false" \
-H "Content-Type: application/json" \
-d '{
"offset": 0,
"limit": 20,
"filters": {
"emailStatus": "Replied",
"campaignId": [12345, 12346],
"leadCategories": {
"categoryIdsIn": [1]
}
},
"sortBy": "REPLY_TIME_DESC"
}'
{
"messages": [
{
"id": "msg_unread_123",
"campaign_lead_map_id": "2433664091",
"lead": {
"email": "john@enterprise.com",
"first_name": "John",
"last_name": "Smith",
"company": "Enterprise Corp"
},
"campaign": {
"id": 12345,
"name": "Q1 Enterprise Outreach"
},
"email_account": {
"id": 789,
"email": "sales@yourcompany.com"
},
"last_message": {
"id": "email_abc789",
"subject": "Re: Demo Request",
"body": "Hi, thanks for reaching out. I'd like to schedule a demo for next week...",
"received_at": "2025-01-20T09:15:00Z",
"sent_from": "john@enterprise.com",
"sent_to": "sales@yourcompany.com"
},
"email_status": "Replied",
"category": {
"id": 2,
"name": "Meeting Request"
},
"assigned_to": {
"id": 456,
"name": "Jane Smith"
},
"is_read": false,
"is_important": true,
"tags": ["enterprise", "demo-request"],
"reply_age_hours": 2.5
}
],
"total_count": 1,
"offset": 0,
"limit": 20
}
Retrieve all unread replies from leads to ensure no important responses are missed
curl -X POST "https://server.smartlead.ai/api/v1/master-inbox/unread-replies?api_key=YOUR_KEY&fetch_message_history=false" \
-H "Content-Type: application/json" \
-d '{
"offset": 0,
"limit": 20,
"filters": {
"emailStatus": "Replied",
"campaignId": [12345, 12346],
"leadCategories": {
"categoryIdsIn": [1]
}
},
"sortBy": "REPLY_TIME_DESC"
}'
{
"messages": [
{
"id": "msg_unread_123",
"campaign_lead_map_id": "2433664091",
"lead": {
"email": "john@enterprise.com",
"first_name": "John",
"last_name": "Smith",
"company": "Enterprise Corp"
},
"campaign": {
"id": 12345,
"name": "Q1 Enterprise Outreach"
},
"email_account": {
"id": 789,
"email": "sales@yourcompany.com"
},
"last_message": {
"id": "email_abc789",
"subject": "Re: Demo Request",
"body": "Hi, thanks for reaching out. I'd like to schedule a demo for next week...",
"received_at": "2025-01-20T09:15:00Z",
"sent_from": "john@enterprise.com",
"sent_to": "sales@yourcompany.com"
},
"email_status": "Replied",
"category": {
"id": 2,
"name": "Meeting Request"
},
"assigned_to": {
"id": 456,
"name": "Jane Smith"
},
"is_read": false,
"is_important": true,
"tags": ["enterprise", "demo-request"],
"reply_age_hours": 2.5
}
],
"total_count": 1,
"offset": 0,
"limit": 20
}
false: Only latest message (recommended for list views)true: Complete conversation thread (use for detail views)Show filters properties
Show leadCategories properties
Opened, Clicked, Replied, Unsubscribed, Bounced, Accepted, Not RepliedNote: For unread endpoint, typically use Replied status12345[12345, 12346, 12347] (max 5 campaigns)789[789, 790, 791, ...] (max 10 accounts)456[456, 457, 458] (max 10 members)5[5, 6, 7] (max 10 tags)100[100, 101, 102] (max 10 clients)["start_datetime", "end_datetime"]Example: ["2025-01-01T00:00:00Z", "2025-01-31T23:59:59Z"]REPLY_TIME_DESC: Most recent replies first (default, recommended)SENT_TIME_DESC: Most recently sent emails firstcurl -X POST "https://server.smartlead.ai/api/v1/master-inbox/unread-replies?api_key=YOUR_KEY&fetch_message_history=false" \
-H "Content-Type: application/json" \
-d '{
"offset": 0,
"limit": 20,
"filters": {
"emailStatus": "Replied",
"campaignId": [12345, 12346],
"leadCategories": {
"categoryIdsIn": [1]
}
},
"sortBy": "REPLY_TIME_DESC"
}'
limit > 20{
"messages": [
{
"id": "msg_unread_123",
"campaign_lead_map_id": "2433664091",
"lead": {
"email": "john@enterprise.com",
"first_name": "John",
"last_name": "Smith",
"company": "Enterprise Corp"
},
"campaign": {
"id": 12345,
"name": "Q1 Enterprise Outreach"
},
"email_account": {
"id": 789,
"email": "sales@yourcompany.com"
},
"last_message": {
"id": "email_abc789",
"subject": "Re: Demo Request",
"body": "Hi, thanks for reaching out. I'd like to schedule a demo for next week...",
"received_at": "2025-01-20T09:15:00Z",
"sent_from": "john@enterprise.com",
"sent_to": "sales@yourcompany.com"
},
"email_status": "Replied",
"category": {
"id": 2,
"name": "Meeting Request"
},
"assigned_to": {
"id": 456,
"name": "Jane Smith"
},
"is_read": false,
"is_important": true,
"tags": ["enterprise", "demo-request"],
"reply_age_hours": 2.5
}
],
"total_count": 1,
"offset": 0,
"limit": 20
}
def morning_inbox_check():
"""Start the day by processing unread replies"""
# Get all unread replies
payload = {
"filters": {"emailStatus": "Replied"},
"sortBy": "REPLY_TIME_DESC",
"limit": 20
}
response = get_unread_replies(payload)
unread = response.get('messages', [])
print(f"📬 Good morning! You have {len(unread)} unread replies\n")
# Categorize by priority
high_priority = [m for m in unread if m.get('is_important')]
interested = [m for m in unread
if m.get('category', {}).get('id') == 1]
print(f"🔥 {len(high_priority)} high-priority")
print(f"👍 {len(interested)} interested leads")
print(f"📋 {len(unread) - len(high_priority) - len(interested)} general")
return unread
def get_unread_count(filters=None):
"""Quick unread count (no message content)"""
payload = {
"filters": filters or {"emailStatus": "Replied"},
"limit": 1 # Minimal data transfer
}
response = get_unread_replies(payload)
return response.get('total_count', 0)
# Usage for dashboard badge
total_unread = get_unread_count()
print(f"Unread badge: {total_unread}")
# By campaign
campaign_unread = get_unread_count({"campaignId": 12345})
print(f"Campaign 12345: {campaign_unread} unread")
def monitor_unread_sla(sla_hours=24):
"""Alert on unread replies exceeding SLA"""
from datetime import datetime, timedelta
sla_threshold = (datetime.now() - timedelta(hours=sla_hours)).isoformat() + 'Z'
payload = {
"filters": {
"emailStatus": "Replied",
"replyTimeBetween": [
"2000-01-01T00:00:00Z", # Beginning of time
sla_threshold
]
},
"sortBy": "REPLY_TIME_DESC",
"limit": 20
}
response = get_unread_replies(payload)
overdue = response.get('messages', [])
if overdue:
print(f"⚠️ SLA BREACH: {len(overdue)} unread replies over {sla_hours}h old")
for msg in overdue:
hours_old = (datetime.now() -
datetime.fromisoformat(msg['last_message']['received_at'].replace('Z', '+00:00'))).total_seconds() / 3600
print(f" - {msg['lead']['email']}: {hours_old:.1f}h old")
else:
print(f"✅ All unread replies within {sla_hours}h SLA")
return overdue
def triage_unread_replies():
"""Auto-categorize unread replies by urgency"""
payload = {
"filters": {"emailStatus": "Replied"},
"limit": 20
}
response = get_unread_replies(payload)
messages = response.get('messages', [])
triage = {
'urgent': [], # >24h old, important, or meeting request
'high': [], # Interested category or >12h old
'normal': [], # Everything else
'low': [] # Already categorized as not interested
}
from datetime import datetime
now = datetime.now()
for msg in messages:
hours_old = (now - datetime.fromisoformat(
msg['last_message']['received_at'].replace('Z', '+00:00')
)).total_seconds() / 3600
category_id = msg.get('category', {}).get('id')
is_important = msg.get('is_important', False)
if hours_old > 24 or is_important or category_id == 2:
triage['urgent'].append(msg)
elif category_id == 1 or hours_old > 12:
triage['high'].append(msg)
elif category_id == 3:
triage['low'].append(msg)
else:
triage['normal'].append(msg)
# Display triage results
print("\n📊 Unread Triage Report:")
print(f"🚨 Urgent: {len(triage['urgent'])} - Respond immediately")
print(f"⚠️ High: {len(triage['high'])} - Respond today")
print(f"📋 Normal: {len(triage['normal'])} - Respond within 24h")
print(f"⬇️ Low: {len(triage['low'])} - Can wait")
return triage
def batch_review_unread(limit=10):
"""Review and mark multiple unread as read"""
payload = {
"filters": {"emailStatus": "Replied"},
"sortBy": "REPLY_TIME_DESC",
"limit": limit
}
response = get_unread_replies(payload, fetch_history=True)
messages = response.get('messages', [])
for i, msg in enumerate(messages, 1):
print(f"\n[{i}/{len(messages)}] {msg['lead']['email']}")
print(f"Subject: {msg['last_message']['subject']}")
print(f"Preview: {msg['last_message']['body'][:100]}...")
# Show full thread if available
if msg.get('message_history'):
print(f"Thread: {len(msg['message_history'])} messages")
# Prompt for action (in real app, this would be UI)
action = input("Action [r]ead / [c]ategorize / [s]kip: ")
if action == 'r':
# Mark as read using change-read-status endpoint
mark_as_read(msg['campaign_lead_map_id'])
print("✅ Marked as read")
elif action == 'c':
category = input("Category ID: ")
update_category(msg['campaign_lead_map_id'], int(category))
mark_as_read(msg['campaign_lead_map_id'])
print("✅ Categorized and marked as read")
# Today's unread (highest priority)
today_unread = {
"filters": {
"emailStatus": "Replied",
"replyTimeBetween": [
datetime.now().replace(hour=0, minute=0).isoformat() + 'Z',
datetime.now().isoformat() + 'Z'
]
}
}
# This week's unread
week_start = (datetime.now() - timedelta(days=7)).isoformat() + 'Z'
week_unread = {
"filters": {
"emailStatus": "Replied",
"replyTimeBetween": [week_start, datetime.now().isoformat() + 'Z']
}
}
# Hot unread leads (interested or meeting requests)
hot_unread = {
"filters": {
"emailStatus": "Replied",
"leadCategories": {
"categoryIdsIn": [1, 2] # Interested, Meeting Request
}
}
}
# Unread but not junk
quality_unread = {
"filters": {
"emailStatus": "Replied",
"leadCategories": {
"categoryIdsNotIn": [3, 4] # Exclude Not Interested, Do Not Contact
}
}
}
# My team's unread
my_team_ids = [456, 457, 458]
team_unread = {
"filters": {
"emailStatus": "Replied",
"campaignTeamMemberId": my_team_ids
}
}
# Unassigned unread (needs triage)
unassigned_unread = {
"filters": {
"emailStatus": "Replied",
"leadCategories": {"unassigned": True}
}
}
# High-value campaign unread
important_campaign_unread = {
"filters": {
"emailStatus": "Replied",
"campaignId": [12345, 12346], # Enterprise campaigns
"campaignTagId": 5 # VIP tag
}
}
import time
def monitor_unread_realtime(interval=60):
"""Monitor unread count in real-time"""
previous_count = 0
while True:
current_count = get_unread_count()
if current_count != previous_count:
if current_count > previous_count:
new_replies = current_count - previous_count
print(f"🔔 {new_replies} new unread reply(ies)! Total: {current_count}")
# Fetch the new ones
payload = {
"filters": {"emailStatus": "Replied"},
"limit": new_replies
}
new_messages = get_unread_replies(payload)
# Notify team
for msg in new_messages.get('messages', []):
send_notification(f"New reply from {msg['lead']['email']}")
else:
print(f"✅ Unread count decreased to {current_count}")
previous_count = current_count
time.sleep(interval) # Check every minute
def send_unread_to_slack(webhook_url):
"""Send unread summary to Slack"""
unread = get_unread_count()
if unread > 0:
# Get details
payload = {"filters": {"emailStatus": "Replied"}, "limit": 5}
messages = get_unread_replies(payload).get('messages', [])
slack_message = {
"text": f"📬 You have {unread} unread replies",
"blocks": [
{
"type": "section",
"text": {"type": "mrkdwn", "text": f"*{unread} Unread Replies*"}
}
]
}
# Add top 5
for msg in messages:
slack_message["blocks"].append({
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"• *{msg['lead']['email']}*\n _{msg['last_message']['subject']}_"
}
})
requests.post(webhook_url, json=slack_message)
def get_unread_dashboard_data():
"""Get unread data for dashboard display"""
total = get_unread_count()
# Get breakdown by category
interested = get_unread_count({"leadCategories": {"categoryIdsIn": [1]}})
meeting = get_unread_count({"leadCategories": {"categoryIdsIn": [2]}})
uncategorized = get_unread_count({"leadCategories": {"unassigned": True}})
# Get age breakdown
today = get_unread_count({
"replyTimeBetween": [
datetime.now().replace(hour=0, minute=0).isoformat() + 'Z',
datetime.now().isoformat() + 'Z'
]
})
return {
"total": total,
"by_category": {
"interested": interested,
"meeting_request": meeting,
"uncategorized": uncategorized
},
"by_age": {
"today": today,
"older": total - today
}
}