> ## Documentation Index
> Fetch the complete documentation index at: https://www.docs.wazap.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Querying Stored Messages

> Query, search, and analyze stored WhatsApp messages and conversations

## Overview

Once storage is enabled, the SDK provides powerful methods to query and analyze your WhatsApp messages. This guide covers all available query methods with practical examples.

<Note>
  Make sure you've completed the [Supabase Integration](/storage/supabase-integration) setup before using these methods.
</Note>

***

## Get Conversation History

Retrieve all messages from a conversation with a specific phone number.

### Method Signature

```typescript theme={null}
client.getConversation(
  phoneNumber: string,
  options?: {
    limit?: number;
    offset?: number;
    dateFrom?: Date;
    dateTo?: Date;
  }
): Promise<ConversationResult>
```

### Basic Usage

```typescript theme={null}
// Get last 50 messages
const conversation = await client.getConversation('+1234567890', {
  limit: 50,
  offset: 0
});

console.log(`Total messages: ${conversation.totalMessages}`);
console.log(`Returned: ${conversation.messages.length}`);

// Display messages
conversation.messages.forEach(msg => {
  const direction = msg.direction === 'incoming' ? '📩' : '📤';
  const content = msg.content.text || `[${msg.message_type}]`;
  console.log(`${direction} ${content}`);
});
```

### With Date Range

```typescript theme={null}
// Get messages from last 7 days
const lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);

const recentConversation = await client.getConversation('+1234567890', {
  dateFrom: lastWeek,
  dateTo: new Date(),
  limit: 100
});

console.log(`Messages from last week: ${recentConversation.messages.length}`);
```

### Pagination

```typescript theme={null}
async function getAllMessages(phoneNumber: string) {
  const allMessages = [];
  const pageSize = 100;
  let offset = 0;
  let hasMore = true;

  while (hasMore) {
    const result = await client.getConversation(phoneNumber, {
      limit: pageSize,
      offset: offset
    });

    allMessages.push(...result.messages);
    offset += pageSize;
    hasMore = result.messages.length === pageSize;
  }

  return allMessages;
}

// Usage
const allMessages = await getAllMessages('+1234567890');
console.log(`Total messages retrieved: ${allMessages.length}`);
```

### Response Structure

```typescript theme={null}
interface ConversationResult {
  phoneNumber: string;
  totalMessages: number;
  messages: Array<{
    id: string;
    whatsappMessageId: string;
    fromPhone: string;
    toPhone: string;
    message_type: string;
    content: {
      text?: string;
      caption?: string;
      // ... other fields based on type
    };
    direction: 'incoming' | 'outgoing';
    status: 'sent' | 'delivered' | 'read' | 'failed';
    timestamp: Date;
    metadata: Record<string, any>;
  }>;
}
```

***

## Search Messages

Search for messages containing specific text across all conversations or within a specific conversation.

### Method Signature

```typescript theme={null}
client.searchMessages(options: {
  text: string;
  phoneNumber?: string;
  messageType?: string;
  dateFrom?: Date;
  dateTo?: Date;
  limit?: number;
  offset?: number;
}): Promise<SearchResult>
```

### Basic Search

```typescript theme={null}
// Search for "order" across all conversations
const results = await client.searchMessages({
  text: 'order',
  limit: 20
});

console.log(`Found ${results.total} messages containing "order"`);

results.messages.forEach(msg => {
  console.log(`From: ${msg.fromPhone}`);
  console.log(`Text: ${msg.content.text}`);
  console.log(`Date: ${msg.timestamp}`);
  console.log('---');
});
```

### Search Within Conversation

```typescript theme={null}
// Search for "invoice" in a specific conversation
const invoiceMessages = await client.searchMessages({
  text: 'invoice',
  phoneNumber: '+1234567890',
  limit: 50
});

console.log(`Found ${invoiceMessages.total} invoice messages`);
```

### Search by Message Type

