message.comDevelopers

Saved views Live

Saved views capture a set of inbox filters under a name and an icon. Used to pin commonly-needed slices of the queue (Unanswered VIPs, Tickets older than 24h, Calls awaiting callback). Saved views render in the dashboard sidebar.

List saved views

GET/api/v1/saved-viewsAuth: Bearer

Cursor-paginated. Filters: scope (workspace / personal).

Code samples

cURL
curl 'https://app.message.com/api/v1/saved-views' \
  -H 'Authorization: Bearer YOUR_WORKSPACE_JWT'
JavaScript
const res = await fetch('https://app.message.com/api/v1/saved-views', {
  headers: { Authorization: 'Bearer ' + token }
});
const { savedViews } = await res.json();
Python
import requests
r = requests.get(
    "https://app.message.com/api/v1/saved-views",
    headers={"Authorization": f"Bearer {token}"},
)
views = r.json()["savedViews"]
Ruby
require "net/http"
require "json"
uri = URI("https://app.message.com/api/v1/saved-views")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  req = Net::HTTP::Get.new(uri)
  req["Authorization"] = "Bearer #{token}"
  http.request(req)
end
views = JSON.parse(res.body)["savedViews"]
PHP
<?php
$ctx = stream_context_create([
  "http" => ["method" => "GET", "header" => "Authorization: Bearer $token"]
]);
$views = json_decode(file_get_contents("https://app.message.com/api/v1/saved-views", false, $ctx), true)["savedViews"];

Get one saved view

GET/api/v1/saved-views/:idAuth: Bearer
200 OK
{
  "id": "uuid",
  "version": 1,
  "name": "Unanswered VIP chats",
  "icon": "star",
  "filters": {
    "channel": "chat",
    "status": ["open"],
    "assigneeId": null,
    "tags": ["vip"]
  },
  "scope": "workspace",
  "createdByAgentId": "uuid",
  "createdAt": "2026-05-13T15:30:00Z"
}

Create a saved view

POST/api/v1/saved-viewsAuth: Bearer
FieldTypeDescription
namerequiredstringDisplay name. 1 to 80 chars. Must be unique within scope.
iconoptionalstringIcon name from our icon set (e.g., star, flag, clock).
filtersrequiredobjectFilter map; same fields as the conversations list endpoint accepts.
scopeoptionalenumOne of workspace (shared) or personal. Defaults to personal.
Body
{
  "name": "Unanswered VIP chats",
  "icon": "star",
  "filters": {
    "channel": "chat",
    "status": ["open"],
    "assigneeId": null,
    "tags": ["vip"]
  },
  "scope": "workspace"
}

Filter fields

Same shape the dashboard sends to /conversations:

  • channel: chat, ticket, call, or array.
  • status: array of open, pending, solved, spam.
  • assigneeId: agent UUID, null for unassigned, or me sentinel.
  • departmentId: department UUID or array.
  • tags: array of tag strings (AND).
  • olderThanMinutes: numeric; for SLA-style views.

Update a saved view

PATCH/api/v1/saved-views/:idAuth: Bearer

Edit name, icon, filters, or scope. Requires expectedVersion.

Delete a saved view

DELETE/api/v1/saved-views/:idAuth: Bearer

To re-order workspace views in the sidebar, set sortOrder in PATCH; the dashboard surfaces a drag-and-drop UI that sends those updates as a batch.

Errors

CodeWhen
400 invalid_bodyFilter shape invalid.
403 forbiddenAgent cannot edit a workspace-scoped view.
409 conflictName already taken within scope.
409 stale_versionOptimistic-lock mismatch.

Common pitfalls

  • Saving a view with assigneeId: "me" at workspace scope. The sentinel resolves per-agent, so the same view shows each agent their own queue. That is usually desired; verify before sharing.
  • Confusing saved views with saved replies. Views filter the queue; replies populate the composer.
  • Overusing tags filters. Tags drift over time. Bake structural filters (department, status) first and lean on tags as a refinement.