evolution-api icon indicating copy to clipboard operation
evolution-api copied to clipboard

Import messages and contacts with date range

Open alohacrmchat opened this issue 10 months ago β€’ 3 comments

Currently, the Evolution API does not provide a way to retrieve messages and contacts based on a date range. This limits the ability to perform historical analysis and data synchronization for systems that need to maintain an interaction history.

It would be useful to have an endpoint that allows requesting messages and contacts filtered by date. A possible implementation for this feature could be:

Suggested Implementation:

  • A new endpoint, such as /messages/history and /contacts/history, that accepts date parameters (start_date and end_date).

Benefits:

  • Enables retrieving old messages without relying solely on real-time events.
  • Facilitates data migration and synchronization in external systems.
  • Reduces the need to store all messages locally for future queries.

If this functionality already exists in some way, please clarify how we can use it. Otherwise, this improvement would greatly enhance the scalability of the API.

Thank you! πŸš€

alohacrmchat avatar Mar 02 '25 04:03 alohacrmchat

I have a issue that will benefit from this solution. my chatwoot crashed but evolution API has been collecting the messages diligently behind the scene. When chatwoot came online, the messages were not imported and i have about 3 days of missing data.

yewkay avatar Mar 05 '25 05:03 yewkay

This would be so helpful!

Related issue on Baileys fetchMessageHistory method - use example

TiagoGouvea avatar Apr 10 '25 11:04 TiagoGouvea

I would be helpful for me too! ;)

rlabanca avatar May 29 '25 13:05 rlabanca

+1 here

the-rock avatar Jul 17 '25 22:07 the-rock

