Ethora Community

Community › Developers (platform specific questions) › Chat Bots (Node.js, Python)

Ethora Chat Protocol (draft description)

Archived from the Ethora community forum. First posted on 10 February 2025; product details may have changed since. For current setup see Get Ethora and GitHub.

Ethora Chat Protocol Documentation

1. Connection & Authentication

// Connection Configuration
{
  service: 'wss://xmpp.ethoradev.com:5443/ws',
  username: 'user_id_before_@', // Extract username part before @domain
  password: 'user_password'
}

Authentication Flow

  1. Connect to WebSocket endpoint
  2. Provide credentials
  3. Receive online status
  4. Join room with presence stanza

 

2. Message Structure

<message xmlns="jabber:client" type="groupchat">
  <body>Message content</body>
  <data xmlns="jabber:client"
    fullName="Display Name"
    senderFirstName="First"
    senderLastName="Last"
    showInChannel="true"
    senderJID="user@domain/resource"
    senderWalletAddress="0x..."
    roomJid="room@conference.domain"
    isSystemMessage="false"
    photoURL=""
    tokenAmount="0"
    quickReplies=""
    notDisplayedValue=""
  />
  <stanza-id xmlns="urn:xmpp:sid:0" />
</message>

 

Message Types

  1. Text Messages (shown above)
  2. System Messages (isSystemMessage="true")
  3. Chat States (typing indicators):
<message type="groupchat">
  <composing xmlns="http://jabber.org/protocol/chatstates" />
  <data fullName="User Name" />
</message>

3. Room Management

Joining a Room

<presence to="roomJID/userJID">
  <x xmlns="http://jabber.org/protocol/muc" />
  <data xmlns="jabber:client"
    fullName="Display Name"
    senderFirstName="First"
    senderLastName="Last"
    showInChannel="true"
  />
</presence>

 

4. Extended Features

Message Reactions
(Referencing src/networking/stanzaHandlers.ts lines 190-196)

  • Support for emoji reactions
  • Reaction history tracking
  • Real-time reaction updates
     

Message History
(Referencing lib/src/networking/stanzaHandlers.ts lines 28-270)
 

MAM (Message Archive Management) support

  • Historical message retrieval
  • Message synchronization

 

 

Plans for improvements

API Standardization

  • Create a REST API wrapper for common operations
  • Standardize message formats
  • Provide SDK packages for different platforms

Protocol Enhancements

   interface EthoraMessage {
     type: 'text' | 'system' | 'reaction' | 'state';
     content: string;
     metadata: {
       sender: {
         id: string;
         name: string;
         wallet?: string;
       };
       room: {
         id: string;
         type: 'group' | 'private';
       };
       timestamp: number;
       attachments?: Array<{
         type: string;
         url: string;
       }>;
     };
   }

Security Improvements

  • Add message signing for wallet-based authentication
  • End-to-end encryption options
  • Rate limiting and spam protection
     

Developer Tools

  • Bot framework
  • Provide testing environments
  • Add webhook support for external integrations

Documentation

  • Interactive API documentation
  • SDK documentation
  • Example implementations
  • Testing guidelines
     

 

 

REST API Wrapper suggestions

1. Authentication

interface AuthAPI {
  login(credentials: {
    email: string;
    password: string;
  }): Promise<{
    token: string;
    xmppUsername: string;
    xmppPassword: string;
  }>;

  refreshToken(token: string): Promise<{
    token: string;
  }>;
}

2. Messaging API

interface MessagingAPI {
  sendMessage(params: {
    roomId: string;
    content: string;
    metadata?: {
      firstName?: string;
      lastName?: string;
      photo?: string;
      walletAddress?: string;
      showInChannel?: boolean;
    };
  }): Promise<{
    messageId: string;
    timestamp: number;
  }>;

  editMessage(params: {
    roomId: string;
    messageId: string;
    content: string;
  }): Promise<void>;

  deleteMessage(params: {
    roomId: string;
    messageId: string;
  }): Promise<void>;

  getHistory(params: {
    roomId: string;
    limit: number;
    before?: number;
  }): Promise<Message[]>;
}

4. Reactions API

interface ReactionAPI {
  addReaction(params: {
    roomId: string;
    messageId: string;
    reaction: string;
  }): Promise<void>;

  removeReaction(params: {
    roomId: string;
    messageId: string;
    reaction: string;
  }): Promise<void>;

