Skip to main content

Endpoint

GET /backend/conversations/stream
This endpoint uses Server-Sent Events (SSE) for real-time communication.

Connection

const eventSource = new EventSource(
  'https://api.leavo.ai/backend/conversations/stream',
  {
    headers: {
      'Authorization': 'Bearer your_api_key_here'
    }
  }
);

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Event received:', data);
};

eventSource.onerror = (error) => {
  console.error('Connection error:', error);
};

Event Types

new_message

New message received or sent.
{
  "type": "new_message",
  "data": {
    "conversation_id": "uuid",
    "message": {
      "id": "message-uuid",
      "content": "Hello!",
      "role": "user",
      "timestamp": "2024-01-15T14:30:00Z"
    }
  }
}

typing

Lead is typing.
{
  "type": "typing",
  "data": {
    "conversation_id": "uuid",
    "lead_id": "lead-uuid"
  }
}

status_change

Conversation status changed.
{
  "type": "status_change",
  "data": {
    "conversation_id": "uuid",
    "status": "archived"
  }
}

Best Practices

Reconnection

Implement automatic reconnection logic in case of disconnection.

Heartbeat

The server sends heartbeat events every 30 seconds to keep the connection alive.

Authentication

The token is validated on initial connection. Connections with invalid tokens are rejected.

Fallback

Have a fallback with periodic polling in case SSE is not supported.

Complete Example

class ConversationStream {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.eventSource = null;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
  }

  connect() {
    this.eventSource = new EventSource(
      `https://api.leavo.ai/backend/conversations/stream?token=${this.apiKey}`
    );

    this.eventSource.onopen = () => {
      console.log('Connected');
      this.reconnectAttempts = 0;
    };

    this.eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.handleEvent(data);
    };

    this.eventSource.onerror = () => {
      this.eventSource.close();
      this.reconnect();
    };
  }

  handleEvent(data) {
    switch (data.type) {
      case 'new_message':
        this.onNewMessage(data.data);
        break;
      case 'typing':
        this.onTyping(data.data);
        break;
    }
  }

  reconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      const delay = Math.pow(2, this.reconnectAttempts) * 1000;
      setTimeout(() => this.connect(), delay);
    }
  }

  disconnect() {
    if (this.eventSource) {
      this.eventSource.close();
    }
  }

  // Override these methods
  onNewMessage(data) {}
  onTyping(data) {}
}