`# Adding fetchMessageHistory to Evolution API - Correct Implementation Guide

Based on the actual Evolution API repository structure, here's how to add the fetchMessageHistory functionality.

Actual Evolution API Structure

From the main.ts file and error traces, the real structure is:

src/
β”œβ”€β”€ api/
β”‚   β”œβ”€β”€ integrations/
β”‚   β”‚   β”œβ”€β”€ channel/
β”‚   β”‚   β”‚   └── whatsapp/
β”‚   β”‚   β”‚       └── whatsapp.baileys.service.ts
β”‚   β”‚   β”œβ”€β”€ chatbot/
β”‚   β”‚   β”œβ”€β”€ event/
β”‚   β”‚   β”‚   └── webhook/
β”‚   β”‚   └── rabbitmq/
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   └── index.router.ts
β”‚   β”œβ”€β”€ server.module.ts
β”‚   └── provider/
β”œβ”€β”€ config/
β”œβ”€β”€ docs/
└── main.ts

Step 1: Add the Method to the Baileys Service

File: src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

This is where you need to add the fetchMessageHistory method. Based on the error traces, this file already contains message handling logic.

// Add this method to the existing WhatsAppBaileysService class

public async fetchMessageHistory(data: {
  count: number;
  oldestMsgId: string;
  oldestMsgRemoteJid: string;
  oldestMsgFromMe?: boolean;
  oldestMsgTimestamp: number;
}): Promise<string> {
  try {
    // Validate that the client is connected
    if (!this.client || this.instance.connectionStatus !== 'open') {
      throw new Error('WhatsApp client is not connected');
    }

    // Create the message key object as Baileys expects it
    const oldestMsgKey = {
      id: data.oldestMsgId,
      remoteJid: data.oldestMsgRemoteJid,
      fromMe: data.oldestMsgFromMe || false
    };

    // Call the Baileys fetchMessageHistory function
    const messageId = await this.client.fetchMessageHistory(
      data.count,
      oldestMsgKey,
      data.oldestMsgTimestamp
    );

    this.logger.log(`Message history fetch requested with ID: ${messageId}`);
    
    return messageId;
  } catch (error) {
    this.logger.error('Error fetching message history:', error);
    throw new Error(`Failed to fetch message history: ${error.message}`);
  }
}

Step 2: Create DTO for Request Validation

File: src/api/dto/fetchMessageHistory.dto.ts (create this file)

import { IsBoolean, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class FetchMessageHistoryDto {
  @ApiProperty({
    description: 'Number of messages to fetch',
    example: 50,
    minimum: 1,
    maximum: 100
  })
  @IsNotEmpty()
  @IsNumber()
  count: number;

  @ApiProperty({
    description: 'ID of the oldest message as reference',
    example: 'BAE5F8D123456789'
  })
  @IsNotEmpty()
  @IsString()
  oldestMsgId: string;

  @ApiProperty({
    description: 'Remote JID of the oldest message',
    example: '[email protected]'
  })
  @IsNotEmpty()
  @IsString()
  oldestMsgRemoteJid: string;

  @ApiPropertyOptional({
    description: 'Whether the oldest message is from the user (true) or contact (false)',
    example: false,
    default: false
  })
  @IsOptional()
  @IsBoolean()
  oldestMsgFromMe?: boolean;

  @ApiProperty({
    description: 'Timestamp of the oldest message (Unix timestamp)',
    example: 1640995200
  })
  @IsNotEmpty()
  @IsNumber()
  oldestMsgTimestamp: number;
}

Step 3: Add Route to the Router

File: src/api/routes/index.router.ts

Look at how other routes are defined in this file and add the new route. Based on the sendText endpoint pattern:

// Add this to the existing router configuration
// This should be added where other message routes are defined

router.post('/message/fetchHistory/:instanceName', 
  // Add your middleware here (auth, validation, etc.)
  async (req, res) => {
    try {
      const { instanceName } = req.params;
      const data = req.body as FetchMessageHistoryDto;
      
      // Get the instance (this will depend on how instances are managed)
      const waMonitor = /* get your wa monitor instance */;
      const instance = waMonitor.waInstances[instanceName];
      
      if (!instance) {
        return res.status(404).json({
          error: 'Instance not found',
          message: `Instance ${instanceName} does not exist`
        });
      }

      // Call the service method
      const messageId = await instance.fetchMessageHistory(data);

      return res.status(200).json({
        success: true,
        messageId,
        message: 'Message history fetch initiated successfully',
        data: {
          count: data.count,
          oldestMsgId: data.oldestMsgId,
          oldestMsgRemoteJid: data.oldestMsgRemoteJid,
          oldestMsgTimestamp: data.oldestMsgTimestamp
        }
      });
    } catch (error) {
      console.error('Error in fetchMessageHistory route:', error);
      
      return res.status(500).json({
        error: 'Internal server error',
        message: error.message
      });
    }
  }
);

Step 4: Alternative Implementation Using Express Router Pattern

If the routing follows a more traditional Express pattern, create a dedicated router file:

File: src/api/routes/message.router.ts (if this doesn't exist, create it)

import { Router } from 'express';
import { validate } from 'class-validator';
import { FetchMessageHistoryDto } from '../dto/fetchMessageHistory.dto';

const messageRouter = Router();

messageRouter.post('/fetchHistory/:instanceName', async (req, res) => {
  try {
    const { instanceName } = req.params;
    
    // Validate DTO
    const dto = Object.assign(new FetchMessageHistoryDto(), req.body);
    const errors = await validate(dto);
    
    if (errors.length > 0) {
      return res.status(400).json({
        error: 'Validation failed',
        details: errors
      });
    }

    // Your implementation here following the pattern used in Evolution API
    
  } catch (error) {
    return res.status(500).json({
      error: 'Internal server error',
      message: error.message
    });
  }
});

export { messageRouter };

Step 5: Add to Swagger Documentation

File: src/docs/swagger.conf.ts

Add the endpoint documentation following the existing pattern in this file:

// Add to the existing swagger configuration
{
  "/message/fetchHistory/{instanceName}": {
    "post": {
      "tags": ["Message"],
      "summary": "Fetch message history from WhatsApp",
      "parameters": [
        {
          "name": "instanceName",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Name of the WhatsApp instance"
        }
      ],
      "requestBody": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/FetchMessageHistoryDto"
            }
          }
        }
      },
      "responses": {
        "200": {
          "description": "Message history fetch initiated successfully"
        },
        "400": {
          "description": "Bad request"
        },
        "404": {
          "description": "Instance not found"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    }
  }
}

Step 6: Update Types and Interfaces

File: src/types/message.types.ts (create if it doesn't exist)

export interface IMessageHistoryRequest {
  count: number;
  oldestMsgId: string;
  oldestMsgRemoteJid: string;
  oldestMsgFromMe?: boolean;
  oldestMsgTimestamp: number;
}

export interface IMessageHistoryResponse {
  success: boolean;
  messageId: string;
  message: string;
  data: IMessageHistoryRequest;
}

Important Implementation Notes

  1. Instance Management: Study how other endpoints get the WhatsApp instance. Look at existing endpoints like sendText to understand the pattern.

  2. Authentication: Follow the same authentication pattern used by other endpoints (likely API key validation).

  3. Error Handling: Use the same error handling pattern as other endpoints in the codebase.

  4. Validation: Use the same validation middleware used by other endpoints.

  5. Logging: Follow the logging pattern used throughout the codebase.

Usage Example

Once implemented, you can use it like this:

curl --request POST \
  --url https://your-server.com/message/fetchHistory/your-instance \
  --header 'Content-Type: application/json' \
  --header 'apikey: your-api-key' \
  --data '{
    "count": 50,
    "oldestMsgId": "BAE5F8D123456789",
    "oldestMsgRemoteJid": "[email protected]",
    "oldestMsgFromMe": false,
    "oldestMsgTimestamp": 1640995200
  }'

Python Client Example

import requests

def fetch_message_history(base_url, api_key, instance_name, count, oldest_msg_id, 
                         oldest_msg_remote_jid, oldest_msg_timestamp, oldest_msg_from_me=False):
    url = f"{base_url}/message/fetchHistory/{instance_name}"
    
    headers = {
        'Content-Type': 'application/json',
        'apikey': api_key
    }
    
    payload = {
        "count": count,
        "oldestMsgId": oldest_msg_id,
        "oldestMsgRemoteJid": oldest_msg_remote_jid,
        "oldestMsgFromMe": oldest_msg_from_me,
        "oldestMsgTimestamp": oldest_msg_timestamp
    }
    
    response = requests.post(url, headers=headers, json=payload)
    
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"API call failed: {response.status_code} - {response.text}")

# Usage
try:
    result = fetch_message_history(
        base_url="https://your-evolution-api.com",
        api_key="your-api-key",
        instance_name="your-instance",
        count=50,
        oldest_msg_id="BAE5F8D123456789",
        oldest_msg_remote_jid="[email protected]",
        oldest_msg_timestamp=1640995200
    )
    print(f"Message history fetch initiated: {result['messageId']}")
except Exception as e:
    print(f"Error: {e}")

Next Steps

  1. Study the Codebase: Look at how sendText and other message endpoints are implemented
  2. Follow the Pattern: Use the same architecture and patterns as existing endpoints
  3. Test Thoroughly: Test with different message types and scenarios
  4. Add Tests: Create unit tests following the existing test structure
  5. Submit PR: Once working, submit a pull request to help the community

This implementation exposes the Baileys fetchMessageHistory function through Evolution API's REST interface, maintaining consistency with the existing codebase architecture. `

the-rock avatar Jul 17 '25 23:07 the-rock

@the-rock posting a claude solution doesn't help so much. The best would be run the code locally, test it and submit as a pull request.

TiagoGouvea avatar Jul 21 '25 11:07 TiagoGouvea

Segundo a doc do Baileys se passarmos uma info de Desktop na opΓ§Γ£o browser, pode pegar mais mensagens

Image

O Evolution estΓ‘ usando o padrΓ£o https://github.com/EvolutionAPI/evolution-api/blob/9cdb897a0fb1b3c2391699d2df053abd360229cf/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts#L534 Image

SerΓ‘ que podemos ter um resultado diferente?

sfiorotti avatar Aug 05 '25 22:08 sfiorotti

Is this already implemented? It's been marked as completed but I can't find how to do it.

yewkay avatar Oct 08 '25 08:10 yewkay