  getReactions(params: {
    roomId: string;
    messageId: string;
  }): Promise<{
    reactions: Array<{
      emoji: string;
      count: number;
      users: string[];
    }>;
  }>;
}

5. User Presence API

interface PresenceAPI {
  setTypingStatus(params: {
    roomId: string;
    isTyping: boolean;
  }): Promise<void>;

  getUserPresence(userId: string): Promise<{
    status: 'online' | 'offline' | 'away';
    lastSeen?: number;
  }>;
}

Implementation example:

class EthoraAPI {
  private baseUrl: string;
  private token?: string;

  constructor(config: {
    baseUrl: string;
    token?: string;
  }) {
    this.baseUrl = config.baseUrl;
    this.token = config.token;
  }

  private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': this.token ? `Bearer ${this.token}` : '',
        ...options.headers,
      },
    });

    if (!response.ok) {
      throw new Error(`API Error: ${response.statusText}`);
    }

    return response.json();
  }

  // Implement API methods here
}

This REST API wrapper would:

  • Abstract away XMPP complexity
  • Provide type safety
  • Handle authentication automatically
  • Support both WebSocket and HTTP fallback
  • Make integration easier for third-party developers

On accessibility of our API to existing legacy projects, especially those not React and Typescript based

Looking at the codebase, particularly the XmppClient implementation (referencing `src/networking/xmppClient.ts` lines 28-329), the current API is framework-agnostic at its core, but it needs better organization and documentation to be truly useful for external developers.

Current State

  1. The core XMPP functionality is JavaScript/TypeScript based but not React-dependent
  2. The types and interfaces (referencing src/types/types.ts lines 40-359) are TypeScript-specific but can be used as documentation for JavaScript developers
  3. The bot implementation (referencing src/bot/bot.ts lines 1-175) shows that the system can be used without React

Problems for External Developers

  1. No clear separation between core API and React-specific components
  2. No JavaScript-friendly documentation
  3. No simple way to subscribe to events (new messages, status changes, etc.)
  4. TypeScript types are tightly coupled with implementation

Suggested Solution

Here's how we could make it more accessible for any JavaScript framework:

// Example of framework-agnostic usage
const ethoraChat = new EthoraChatAPI({
  endpoint: 'wss://xmpp.ethoradev.com:5443/ws',
  credentials: {
    username: 'user123',
    password: 'pass123'
  }
});

// Event-based API
ethoraChat.on('message', (message) => {
  console.log('New message:', message);
});

// Promise-based methods
const history = await ethoraChat.rooms.getHistory({
  roomId: 'room123',
  limit: 50
});

// Subscribing to room updates
const unsubscribe = ethoraChat.rooms.subscribe('room123', {
  onMessage: (msg) => console.log(msg),
  onTyping: (user) => console.log(`${user} is typing...`),
  onPresence: (updates) => console.log('Present users:', updates)
});

Integration Example for Vue.js

// Vue.js Component Example
export default {
  data() {
    return {
      messages: [],
      isConnected: false
    }
  },
  async created() {
    this.chat = new EthoraChatAPI({
      endpoint: 'wss://xmpp.ethoradev.com:5443/ws',
      credentials: this.userCredentials
    });

    this.unsubscribe = this.chat.rooms.subscribe(this.roomId, {
      onMessage: (msg) => this.messages.push(msg),
      onPresence: (status) => this.isConnected = status.connected
    });
  },
  beforeDestroy() {
    this.unsubscribe();
  }
}

Integration Example for Angular

@Component({
  selector: 'app-chat',
  template: '...'
})
export class ChatComponent implements OnInit, OnDestroy {
  private chat: EthoraChatAPI;
  private unsubscribe: () => void;

  async ngOnInit() {
    this.chat = new EthoraChatAPI({...});
    this.unsubscribe = this.chat.rooms.subscribe(roomId, {
      onMessage: this.handleMessage.bind(this)
    });
  }

  ngOnDestroy() {
    this.unsubscribe();
  }
}

 

To make this happen, we would need to:

  1. Create a framework-agnostic core library
  2. Provide simple event subscription mechanisms
  3. Document the API in plain JavaScript terms
  4. Create example integrations for popular frameworks
  5. Provide TypeScript types as an optional enhancement

 

 

Have a question about this? Ask the Ethora team.