Files
Toju/docs-site/docs/plugin-development/api/messages-and-typing.md
Myx 0a714428f6 docs: improve doucmentation
improve doucmentation and fix small store changes
2026-04-30 01:16:48 +02:00

3.5 KiB

sidebar_position
sidebar_position
6

Messages and Typing API

The messages API reads current messages, sends messages, edits or deletes plugin-owned messages, moderates messages, syncs messages, and exposes typing state.

Required Capabilities

Method Capability
messages.readCurrent() messages.read
messages.send(content, channelId?) messages.send
messages.sendAsPluginUser(request) messages.send
messages.setTyping(isTyping, channelId?) messages.send
messages.subscribeTyping(handler) messages.read
messages.edit(messageId, content) messages.editOwn
messages.delete(messageId) messages.deleteOwn
messages.moderateDelete(messageId) messages.moderate
messages.sync(messages) messages.sync

Read Current Messages

export function activate(context) {
  const messages = context.api.messages.readCurrent();

  context.api.logger.info('Current messages', messages.slice(-3).map((message) => ({
    id: message.id,
    channelId: message.channelId,
    senderName: message.senderName,
    content: message.content
  })));
}

Send a Message

export function activate(context) {
  const created = context.api.messages.send(
    'Reminder: raid starts at 20:00. Bring repairs and snacks.',
    'general'
  );

  context.api.logger.info('Sent reminder', { messageId: created.id });
}

Send as a Plugin User

export function activate(context) {
  const botUserId = context.api.server.registerPluginUser({
    id: 'poll-bot',
    displayName: 'Poll Bot'
  });

  context.api.messages.sendAsPluginUser({
    pluginUserId: botUserId,
    channelId: 'general',
    content: 'Poll is open: react with 1 for dungeon, 2 for arena, 3 for crafting.'
  });
}

Capabilities required: users.manage and messages.send.

Edit and Delete Plugin-Owned Messages

export function activate(context) {
  const message = context.api.messages.send('Draft event reminder', 'announcements');

  context.api.messages.edit(message.id, 'Event reminder: voice meetup starts in 15 minutes.');
  context.api.messages.delete(message.id);
}

Moderation Delete

export function activate(context) {
  context.api.messages.moderateDelete('msg-spam-20260429-001');
}

Use moderation from explicit moderator actions, not automatic activation.

Typing State

export function activate(context) {
  context.api.messages.setTyping(true, 'general');

  setTimeout(() => {
    context.api.messages.setTyping(false, 'general');
  }, 1500);

  context.subscriptions.push(context.api.messages.subscribeTyping((event) => {
    context.api.logger.info('Typing event', {
      displayName: event.displayName,
      isTyping: event.isTyping,
      channelId: event.channelId,
      serverId: event.serverId,
      voiceChannel: event.voiceChannel?.name ?? null
    });
  }));
}

Example typing event:

{
  "serverId": "room-7ebdde75",
  "channelId": "general",
  "userId": "user-muse-01",
  "displayName": "Muse",
  "isTyping": true
}

Sync Messages

export function activate(context) {
  context.api.messages.sync([
    {
      id: 'external-standup-001',
      roomId: 'room-7ebdde75',
      channelId: 'standup',
      senderId: 'standup-importer',
      senderName: 'Standup Importer',
      content: 'Imported note: Alice is working on plugin docs.',
      timestamp: 1777473600000,
      isDeleted: false
    }
  ]);
}

Sync should preserve message ids and timestamps from the source system when possible.