Chatter API Documentation

Overview

The Chatter API allows developers to create custom channels and extend the platform's functionality. Custom channels are JavaScript-based modules that can be loaded directly into Chatter, providing new communication features and integrations.

Key Features

  • Real-time message handling via Socket.IO
  • File management with tmpweb integration
  • User interaction and presence tracking
  • Built-in commands for common operations
  • Persistent storage and state management

Authentication

Custom channels inherit the authentication context from the main Chatter application. The current user is available through the global socket object and session data.

Getting Current User

// Get current username from session
const username = sessionStorage.getItem('username');

// Or via API
fetch('/api/whoami')
    .then(r => r.json())
    .then(data => console.log(data.username));

Custom Channels

Custom channels are self-contained modules that extend Chatter's functionality. They can be loaded from URLs and provide custom UI, commands, and integrations.

Channel Structure

A custom channel is a JavaScript object with the following structure:

{
    name: "Channel Name",
    version: "1.0.0",
    description: "Channel description",
    icon: "📦",
    
    // Initialize the channel
    init: function(container, socket, utils) {
        // Setup UI and event listeners
    },
    
    // Handle incoming messages
    onMessage: function(data) {
        // Process messages
    },
    
    // Handle commands
    onCommand: function(cmd, args) {
        // Process commands
    },
    
    // Cleanup on unload
    destroy: function() {
        // Cleanup resources
    }
}

Loading Custom Channels

Custom channels can be loaded in settings by providing a URL to the channel definition:

// Channel URL should return the channel object
// Example: https://example.com/my-channel.js
// The file should export: window.ChatterCustomChannel = { ... }

API Reference

Complete API documentation for all Chatter endpoints and services:

📁 File Management API

Upload, manage, and delete files with tmpweb integration

👤 User Management API

Manage users, authentication, and permissions

🔧 Settings API

User preferences and application settings

🌐 Public API

Public information and status endpoints

⚙️ Admin API

Administrative functions and system management

Documents API

The Documents API provides functionality for creating, managing, and collaborating on documents with real-time editing and role-based permissions.

Document Management

The Documents API provides functionality for creating, managing, and collaborating on documents with real-time editing and role-based permissions.

Document Roles

  • Viewer: Can read documents only
  • Editor: Can read and edit documents
  • Creator: Document owner who can manage members and permissions
POST /api/doc/create

Create a new document

Parameter Type Description
name string Document name
content string Initial document content
members array List of members to add (username, role)
Request Example
POST /api/doc/create
Content-Type: application/json

{
    "name": "Meeting Notes",
    "content": "# Meeting Notes\n\n## Agenda\n- Project updates\n- Timeline review",
    "members": [
        {"username": "alice", "role": "editor"},
        {"username": "bob", "role": "viewer"}
    ]
}
GET /api/doc/list

List all documents you have access to

Response Example
{
    "ok": true,
    "documents": [
        {
            "id": 1,
            "name": "Meeting Notes",
            "created_by": "john_doe",
            "created_at": "2025-01-15T10:30:00Z",
            "last_edited_at": "2025-01-15T11:00:00Z",
            "role": "creator"
        }
    ]
}
GET /api/doc/:id

Get document details and content

Parameter Type Description
id integer Document ID
Response Example
{
    "id": 1,
    "name": "My Document",
    "content": "Document content here...",
    "created_by": "username",
    "created_at": "2025-01-15T10:30:00Z",
    "last_edited_by": "username",
    "last_edited_at": "2025-01-15T11:00:00Z"
}
GET /api/doc/:id/members

List all members of a document

Response Example
{
    "ok": true,
    "members": [
        {
            "username": "user1",
            "role": "editor",
            "added_at": "2025-01-15T10:30:00Z"
        },
        {
            "username": "user2", 
            "role": "viewer",
            "added_at": "2025-01-15T10:35:00Z"
        }
    ]
}
POST /api/doc/:id/add_member

Add a member to a document

Parameter Type Description
username string Username to add
role string Role: "viewer" or "editor"
Request Example
POST /api/doc/1/add_member
Content-Type: application/json

{
    "username": "newuser",
    "role": "editor"
}
POST /api/doc/:id/remove_member

Remove a member from a document

Parameter Type Description
username string Username to remove
POST /api/doc/:id/update_member_role

Update a member's role

Parameter Type Description
username string Username to update
role string New role: "viewer" or "editor"
POST /api/doc/:id/delete