```typescript theme={null}
// Find all image messages containing "receipt"
const receiptImages = await client.searchMessages({
  text: 'receipt',
  messageType: 'image',
  limit: 10
});

// Find all document messages
const documents = await client.searchMessages({
  text: '', // Empty string matches all
  messageType: 'document',
  limit: 100
});
```

### Search with Date Range

```typescript theme={null}
// Search for "payment" in messages from January 2024
const januaryPayments = await client.searchMessages({
  text: 'payment',
  dateFrom: new Date('2024-01-01'),
  dateTo: new Date('2024-01-31'),
  limit: 50
});
```

### Advanced Search Example

```typescript theme={null}
// Search for order-related messages in the last month
async function searchRecentOrders(customerPhone: string) {
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const results = await client.searchMessages({
    text: 'ORDER-', // Matches ORDER-12345, ORDER-67890, etc.
    phoneNumber: customerPhone,
    dateFrom: thirtyDaysAgo,
    limit: 100
  });

  // Extract order numbers from messages
  const orderNumbers = results.messages
    .map(msg => {
      const match = msg.content.text?.match(/ORDER-\d+/);
      return match ? match[0] : null;
    })
    .filter(Boolean);

  return [...new Set(orderNumbers)]; // Remove duplicates
}

// Usage
const orders = await searchRecentOrders('+1234567890');
console.log('Recent orders:', orders);
```

***

## Get Message Thread

Retrieve all replies to a specific message, useful for tracking conversation context.

### Method Signature

```typescript theme={null}
client.getMessageThread(
  messageId: string
): Promise<MessageThread | null>
```

### Basic Usage

```typescript theme={null}
// Get thread for a specific message
const thread = await client.getMessageThread('message_id_here');

if (thread) {
  console.log('Original message:', thread.originalMessage.content.text);
  console.log(`Replies: ${thread.replies.length}`);

  thread.replies.forEach((reply, index) => {
    console.log(`Reply ${index + 1}: ${reply.content.text}`);
  });
} else {
  console.log('No thread found');
}
```

### Track Support Tickets

```typescript theme={null}
async function getSupportThreadDetails(ticketMessageId: string) {
  const thread = await client.getMessageThread(ticketMessageId);

  if (!thread) {
    return null;
  }

  return {
    originalIssue: thread.originalMessage.content.text,
    customerPhone: thread.originalMessage.fromPhone,
    totalReplies: thread.replies.length,
    resolved: thread.replies.some(r =>
      r.content.text?.toLowerCase().includes('resolved')
    ),
    lastReply: thread.replies[thread.replies.length - 1],
    timeline: thread.replies.map(r => ({
      from: r.fromPhone,
      text: r.content.text,
      timestamp: r.timestamp
    }))
  };
}

// Usage
const ticketDetails = await getSupportThreadDetails('msg_123');
console.log('Support ticket:', ticketDetails);
```

***

## Get Conversation Analytics

Analyze conversation patterns, response rates, and engagement metrics.

### Method Signature

```typescript theme={null}
client.getConversationAnalytics(
  phoneNumber: string,
  options?: {
    from?: Date;
    to?: Date;
  }
): Promise<ConversationAnalytics>
```

### Basic Usage

```typescript theme={null}
const analytics = await client.getConversationAnalytics('+1234567890', {
  from: new Date('2024-01-01'),
  to: new Date()
});

console.log('Analytics:', {
  totalMessages: analytics.totalMessages,
  incomingMessages: analytics.incomingMessages,
  outgoingMessages: analytics.outgoingMessages,
  averageResponseTime: analytics.averageResponseTime,
  responseRate: analytics.responseRate
});
```

### Response Structure

```typescript theme={null}
interface ConversationAnalytics {
  phoneNumber: string;
  totalMessages: number;
  incomingMessages: number;
  outgoingMessages: number;
  firstMessageAt: Date;
  lastMessageAt: Date;
  averageResponseTime: number; // in milliseconds
  responseRate: number; // percentage (0-100)
  messagesByType: Record<string, number>;
  messagesByDay: Array<{
    date: string;
    count: number;
  }>;
}
```

