---
title: "List chat conversations"
method: GET
path: "/chat/threads"
tags: ["Chat"]
---

# List chat conversations

`GET /chat/threads`

## Request

- Base URL: `https://viral.app/api/v1`
- URL: `https://viral.app/api/v1/chat/threads`
- Auth: API key in header `x-api-key`

Lists brand-creator conversations with latest-message previews and unread counts. Rows with kind "group" are group chats (title = the internal name, publicTitle = the name creators see, memberCount; creator fields are null). An API key always reads its organization's inbox (scope "org").

Three modes:
- **Default** (no `pageToken`, `limit` or `updatedSince`): the 200 most recently active conversations, pinned ones first. There is no continuation (`nextPageToken` is null); pass `limit` to read a larger inbox.
- **Paged** (`limit` and/or `pageToken`): every conversation, newest first by creation, an order that stays put while conversations get new messages. Pass each `nextPageToken` back until it is null.
- **Changed since** (`updatedSince`): the conversations whose `updatedAt` is later (a message sent, edited or deleted, a group renamed or its members changed), oldest change first. Pass `nextPageToken` back with the same `updatedSince`. A conversation that changes during the scan comes back on a later page, and the server looks back 2 minutes before `updatedSince` because changes commit slightly out of order, so a thread can appear more than once: dedupe on `chatId`. Pass the newest `updatedAt` you received as the next `updatedSince`. Unread counts and the caller's own pin, archive and mute state are not changes.

`search`, `filter` and `applicationStatus` apply in every mode. The default mode leaves out the conversations the caller archived; the paged and changed-since modes include them (`archived` is true on the row), so an archive never hides a conversation from a sync. `archived` true lists only the archived conversations, combined with `filter` (`filter` "archived" alone is the same), and false only the others, in every mode. `archivedCount` counts the archived conversations matching `search`, `filter` and `applicationStatus`; `relationshipStats` and `groupStats` always describe the whole inbox. A page token only continues the mode that issued it: any other token is refused with 400.

## Query parameters

- `scope` 'org' | 'creator', required
- `search` string
- `filter` 'all' | 'unread' | 'active' | 'application' | 'past' | 'groups' | 'archived'
- `archived` boolean: true lists only the conversations you archived, false only the others, on top of `filter` (archived unread ones, archived groups, …). Left out, the default mode lists the others and the paged modes both. `filter` "archived" is the same as `archived` true.
- `applicationStatus` 'open' | 'in_review' | 'accepted' | 'rejected' | 'withdrawn' | 'auto_closed' | 'invited' | 'not_interested' | 'answered' | 'retracted': Only the direct conversations whose creator has an application to your organization in this status (any of their applications), on top of `filter`: with `filter` "application", the applicants at that stage.
- `pageToken` string: The previous page's `nextPageToken`. Pass it with the same `updatedSince`, `search` and `filter`.
- `limit` integer: Page size (default 200). Passing it pages through every conversation, newest first by creation.
- `updatedSince` string, date-time: Only conversations changed since this instant, oldest change first. Pass the newest `updatedAt` you received; the server looks back 2 minutes before it, so dedupe on `chatId`.

## Response `200`

OK

- object
  - `threads` object[], required
    - `chatId` union, required
      - string
      - string
    - `orgId` string, required
    - `kind` 'direct' | 'group'
    - `creatorUserId` string, nullable, required
    - `creatorName` string, nullable, required
    - `creatorEmail` string, nullable, required
    - `creatorImage` string, nullable, required
    - `creatorEmailVerified` boolean, nullable
    - `orgName` string, required
    - `orgLogo` string, nullable, required
    - `relationship` 'active' | 'application' | 'past', nullable, required
    - `title` string, nullable
    - `publicTitle` string, nullable
    - `groupKind` 'manual' | 'campaign' | 'all', nullable
    - `campaignId` string, nullable
    - `memberCount` integer
    - `lastMessageSenderUserId` string, nullable
    - `lastMessageSenderName` string, nullable
    - `creatorOrgCreatorId` string, nullable
    - `creatorIsMarketplaceCreator` boolean
    - `creatorNeedsPlatformInvite` boolean
    - `lastMessageAt` string, date-time, required
    - `updatedAt` string, date-time, nullable
    - `lastMessageId` string, nullable
    - `lastMessagePreview` string, nullable, required
    - `lastMessageDeleted` boolean, required
    - `lastMessageSenderType` 'org' | 'creator' | 'system', nullable, required
    - `unreadCount` integer, required
    - `pinned` boolean, required
    - `archived` boolean, required
    - `muted` boolean
    - `draft` boolean
  - `archivedCount` integer, required
  - `relationshipStats` object, required
    - `application` object, required
      - `count` integer, required
      - `hasUnread` boolean, required
    - `active` object, required
      - `count` integer, required
      - `hasUnread` boolean, required
    - `past` object, required
      - `count` integer, required
      - `hasUnread` boolean, required
  - `groupStats` object
    - `count` integer, required
    - `hasUnread` boolean, required
  - `nextPageToken` string, nullable

## Other responses

- `400`: 400
- `401`: 401
- `402`: 402
- `404`: 404
- `408`: 408
- `429`: 429
- `500`: 500

---

[API](https://skmtc.dev/viral/apis/viral-app-api.md) · [All operations](https://skmtc.dev/viral/apis/viral-app-api/llms.txt) · [OpenAPI document](https://skmtc.dev/viral/apis/viral-app-api/revisions/31e97fa79ef1?raw)