Delete a document (creator only)

Note: Only the document creator can delete a document. This action cannot be undone and will remove all document content and member associations.
Response Example
{
    "ok": true
}

Socket.IO Events

Documents use Socket.IO for real-time collaboration:

EMIT doc_join

Join a document room for real-time updates

Event Data
{
    "doc_id": 1
}
EMIT doc_edit

Send document edits to other users

Event Data
{
    "doc_id": 1,
    "content": "Updated document content..."
}
LISTEN doc_updated

Receive document updates from other users

Event Data
{
    "doc_id": 1,
    "content": "Updated document content..."
}
LISTEN doc_member_added

Notify when a member is added

LISTEN doc_member_removed

Notify when a member is removed

LISTEN doc_member_role_updated

Notify when a member's role is updated

LISTEN doc_deleted

Notify when a document is deleted

Event Data
{
    "doc_id": 1
}

Messaging API

The Messaging API provides endpoints for managing Direct Messages (DMs) and Group Direct Messages (GDMs), including message history, logging, and real-time communication.

Message Logging Configuration

DM logging can be controlled via the GD_SAVE_DM_LOGS setting:

  • Enabled (1): DM messages are logged and accessible via admin APIs
  • Disabled (0): DM messages are not logged for privacy

Direct Messages (DMs)

GET /api/dm/peers

Get list of users you have DM conversations with

Response Example
[
    "user1",
    "user2", 
    "admin"
]
GET /api/dm/messages

Get DM conversation history with a specific user

Parameter Type Description
peer string Username to get conversation with
Response Example
[
    {
        "id": 123,
        "from_user": "username",
        "to_user": "peer",
        "text": "Hello there!",
        "attachment": null,
        "created_at": "2025-01-15T10:30:00Z",
        "reply_to": null
    }
]

Group Direct Messages (GDMs)

GET POST /api/gdm/threads

Get GDM threads or create a new GDM

Create GDM Request
POST /api/gdm/threads
Content-Type: application/json

{
    "name": "Project Team",
    "members": ["user1", "user2", "user3"]
}
Response Example
{
    "ok": true,
    "id": 456,
    "name": "Project Team"
}
GET /api/gdm/messages

Get messages from a specific GDM thread

Parameter Type Description
tid integer Thread ID
Response Example
[
    {
        "id": 789,
        "username": "user1",
        "text": "Hey team!",
        "attachment": null,
        "created_at": "2025-01-15T11:00:00Z",
        "edited": 0,
        "reply_to": null,
        "reply_username": null,
        "reply_snippet": null
    }
]
POST /api/gdm/rename

Rename a GDM thread (creator only)

POST /api/gdm/add_member

Add members to a GDM (creator only)

POST /api/gdm/remove_member

Remove member from GDM (creator or admin)

POST /api/gdm/transfer

Transfer GDM ownership to another member

GET /api/gdm/thread_info

Get information about a GDM thread (members, lock status, etc.)

Parameter Type Description
tid integer Thread ID
POST /api/gdm/kick

Kick a member from GDM (owner only)

GDM Management (Admin Controls)

The following endpoints require admin permissions and respect toggle settings:

POST /api/gdm/lock

Lock a GDM (prevents new messages)

POST /api/gdm/unlock

Unlock a GDM

POST /api/gdm/delete

Delete a GDM permanently

Admin Message Logging

GET /api/admin/dm_logs

Get DM logs for a specific user (admin only, requires GD_SAVE_DM_LOGS enabled)

Parameter Type Description
peer string Username to get logs for
Response Example
[
    {
        "id": 123,
        "from_user": "user1",
        "to_user": "user2",
        "text": "Private message",
        "created_at": "2025-01-15T10:30:00Z"
    }
]
Note: DM logging is controlled by the GD_SAVE_DM_LOGS setting. When disabled, this endpoint returns 403 and no DM messages are logged.

Socket.IO Events

Real-time messaging uses Socket.IO events:

EMIT dm_send

Send a direct message

Event Data
{
    "to": "username",
    "text": "Hello!",
    "attachment": null,
    "reply_to": null
}
EMIT gdm_send

Send a message to a GDM

Event Data
{
    "thread_id": 456,
    "text": "Hey team!",
    "attachment": null,
    "reply_to": null
}
LISTEN dm_new

Receive new direct messages

LISTEN gdm_new

Receive new GDM messages

LISTEN gdm_threads_refresh