### Calculate Customer Satisfaction

```typescript theme={null}
async function calculateCustomerSatisfaction(phoneNumber: string) {
  const analytics = await client.getConversationAnalytics(phoneNumber);

  // Fast response time (< 5 minutes) = good satisfaction
  const avgResponseMinutes = analytics.averageResponseTime / 1000 / 60;

  let satisfaction: 'Excellent' | 'Good' | 'Fair' | 'Poor';

  if (avgResponseMinutes < 5) {
    satisfaction = 'Excellent';
  } else if (avgResponseMinutes < 30) {
    satisfaction = 'Good';
  } else if (avgResponseMinutes < 120) {
    satisfaction = 'Fair';
  } else {
    satisfaction = 'Poor';
  }

  return {
    satisfaction,
    avgResponseMinutes: Math.round(avgResponseMinutes),
    totalConversations: analytics.totalMessages,
    responseRate: analytics.responseRate
  };
}

// Usage
const satisfaction = await calculateCustomerSatisfaction('+1234567890');
console.log('Customer satisfaction:', satisfaction);
```

### Team Performance Dashboard

```typescript theme={null}
async function getTeamPerformance(customerPhones: string[]) {
  const performanceData = await Promise.all(
    customerPhones.map(async (phone) => {
      const analytics = await client.getConversationAnalytics(phone, {
        from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // Last 7 days
      });

      return {
        customer: phone,
        messages: analytics.totalMessages,
        responseTime: analytics.averageResponseTime,
        responseRate: analytics.responseRate
      };
    })
  );

  // Calculate team averages
  const teamAvg = {
    totalMessages: performanceData.reduce((sum, p) => sum + p.messages, 0),
    avgResponseTime: performanceData.reduce((sum, p) => sum + p.responseTime, 0) / performanceData.length,
    avgResponseRate: performanceData.reduce((sum, p) => sum + p.responseRate, 0) / performanceData.length
  };

  return {
    individual: performanceData,
    team: teamAvg
  };
}
```

***

## Export Conversation

Export conversation data for backup, compliance, or analysis purposes.

### Method Signature

```typescript theme={null}
client.exportConversation(
  phoneNumber: string,
  options?: {
    format?: 'json' | 'csv';
    dateFrom?: Date;
    dateTo?: Date;
  }
): Promise<ExportResult>
```

### JSON Export

```typescript theme={null}
// Export as JSON
const jsonExport = await client.exportConversation('+1234567890', {
  format: 'json'
});

console.log('Export data:', jsonExport.data);
console.log('Message count:', jsonExport.messageCount);

// Save to file
import fs from 'fs';
fs.writeFileSync(
  'conversation-export.json',
  JSON.stringify(jsonExport.data, null, 2)
);
```

### CSV Export

```typescript theme={null}
// Export as CSV
const csvExport = await client.exportConversation('+1234567890', {
  format: 'csv'
});

// CSV string ready for download
console.log(csvExport.data);

// Save to file
import fs from 'fs';
fs.writeFileSync('conversation-export.csv', csvExport.data);
```

### Export with Date Range

```typescript theme={null}
// Export Q1 2024 messages
const q1Export = await client.exportConversation('+1234567890', {
  format: 'json',
  dateFrom: new Date('2024-01-01'),
  dateTo: new Date('2024-03-31')
});

console.log(`Exported ${q1Export.messageCount} messages from Q1 2024`);
```

### Automated Daily Backups

```typescript theme={null}
async function dailyBackup(customerPhones: string[]) {
  const today = new Date().toISOString().split('T')[0];

  for (const phone of customerPhones) {
    const export = await client.exportConversation(phone, {
      format: 'json',
      dateFrom: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours
      dateTo: new Date()
    });

    if (export.messageCount > 0) {
      const filename = `backup-${phone}-${today}.json`;
      fs.writeFileSync(filename, JSON.stringify(export.data));
      console.log(`✅ Backed up ${export.messageCount} messages to ${filename}`);
    }
  }
}

// Run daily
dailyBackup(['+1234567890', '+0987654321']);
```

