GET /api/v1/search/messages
Matches messages whose text contains the query, with filters and cursor pagination. Activity messages are excluded. Returns only messages in conversations the caller can access. Requires the messages:read permission.
Authentication
Use an agent API key and secret.
Parameters
All parameters are query parameters.
| Name | Type | Required | Description |
|---|---|---|---|
| query | string | Yes | Search query (minimum 3 characters) minLength: 3 |
| filters | string | No | JSON-encoded filter. Either an array of conditions that are AND-ed, e.g. [{"model":"conversations","field":"status_id","operator":"equals","value":"1"}], or a group {"logic":"AND","rules":[...]} with at most one level of nested groups. Operators: equals, not equals, greater than, less than, set, not set, in, between, contains, ilike, not contains. Filterable fields: conversations (status_id, priority_id, assigned_team_id, assigned_user_id, inbox_id, last_message_at, last_interaction_at, last_interaction_sender, created_at, waiting_since, next_sla_deadline_at, snoozed_until, sla_policy_id, tags), conversation_statuses (id, name), users (email, external_user_id), inboxes (channel). Messages can also be filtered on conversation_messages (created_at). |
| sort | string (enum) | No | Sort by message creation time. Defaults to newest. default: "newest" enum: ["newest", "oldest"] |
| cursor | string | No | next_cursor from the previous page. A cursor works only with the sort it was created with. |
| page_size | integer | No | Number of results per page (defaults to 30). Values above 100 use 100. default: 30 minimum: 1 maximum: 100 |
Responses
200
Search results retrieved successfully
Content type: application/json.
All fields are optional.
| Field | Type | Description |
|---|---|---|
| status | string | example: "success" |
| data | object | |
| data.results | array of object | |
| data.results[].uuid | string | |
| data.results[].created_at | string (date-time) | example: "2025-08-28T10:00:00Z" |
| data.results[].type | string (enum) | enum: ["incoming", "outgoing"] |
| data.results[].private | boolean | Whether the message is a private note |
| data.results[].text_content | string | First 200 characters of the message text example: "Hello, I need help with my order." |
| data.results[].snippet | string | Up to 300 characters of the message text around the first match nullable: true |
| data.results[].sender | object | |
| data.results[].sender.first_name | string | nullable: true |
| data.results[].sender.last_name | string | nullable: true |
| data.results[].conversation_created_at | string (date-time) | example: "2025-08-28T10:00:00Z" |
| data.results[].conversation_uuid | string | example: "550e8400-e29b-41d4-a716-446655440000" |
| data.results[].conversation_reference_number | string | example: "150" |
| data.results[].conversation_subject | string | nullable: true |
| data.results[].conversation_status | string | nullable: true example: "Open" |
| data.results[].assigned_user_id | integer | nullable: true |
| data.results[].assigned_team_id | integer | nullable: true |
| data.results[].assignee | object | Assigned agent. Fields are null when no agent is assigned. |
| data.results[].assignee.first_name | string | nullable: true |
| data.results[].assignee.last_name | string | nullable: true |
| data.results[].assignee.avatar_url | string | nullable: true |
| data.results[].team_name | string | nullable: true |
| data.results[].priority | string | nullable: true |
| data.results[].inbox_name | string | nullable: true |
| data.results[].inbox_channel | string (enum) | enum: ["email", "livechat"] nullable: true |
| data.results[].contact | object | |
| data.results[].contact.first_name | string | nullable: true |
| data.results[].contact.last_name | string | nullable: true |
| data.results[].contact.email | string | nullable: true |
| data.results[].contact.avatar_url | string | nullable: true |
| data.per_page | integer | |
| data.has_more | boolean | Whether another page exists |
| data.next_cursor | string | Pass as cursor to fetch the next page. Empty when has_more is false. |
400
Invalid request
Content type: application/json.
All fields are optional.
| Field | Type | Description |
|---|---|---|
| status | string | example: "error" |
| message | string | Error message example: "Invalid request" |
| data | unspecified | Additional error data nullable: true |
| error_type | string (enum) | enum: ["GeneralException", "PermissionException", "InputException", "DataException", "NetworkException", "NotFoundException", "ConflictException", "UnauthorizedException", "RateLimitException"] |
401
Unauthorized
Content type: application/json.
Response fields match the 400 response.
403
Forbidden
Content type: application/json.
Response fields match the 400 response.
500
Internal server error
Content type: application/json.
Response fields match the 400 response.
Specification
Download the complete OpenAPI specification.
OpenAPI definition for this endpoint
openapi: 3.0.0
info:
title: libredesk API
description: >-
REST API documentation for libredesk helpdesk system.
## Authentication
The libredesk API supports two authentication methods:
### 1. Basic Authentication
Use your API key and secret with Basic authentication:
```
Authorization: Basic <base64_encoded_api_key:api_secret>
```
### 2. Token Authentication
Use your API key and secret with token authentication:
```
Authorization: token api_key:api_secret
```
To obtain API credentials, generate them from your agent profile in the
libredesk dashboard.
version: 1.0.0
servers:
- url: http://localhost:8080
description: Local development server
security:
- basicAuth: []
- tokenAuth: []
paths:
/api/v1/search/messages:
get:
tags:
- Search
summary: Paginated Search Messages
description: >-
Matches messages whose text contains the query, with filters and cursor
pagination. Activity messages are excluded. Returns only messages in
conversations the caller can access. Requires the `messages:read`
permission.
operationId: handlePaginatedSearchMessages
parameters:
- name: query
in: query
required: true
schema:
type: string
minLength: 3
description: Search query (minimum 3 characters)
- name: filters
in: query
required: false
schema:
type: string
description: >-
JSON-encoded filter. Either an array of conditions that are AND-ed,
e.g.
`[{"model":"conversations","field":"status_id","operator":"equals","value":"1"}]`,
or a group `{"logic":"AND","rules":[...]}` with at most one level of
nested groups. Operators: `equals`, `not equals`, `greater than`,
`less than`, `set`, `not set`, `in`, `between`, `contains`, `ilike`,
`not contains`. Filterable fields: `conversations` (status_id,
priority_id, assigned_team_id, assigned_user_id, inbox_id,
last_message_at, last_interaction_at, last_interaction_sender,
created_at, waiting_since, next_sla_deadline_at, snoozed_until,
sla_policy_id, tags), `conversation_statuses` (id, name), `users`
(email, external_user_id), `inboxes` (channel). Messages can also be
filtered on `conversation_messages` (created_at).
- name: sort
in: query
required: false
schema:
type: string
enum:
- newest
- oldest
default: newest
description: Sort by message creation time. Defaults to `newest`.
- name: cursor
in: query
required: false
schema:
type: string
description: >-
`next_cursor` from the previous page. A cursor works only with the
`sort` it was created with.
- name: page_size
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 30
description: >-
Number of results per page (defaults to 30). Values above 100 use
100.
responses:
'200':
description: Search results retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/MessageSearchPageResponse'
'400':
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
security:
- basicAuth: []
- tokenAuth: []
components:
schemas:
MessageSearchPageResponse:
type: object
properties:
status:
type: string
example: success
data:
type: object
properties:
results:
type: array
items:
$ref: '#/components/schemas/MessageSearchResult'
per_page:
type: integer
has_more:
type: boolean
description: Whether another page exists
next_cursor:
type: string
description: >-
Pass as `cursor` to fetch the next page. Empty when `has_more`
is false.
ErrorResponse:
type: object
description: Error response format
properties:
status:
type: string
example: error
message:
type: string
description: Error message
example: Invalid request
data:
nullable: true
description: Additional error data
error_type:
type: string
enum:
- GeneralException
- PermissionException
- InputException
- DataException
- NetworkException
- NotFoundException
- ConflictException
- UnauthorizedException
- RateLimitException
MessageSearchResult:
type: object
properties:
uuid:
type: string
created_at:
type: string
format: date-time
example: '2025-08-28T10:00:00Z'
type:
type: string
enum:
- incoming
- outgoing
private:
type: boolean
description: Whether the message is a private note
text_content:
type: string
description: First 200 characters of the message text
example: Hello, I need help with my order.
snippet:
type: string
nullable: true
description: Up to 300 characters of the message text around the first match
sender:
type: object
properties:
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
conversation_created_at:
type: string
format: date-time
example: '2025-08-28T10:00:00Z'
conversation_uuid:
type: string
example: 550e8400-e29b-41d4-a716-446655440000
conversation_reference_number:
type: string
example: '150'
conversation_subject:
type: string
nullable: true
conversation_status:
type: string
nullable: true
example: Open
assigned_user_id:
type: integer
nullable: true
assigned_team_id:
type: integer
nullable: true
assignee:
type: object
description: Assigned agent. Fields are null when no agent is assigned.
properties:
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
avatar_url:
type: string
nullable: true
team_name:
type: string
nullable: true
priority:
type: string
nullable: true
inbox_name:
type: string
nullable: true
inbox_channel:
type: string
nullable: true
enum:
- email
- livechat
contact:
type: object
properties:
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
email:
type: string
nullable: true
avatar_url:
type: string
nullable: true
securitySchemes:
basicAuth:
type: http
scheme: basic
description: >-
Basic authentication using base64 encoded API key and secret. Format:
`Authorization: Basic <base64(api_key:api_secret)>`
tokenAuth:
type: apiKey
name: Authorization
in: header
description: >-
Token authentication using API key and secret. Format: `Authorization:
token api_key:api_secret`