GDM thread updates (member changes, rename, etc.)

LISTEN dm_typing

DM typing indicators

LISTEN gdm_typing

GDM typing indicators

GDM Invite System

GDM invites allow users to join private groups through invite links or codes.

POST /api/gdm/invite/create

Create an invite for a GDM (creator only)

Parameter Type Description
thread_id integer GDM thread ID
expires_in integer Invite expiry time in seconds (default: 24 hours)
Request Example
POST /api/gdm/invite/create
Content-Type: application/json

{
    "thread_id": 123,
    "expires_in": 86400
}
Response Example
{
    "ok": true,
    "invite_code": "ABC123XYZ",
    "invite_url": "https://chat.example.com/join/ABC123XYZ",
    "expires_at": "2025-01-16T09:00:00Z"
}
GET POST /api/gdm/invite/join

Join a GDM using an invite code or link

Parameter Type Description
code string Invite code (GET: query param, POST: body)
Request Examples
GET /api/gdm/invite/join?code=ABC123XYZ

POST /api/gdm/invite/join
Content-Type: application/json

{
    "code": "ABC123XYZ"
}
Response Example
{
    "ok": true,
    "thread_id": 123,
    "thread_name": "Project Team"
}
Note: Invite codes are single-use and expire after the specified time or when used.

Channel API

The Channel API provides endpoints for managing custom channels and voice channels in Chatter.

Custom Channels

Custom channels are JavaScript-based modules that extend Chatter's functionality. They can be loaded from URLs and provide custom UI, commands, and integrations.

POST /api/channels/custom/register

Register a custom channel

Parameter Type Description
url string URL to the custom channel definition
name string Display name for the channel
enabled boolean Whether to enable the channel (default: true)
Request Example
POST /api/channels/custom/register
Content-Type: application/json

{
    "url": "https://example.com/my-channel.js",
    "name": "My Custom Channel",
    "enabled": true
}
Response Example
{
    "ok": true,
    "id": 1
}
GET /api/channels/custom/list

List all registered custom channels

Response Example
{
    "ok": true,
    "channels": [
        {
            "id": 1,
            "name": "My Custom Channel",
            "url": "https://example.com/my-channel.js",
            "enabled": true,
            "created_at": "2025-01-15T10:30:00Z"
        }
    ]
}
DELETE /api/channels/custom/:id

Delete a custom channel (creator or admin only)

Parameter Type Description
id integer Channel ID to delete
POST /api/channels/custom/:id/toggle

Enable or disable a custom channel (creator or admin only)

Parameter Type Description
id integer Channel ID to toggle
enabled boolean Whether to enable the channel

Voice Channels

Voice channels provide real-time audio communication capabilities within Chatter.

GET /api/voice/channels

List active voice channels

Response Example
{
    "ok": true,
    "channels": [
        "general",
        "gaming",
        "music"
    ]
}
Error Response
{
    "ok": false,
    "error": "Voice service unavailable",
    "channels": []
}

Channel Structure

A custom channel is a JavaScript object with the following structure:

{
    name: "Channel Name",
    version: "1.0.0",
    description: "Channel description",
    icon: "📦",
    
    // Initialize the channel
    init: function(container, socket, utils) {
        // Setup UI and event listeners
    },
    
    // Handle incoming messages
    onMessage: function(data) {
        // Process messages
    },
    
    // Handle commands
    onCommand: function(cmd, args) {
        // Process commands
    },
    
    // Cleanup on unload
    destroy: function() {
        // Cleanup resources
    }
}

Loading Custom Channels

Custom channels can be loaded in settings by providing a URL to the channel definition:

// Channel URL should return the channel object
// Example: https://example.com/my-channel.js
// The file should export: window.ChatterCustomChannel = { ... }
Note: Custom channels run in the same context as the main Chatter application. Be careful not to pollute the global namespace or override existing functionality.
Warning: Only load custom channels from trusted sources. Malicious channels could access user data or compromise security.

Built-in Commands

Custom channels have access to built-in commands for common operations:

/file upload <url>

Upload a file from URL to tmpweb storage

/file list

List all uploaded files with expiry times

/file delete <id>

Delete a file by ID

/file info <id>

Get detailed information about a file

/user info <username>

Get information about a user

/user list

List all online users

/message send <channel> <text>

Send a message to a channel

/channel info

Get current channel information

Examples

Example 1: Simple Echo Channel

A basic channel that echoes messages back to the user:

