Search archived chat messages by text content
Searches the Mongo archive (*_chat_archive.messages) populated by the ejabberd mod_track_message hook. This is a parallel store to the live MAM history — denormalized, indexed for $text + substring queries, and isolated from the live XMPP DB so search load never touches the chat runtime.
Two query modes:
- substring (default): case-insensitive regex on body. Finds short queries like "h" inside "hello" — good for autocomplete-style flows. Special regex characters are escaped, so a query like "." matches a literal dot, not "any char".
- fulltext: Mongo $text operator. Token-based; won't match substrings of a word, but very fast and supports sort=relevance with a score field on each item.
Visibility:
- B2B server token: full access to every message in the target app.
- User token: restricted to chats the caller can see. Groupchat membership is resolved via user_to_chats; private 1-1 access is derived from the canonical chatId (the caller's xmppUsername must be one of the two participants).
When the caller passes an explicit chatId they have no access to, the response is 403 CHAT_FORBIDDEN (not an empty list) so the client can distinguish "denied" from "no matches".
Note: the archive only stores messages whose chat / users are registered in the Ethora API. Ad-hoc XMPP rooms and synthetic test fixtures don't pollute the searchable set.
Request
- Base URL: https://api.chat.ethora.com
- URL: https://api.chat.ethora.com/v2/apps/{appId}/messages/search
- Auth: one of:
- HTTP bearer
- HTTP bearer
Path parameters
Target App ID. Must be an app the calling actor owns or has been delegated access to.
Query parameters
Search query (1..500 chars). Always required.
Search mode: text (default; substring match on message body) or semantic (vector search via the AI service, if enabled).
Optional chat localpart (${appId}_${uuid}, no @conference.host). When provided, scopes search to one chat. For user tokens, returns 403 CHAT_FORBIDDEN if the caller has no access to it.
Bare uuid (not xmppUsername) — filters by sender.
Lower bound (inclusive) on message.createdAt. ISO-8601 timestamp or Unix-epoch seconds.
Upper bound (exclusive) on message.createdAt. Same format as since.
relevance is only meaningful with mode=fulltext; with substring it falls back to date desc.
Maximum number of items to return per page. Server caps vary per endpoint; the response carries the actual page size.
Number of items to skip from the beginning of the result set. Use with limit for paging.
Response
{
items: [
{
_id, appId, chatId, chatType, room,
from, fromUserId, to, toUserId,
body, messageId, stanzaId, createdAt,
score? // only when mode=fulltext AND sort=relevance
}
],
total: number,
limit, offset, q, mode
}
Changes
No recorded changes to this operation across all 1 revision of this API.