Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Messages

daRPC normalizes recent chat and system messages so a tool does not need to parse the punctuation the client uses for each channel.

UseRoute or events
Read recent messagesGET /clients/{client}/messages
Send a messagePOST /clients/{client}/messages/send
Send an internal messagePOST /messages/send
Filter retained historychannels, since, skip, and count
Watch new messagesMessage events

Reading recent messages

curl "http://127.0.0.1:2626/clients/ZiLo/messages"

Each message contains:

  • timestamp, formatted as ISO 8601 in the daemon’s local time and UTC offset
  • Optional tick_ms, the client’s wrapping Windows millisecond tick
  • channel
  • Optional sender and recipient
  • Cleaned game message text, or an internal message payload object
Messages {
    messages: Message[],
}

Message {
    timestamp: string,
    tick_ms: u32?,
    channel: MessageChannel,
    sender: string?,
    recipient: string?,
    text: string?,
    payload: object?,
}

Retained history uses one of these channels:

say, shout, whisper, guild, group, system, world, internal

Spell chants are transient message.chant SSE events and are intentionally not stored by /messages. This keeps spell and NPC command chants from crowding ordinary conversation history.

Whisper packet type is authoritative when the server returns an error without the usual name> or name" formatting. Such records remain whisper; sender and recipient are absent when no participant can be extracted.

Channel markers and participant punctuation shown by the game are removed from the text. Empty messages are ignored. A world shout is stored once as world, even though the client also renders a duplicate shout-form message.

Sending messages

Send nearby speech, shouts, guild chat, group chat, or a whisper through the selected client:

curl -X POST "http://127.0.0.1:2626/clients/ZiLo/messages/send" \
  -H "content-type: application/json" \
  -d '{"channel":"whisper","recipient":"Eidolon","content":"hello"}'

The request body has channel, optional recipient, and content fields. channel must be say, shout, guild, group, or whisper. A whisper requires a recipient; every other channel rejects one. Content must contain from 1 through 100 ASCII characters. Whisper recipients must contain from 1 through 15 ASCII characters without whitespace.

Guild and group messages use the game’s directed-message packet with the special recipients ! and !!, respectively. Callers select guild or group; they do not supply those markers as whisper recipients.

Internal messages

Internal messages travel only inside darpcd.exe. They are not sent to the game client, DLL, or game server. Send one to a connected in-game character by name:

curl -X POST "http://127.0.0.1:2626/messages/send" \
  -H "content-type: application/json" \
  -d '{"channel":"internal","recipient":"Eidolon","payload":{"action":"ready"}}'

Omit recipient to deliver to every connected daRPC client. A broadcast with no connected clients succeeds with {"delivered":0}. A named recipient that does not exist returns 404; duplicate active names return 409.

Provide exactly one of content or payload. payload must be a JSON object. content accepts nonempty Unicode text without the game’s 100-character limit and is delivered as {"content":"..."} inside payload. The API’s bounded 4 KiB request-body limit still applies. Internal records omit tick_ms and text, use channel: "internal", and appear only in daRPC REST history and SSE streams.

Filtering and paging

Messages are sorted newest first. The route returns 20 records by default.

QueryMeaning
channelsComma-separated channels, such as say,shout.
sinceOnly messages strictly newer than this ISO 8601 timestamp.
skipSkip this many matching records after sorting. Default 0.
countReturn at most this many records. Default 20, maximum 100.

Example:

curl "http://127.0.0.1:2626/clients/ZiLo/messages?channels=say,shout&since=2026-08-02T15:00:00-04:00&skip=0&count=20"

since is optional. When it is omitted, the route searches the retained history without a time boundary.

Live message events

The complete message payload and stream behavior are in Message events.

Each channel has its own SSE routing name:

message.say
message.shout
message.chant
message.whisper
message.guild
message.group
message.system
message.world
message.internal

All nine routes use the JSON discriminator type: "message". The channel is inside data.channel. Separate SSE names let a browser subscribe only to the channels it cares about.

Message events do not contain the common state observation object. The SSE id still provides ordering, and the subscription path identifies the client. The daemon adds normal chat and system messages to REST history before broadcasting them. It broadcasts chants without retaining them.

Some system messages also confirm spell results or reject a ground-item pickup. In those cases the stream contains both message.system and a semantic spell event or item.pickup_failed. The original message remains available for display and debugging. See Spells for spell correlation behavior.

Retention

The daemon keeps at most 4,096 messages and 1 MiB of message text and payload per DLL instance. It removes the oldest messages first. History is held in memory and is cleared when the daemon restarts or a new DLL instance replaces the old one.

If an SSE connection is interrupted, read /messages with a suitable since value to recover recent conversation context. Chants and state events from before the subscription are not replayed.

Privacy

Message history can contain private whispers. daRPC does not write message text to its normal logs, but any local program with access to the loopback API can read retained messages. Run only consumers you trust.