***

## Advanced Query Patterns

### Multi-Customer Search

```typescript theme={null}
async function searchAcrossCustomers(
  customerPhones: string[],
  searchText: string
) {
  const results = await Promise.all(
    customerPhones.map(async (phone) => {
      const messages = await client.searchMessages({
        text: searchText,
        phoneNumber: phone,
        limit: 10
      });

      return {
        phone,
        matchCount: messages.total,
        matches: messages.messages
      };
    })
  );

  // Filter customers with matches
  return results.filter(r => r.matchCount > 0);
}

// Usage
const matches = await searchAcrossCustomers(
  ['+1234567890', '+0987654321'],
  'urgent'
);
```

### Time-Based Analysis

```typescript theme={null}
async function getHourlyMessageDistribution(phoneNumber: string) {
  const conversation = await client.getConversation(phoneNumber, {
    dateFrom: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // Last 7 days
  });

  const hourlyDistribution = Array(24).fill(0);

  conversation.messages.forEach(msg => {
    const hour = new Date(msg.timestamp).getHours();
    hourlyDistribution[hour]++;
  });

  return hourlyDistribution.map((count, hour) => ({
    hour: `${hour}:00`,
    messageCount: count
  }));
}

// Usage
const distribution = await getHourlyMessageDistribution('+1234567890');
console.log('Peak hours:', distribution.filter(h => h.messageCount > 10));
```

### Customer Segmentation

```typescript theme={null}
async function segmentCustomersByActivity(customerPhones: string[]) {
  const segments = {
    active: [],      // > 50 messages in last 30 days
    moderate: [],    // 10-50 messages
    inactive: []     // < 10 messages
  };

  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  for (const phone of customerPhones) {
    const analytics = await client.getConversationAnalytics(phone, {
      from: thirtyDaysAgo
    });

    if (analytics.totalMessages > 50) {
      segments.active.push(phone);
    } else if (analytics.totalMessages >= 10) {
      segments.moderate.push(phone);
    } else {
      segments.inactive.push(phone);
    }
  }

  return segments;
}
```

***

## Performance Tips

### 1. Use Pagination

Always paginate large result sets:

```typescript theme={null}
// Good
const page1 = await client.getConversation(phone, { limit: 50, offset: 0 });
const page2 = await client.getConversation(phone, { limit: 50, offset: 50 });

// Avoid
const all = await client.getConversation(phone, { limit: 10000 });
```

### 2. Filter by Date

Narrow down queries with date ranges:

```typescript theme={null}
// Good - specific date range
const recent = await client.searchMessages({
  text: 'order',
  dateFrom: new Date('2024-01-01'),
  dateTo: new Date('2024-01-31')
});

// Avoid - searching all history
const all = await client.searchMessages({ text: 'order' });
```

### 3. Cache Frequent Queries

```typescript theme={null}
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getCachedAnalytics(phoneNumber: string) {
  const cached = cache.get(phoneNumber);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const analytics = await client.getConversationAnalytics(phoneNumber);

  cache.set(phoneNumber, {
    data: analytics,
    timestamp: Date.now()
  });

  return analytics;
}
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Supabase Setup" icon="database" href="/storage/supabase-integration">
    Set up Supabase storage integration
  </Card>

  <Card title="Best Practices" icon="star" href="/storage/best-practices">
    Learn storage best practices
  </Card>

  <Card title="Custom Adapters" icon="code" href="/storage/custom-adapters">
    Build custom storage adapters
  </Card>

  <Card title="Webhook System" icon="webhook" href="/webhooks/overview">
    Understand webhook integration
  </Card>
</CardGroup>
