Chats

Batch unread message counts per room for a set of users

Returns, for each requested user, how many unread messages they have per chat room in the target app. Built for backend / CRON flows - e.g. a scheduled "you have unread messages" digest email - where your backend iterates its own users and asks Ethora for their unread state.

Why POST, not GET: the input is an array of user ids, which would not fit reliably in a query string. The call is otherwise a plain synchronous read - it returns the counts immediately, nothing is queued or processed in the background.

How unread is derived (read-only, no client change required): per room, a cutoff is chosen as the user's lastViewed marker for that room (persisted by the chat clients in ejabberd private storage), or - if the user never opened the room - the time they were added to it. Unread = messages in that room newer than the cutoff, excluding the user's own. Messages are counted from the Mongo archive (*_chat_archive.messages, the same store as /messages/search), so this load never touches the live XMPP database.

Modes:

  • count (default): exact per-room counts, each bounded by cap (a room with more than cap unread reports cap with capped: true, i.e. "99+").
  • flag: skips exact counting and only reports whether each room has any unread (unreadCount collapses to 1). Cheapest option for very large / hot deployments.

Scope & limits: all userIds must belong to appId. Identifiers may be a user's uuid, Mongo _id, or xmppUsername. Max 200 users per request - split larger runs into multiple calls. Ids that don't resolve to a user in the app are returned in notFound rather than failing the request.

Accuracy note: this is a best-effort count for nudge/notification use. It can differ slightly from the in-app badge (which zeroes the active room live and is multi-device-synced only on app open). For a periodic digest that difference is immaterial.

post/v2/apps/{appId}/users/unread-counts

Request

  • Base URL: https://api.chat.ethora.com
  • URL: https://api.chat.ethora.com/v2/apps/{appId}/users/unread-counts
  • Auth: one of:
    • HTTP bearer
    • HTTP bearer

Path parameters

appIdstring required

Target App ID. Must be an app the calling actor owns or has been delegated access to.

Request body

userIdsstring[] required

User identifiers (uuid / Mongo _id / xmppUsername), all within appId.

mode'count' | 'flag'

count = exact per-room counts (capped); flag = presence only.

capinteger

Per-room count ceiling. Counts at or above this report capped=true.

Response

Per-user unread breakdown. Rooms with zero unread are omitted from each user's rooms array.

{
  appId: string,
  mode: 'count' | 'flag',
  cap: number,
  markerSource: 'private-storage' | 'membership-fallback',
  results: [
    {
      userId: string,        // the identifier you passed in
      uuid: string | null,
      xmppUsername: string | null,
      total: number,         // sum of per-room unreadCount
      hasUnread: boolean,
      unreadRoomCount: number,
      capped: boolean,       // any room hit the cap
      rooms: [
        { chatId: string, unreadCount: number, capped: boolean }
      ]
    }
  ],
  notFound: string[]         // ids that didn't resolve to a user
}

Changes

No recorded changes to this operation across all 1 revision of this API.