window.ChatterCustomChannel = {
    name: "Echo Channel",
    version: "1.0.0",
    description: "Echoes messages back to you",
    icon: "🔊",
    
    init: function(container, socket, utils) {
        container.innerHTML = `
            <div style="padding: 1rem;">
                <h3>Echo Channel</h3>
                <div id="echo-messages" style="margin-bottom: 1rem;"></div>
                <input id="echo-input" type="text" placeholder="Type something..." 
                       style="width: 100%; padding: 0.5rem;">
            </div>
        `;
        
        const input = document.getElementById('echo-input');
        const messages = document.getElementById('echo-messages');
        
        input.addEventListener('keypress', (e) => {
            if (e.key === 'Enter' && input.value) {
                const msg = document.createElement('div');
                msg.textContent = '🔊 ' + input.value;
                msg.style.padding = '0.5rem';
                msg.style.margin = '0.25rem 0';
                msg.style.background = 'rgba(59, 130, 246, 0.1)';
                msg.style.borderRadius = '0.25rem';
                messages.appendChild(msg);
                input.value = '';
            }
        });
    },
    
    destroy: function() {
        // Cleanup
    }
};

Example 2: File Manager Channel

A channel for managing uploaded files:

window.ChatterCustomChannel = {
    name: "File Manager",
    version: "1.0.0",
    description: "Manage uploaded files",
    icon: "📁",
    
    init: function(container, socket, utils) {
        container.innerHTML = `
            <div style="padding: 1rem;">
                <h3>File Manager</h3>
                <input type="file" id="file-input" style="margin-bottom: 1rem;">
                <button id="upload-btn" style="padding: 0.5rem 1rem; cursor: pointer;">
                    Upload
                </button>
                <div id="file-list" style="margin-top: 1rem;"></div>
            </div>
        `;
        
        document.getElementById('upload-btn').addEventListener('click', async () => {
            const file = document.getElementById('file-input').files[0];
            if (!file) return;
            
            const formData = new FormData();
            formData.append('file', file);
            
            const response = await fetch('/api/files/upload', {
                method: 'POST',
                body: formData
            });
            
            const data = await response.json();
            if (data.ok) {
                alert('File uploaded: ' + data.url);
                this.loadFiles();
            }
        });
        
        this.loadFiles();
    },
    
    loadFiles: function() {
        fetch('/api/files/list')
            .then(r => r.json())
            .then(data => {
                const list = document.getElementById('file-list');
                list.innerHTML = data.files.map(f => `
                    <div style="padding: 0.5rem; margin: 0.25rem 0; 
                                background: rgba(59, 130, 246, 0.1); 
                                border-radius: 0.25rem;">
                        <strong>${f.name}</strong>
                        <small>Expires: ${new Date(f.expires_at).toLocaleString()}</small>
                    </div>
                `).join('');
            });
    },
    
    destroy: function() {}
};

Example 3: User Status Channel

A channel that displays online users:

window.ChatterCustomChannel = {
    name: "User Status",
    version: "1.0.0",
    description: "View online users",
    icon: "👥",
    
    init: function(container, socket, utils) {
        container.innerHTML = `
            <div style="padding: 1rem;">
                <h3>Online Users</h3>
                <div id="user-list"></div>
            </div>
        `;
        
        socket.on('user_list_refresh', () => this.loadUsers());
        this.loadUsers();
    },
    
    loadUsers: function() {
        fetch('/api/users/online')
            .then(r => r.json())
            .then(data => {
                const list = document.getElementById('user-list');
                list.innerHTML = data.users.map(u => `
                    <div style="padding: 0.5rem; margin: 0.25rem 0; 
                                display: flex; align-items: center; gap: 0.5rem;">
                        <span style="width: 8px; height: 8px; 
                                    background: #10b981; border-radius: 50%;"></span>
                        <strong>${u.username}</strong>
                    </div>
                `).join('');
            });
    },
    
    destroy: function() {}
};

Best Practices

  • Always clean up resources in the destroy method
  • Use Socket.IO events for real-time updates
  • Handle errors gracefully with try-catch blocks
  • Validate user input before processing
  • Use HTTPS for custom channel URLs in production
  • Test channels thoroughly before deployment
  • Document your channel's API and commands
Note: Custom channels run in the same context as the main Chatter application. Be careful not to pollute the global namespace or override existing functionality.
Warning: Only load custom channels from trusted sources. Malicious channels could access user data or compromise security.