# Create customer search

> POST /v1/customers/search · Core resources API

Source: https://developer.kustomer.com/api/core-resources/create-customer-search

```http
POST https://{orgname}.api.kustomerapp.com/v1/customers/search
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.permission.search.create`, `org.permission.search.update`, `org.permission.search_global.create`, `org.permission.search_preview.create`; or legacy `org.user.search.read`, `org.admin.search.read`. The API key or user must hold at least one of them. Legacy roles predate permission sets and still work.

Searches across customer data with criteria based on standard Object data and any custom attribute data for standard Objects, including Message, Conversation, and Company objects.
Standard object data, custom object data, and conversation time data is limited to objects that have an updatedAt more recent than in the past 2 years. To query for older, archived data for standard and custom objects, see the [Archive Search API](https://developer.kustomer.com/api/core-resources/create-customer-archive-search).
Older conversation time data is not available via search.

## Filter on dates
You can filter by dates in either a local date `YYYY-MM-DD` format or a UTC date format. If you include a timezone in the query, a local date will be adjusted to account for the included timezone. UTC dates will not be timezone adjusted.
<br>
### Example of search criteria with local date
```json
{
    "and": [
        {
            "conversation_created_at": {
                "lte": "2020-11-19"
            }
        }
    ],
    "queryContext": "conversation",
    "timeZone": "America/New_York"
}
```
#### Note
> The default `GMT` timezone is applied when you exclude a timezone.

### Example of search criteria with UTC date
```json
{
    "and": [
        {
            "conversation_created_at": {
                "lte": "2020-11-20T16:34:00.000Z"
            }
        }
    ],
    "queryContext": "conversation"
}
```

## Filter on standard attributes
For a list of available standard attributes, see [Standard attributes JSON schema](https://developer.kustomer.com/docs/concepts/search#standard-attributes-json-schema).

### Example of search criteria with standard attributes
```json
[
  {"customer_updated_at": {"gte": "2016-06-24" }},
  {"conversation_status": {"equals": "done" }}
]
```

## Filter on custom attributes for standard Objects
You can query custom attributes on standard Objects with the following syntax:
`<<standard_object_name>>_custom_<<custom_field_name>>`.

### Example of search criteria with custom attributes

```json
{ "customer_custom_myCustomStr": { "equals": "some value" }}
{ "message_custom_myCustomNum": { "gte": 5 }}
```

## Filter on custom attributes for custom Objects
You can query custom attributes for custom Object with the following syntax: `kobject_custom_<<klass_name>>_<<custom_field_name>>`.

### Examples
```json
{ "kobject_custom_myKlass_myCustomNum": { "gte": 5 }}
```

## Sort on customer attributes
You can sort based on the following customer attributes:

```
customer_name
customer_gender
customer_created_at
customer_updated_at
customer_modified_at
customer_externalId
customer_activity_at
customer_last_seen_at
customer_signed_up_at
customer_lastmessage_preview
customer_progressive_status
customer_done
customer_open
customer_snoozed
customer_last_message_sent_at
customer_last_message_out_sent_at
customer_last_message_unresponded_to_sent_at
customer_last_message_at
```

### Example of sort with customer attributes
```
{"sort": [{"customer_updated_at": "asc"}]}
{"sort": [{"customer_gender": "asc"}, {"customer_created_at": "asc"}]}
```

#### Note
> Sorting based on other standard Object attributes is unavailable.

## Pagination
There is a hard limit of **100** for the maximum number of pages.

There may be cases where you want to page through more records. For example, let's say you'd like to get an initial snapshot of data and then update the data.

To work around the pagination limit, you can write a query based on the `updated_at` attribute for a standard Object. You can then use the returned information in following API requests based on the last `updated_at` value from the response.

## Standard attributes JSON Schema

```json
{
  "type": "object",
  "properties": {
    "customer_any_text": {
      "type": "string",
      "operator": "any"
    },
    "customer_name": {
      "type": "string",
      "operator": "string"
    },
    "customer_gender": {
      "type": "string",
      "enum": ["m", "f"],
      "operator": "list"
    },
    "customer_presence": {
      "type": "string",
      "enum": ["online", "offline", "idle"],
      "operator": "list"
    },
    "customer_email": {
      "type": "string",
      "format": "email",
      "operator": "string"
    },
    "customer_shared_email": {
      "type": "string",
      "format": "email",
      "operator": "string"
    },
    "customer_phone": {
      "type": "string",
      "pattern": "^\\+?[1-9]\\d{1,14}$",
      "operator": "string"
    },
    "customer_shared_phone": {
      "type": "string",
      "pattern": "^\\+?[1-9]\\d{1,14}$",
      "operator": "string"
    },
    "customer_urls": {
      "type": "string",
      "operator": "string"
    },
    "customer_address": {
      "type": "string",
      "operator": "string"
    },
    "customer_locale": {
      "type": "string",
      "operator": "string"
    },
    "customer_activity_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_last_seen_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_signed_up_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_last_message_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_last_message_out_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_last_message_unresponded_to_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_last_message_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_externalId": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "customer_shared_externalId": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "customer_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_updated_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_modified_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_created_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "customer_modified_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "customer_satisfaction_avg_score": {
      "type": "number",
      "operator": "number"
    },
    "customer_satisfaction_avg_rating": {
      "type": "number",
      "operator": "number"
    },
    "customer_conversations_count": {
      "type": "number",
      "operator": "number"
    },
    "customer_status": {
      "type": "string",
      "enum": ["snoozed", "open", "done"],
      "operator": "list"
    },
    "customer_progressive_status": {
      "type": "string",
      "enum": ["snoozed", "open", "done"],
      "operator": "list"
    },
    "customer_active_users": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "customer_watchers": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "customer_tags": {
      "type": "string",
      "operator": "list"
    },
    "customer_sentiment": {
      "type": "string",
      "enum": ["happy", "unhappy", "indifferent"],
      "operator": "list"
    },
    "customer_social_type": {
      "type": "string",
      "enum": ["facebook", "instagram", "whatsapp", "linkedin", "pinterest", "twitter"],
      "operator": "list"
    },
    "customer_social_userid": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "customer_social_username": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "customer_shared_social_type": {
      "type": "string",
      "enum": ["facebook", "instagram", "whatsapp", "linkedin", "pinterest", "twitter"],
      "operator": "list"
    },
    "customer_shared_social_userid": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "customer_shared_social_username": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "customer_default_lang": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "customer_imported_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "customer_imported": {
      "type": "boolean",
      "operator": "boolean"
    },
    "company_any_text": {
      "type": "string",
      "operator": "any"
    },
    "company_name": {
      "type": "string",
      "operator": "string"
    },
    "company_tags": {
      "type": "string",
      "operator": "list"
    },
    "company_default_lang": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "company_imported_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "company_imported": {
      "type": "boolean",
      "operator": "boolean"
    },
    "message_any_text": {
      "type": "string",
      "operator": "any"
    },
    "message_body": {
      "type": "string",
      "operator": "text"
    },
    "message_channel": {
      "type": "string",
      "enum": ["sms", "chat", "email", "facebook", "voice", "twitter-dm", "twitter-tweet", "instagram", "whatsapp"],
      "operator": "list"
    },
    "message_size": {
      "type": "number",
      "operator": "number"
    },
    "message_direction": {
      "type": "string",
      "enum": ["in", "out"],
      "operator": "boolean"
    },
    "message_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "message_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "message_updated_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "message_created_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "message_modified_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "message_sentiment": {
      "type": "string",
      "enum": ["happy", "unhappy", "indifferent"],
      "operator": "list"
    },
    "message_customer_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "message_status": {
      "type": "string",
      "enum": ["sent", "received", "error"],
      "operator": "list"
    },
    "message_error_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "message_error_title": {
      "type": "string",
      "operator": "string"
    },
    "message_external_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "message_direction_type": {
      "type": "string",
      "enum": ["initial-in", "initial-out", "response-in", "response-out", "followup-in", "followup-out"],
      "operator": "list"
    },
    "message_created_by_teams": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "message_redacted": {
      "type": "string",
      "operator": "boolean"
    },
    "message_redacted_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "message_imported_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "message_imported": {
      "type": "boolean",
      "operator": "boolean"
    },
    "message_recipients": {
      "type": "string",
      "operator": "string"
    },
    "message_sender": {
      "type": "string",
      "operator": "string"
    },
    "message_shortcuts": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "message_subject": {
      "type": "string",
      "operator": "text"
    },
    "message_source": {
      "type": "string",
      "enum": ["bulk"],
      "operator": "list"
    },
    "message_attachment_count": {
      "type": "number",
      "operator": "number"
    },
    "message_auto": {
      "type": "string",
      "operator": "boolean"
    },
    "message_lang": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "note_any_text": {
      "type": "string",
      "operator": "any"
    },
    "note_body": {
      "type": "string",
      "operator": "text"
    },
    "note_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "note_modified_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "note_updated_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "note_created_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "note_modified_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "note_deleted": {
      "$ref": "#/definitions/user",
      "operator": "boolean"
    },
    "note_user_mentions": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "note_team_mentions": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "teams",
      "operator": "list"
    },
    "note_attachment_count": {
      "$ref": "#/definitions/user",
      "operator": "number"
    },
    "note_external_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "note_customer_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "note_conversation_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "note_lang": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "note_imported_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "note_imported": {
      "type": "boolean",
      "operator": "boolean"
    },
    "conversation_any_text": {
      "type": "string",
      "operator": "any"
    },
    "conversation_name": {
      "type": "string",
      "operator": "string"
    },
    "conversation_sentiment": {
      "type": "string",
      "enum": ["happy", "unhappy", "indifferent"],
      "operator": "list"
    },
    "conversation_status": {
      "type": "string",
      "enum": ["snoozed", "open", "done"],
      "operator": "list"
    },
    "conversation_sub_status": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "conversation_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_updated_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_modified_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_modified_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_message_count": {
      "type": "number",
      "operator": "number"
    },
    "conversation_note_count": {
      "type": "number",
      "operator": "number"
    },
    "conversation_satisfaction_survey_id": {
      "type": "string",
      "operator": "list"
    },
    "conversation_satisfaction_sent_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_satisfaction_sent_by_teams": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "teams",
      "operator": "list"
    },
    "conversation_satisfaction_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_satisfaction_score": {
      "type": "number",
      "operator": "number"
    },
    "conversation_satisfaction_rating": {
      "type": "number",
      "operator": "number"
    },
    "conversation_satisfaction_status": {
      "type": "string",
      "enum": [
        "canceled",
        "scheduled",
        "offered",
        "unresponded",
        "rated",
        "commented"
      ],
      "operator": "list"
    },
    "conversation_channels": {
      "type": "string",
      "enum": ["sms", "chat", "email", "facebook", "voice", "twitter-dm", "twitter-tweet", "instagram", "whatsapp"],
      "operator": "list"
    },
    "conversation_satisfaction": {
      "type": "string",
      "operator": "string"
    },
    "conversation_priority": {
      "type": "integer",
      "operator": "number",
      "minimum": 1,
      "maximum": 5
    },
    "conversation_tags": {
      "type": "string",
      "operator": "list"
    },
    "conversation_assigned_users": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_assigned_teams": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "teams",
      "operator": "list"
    },
    "conversation_last_message_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_last_message_out_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_last_message_unresponded_to_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_last_message_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_first_response_sent_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_first_response_time": {
      "type": "number",
      "operator": "number"
    },
    "conversation_first_response_created_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_last_response_created_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_last_message_direction": {
      "type": "string",
      "enum": ["in", "out"],
      "operator": "list"
    },
    "conversation_direction": {
      "type": "string",
      "enum": ["in", "out"],
      "operator": "list"
    },
    "conversation_outbound_message_count": {
      "type": "number",
      "operator": "number"
    },
    "conversation_customer_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "conversation_campaign_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "conversation_first_message_in_sent_at": {
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_first_message_in_direction_type": {
      "type": "string",
      "enum": ["initial-in", "initial-out", "response-in", "response-out", "followup-in", "followup-out"],
      "operator": "list"
    },
    "conversation_first_message_in_channel": {
      "type": "string",
      "enum": ["sms", "chat", "email", "facebook", "voice", "twitter-dm", "twitter-tweet", "instagram", "whatsapp"],
      "operator": "list"
    },
    "conversation_first_message_out_sent_at": {
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_first_message_out_direction_type": {
      "type": "string",
      "enum": ["initial-in", "initial-out", "response-in", "response-out", "followup-in", "followup-out"],
      "operator": "list"
    },
    "conversation_first_message_out_channel": {
      "type": "string",
      "enum": ["sms", "chat", "email", "facebook", "voice", "twitter-dm", "twitter-tweet", "instagram", "whatsapp"],
      "operator": "list"
    },
    "conversation_time_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_time_conversation_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "conversation_time_created_by_teams": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "teams",
      "operator": "list"
    },
    "conversation_time_assigned_users": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_time_assigned_teams": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "teams",
      "operator": "list"
    },
    "conversation_time_touched": {
      "type": "string",
      "operator": "boolean"
    },
    "conversation_time_reopened": {
      "type": "string",
      "operator": "boolean"
    },
    "conversation_time_snoozed": {
      "type": "string",
      "operator": "boolean"
    },
    "conversation_time_resolved": {
      "type": "string",
      "operator": "boolean"
    },
    "conversation_time_message_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_time_message_time": {
      "type": "number",
      "operator": "number"
    },
    "conversation_time_messages_sent": {
      "type": "number",
      "operator": "number"
    },
    "conversation_time_note_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_time_note_time": {
      "type": "number",
      "operator": "number"
    },
    "conversation_time_notes_sent": {
      "type": "number",
      "operator": "number"
    },
    "conversation_time_handle_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_time_handle_time": {
      "type": "number",
      "operator": "number"
    },
    "conversation_time_channels": {
      "type": "string",
      "enum": ["sms", "chat", "email", "facebook", "voice", "twitter-dm", "twitter-tweet", "instagram", "whatsapp"],
      "operator": "list"
    },
    "conversation_default_lang": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "any_text": {
      "type": "string",
      "operator": "any"
    },
    "tracking_events": {
      "type": "string",
      "operator": "number"
    },
    "conversation_sla_status": {
      "type": "string",
      "enum": ["done", "pending", "paused"],
      "operator": "list"
    },
    "conversation_sla_version_id": {
      "type": "string",
      "operator": "string_notanalyzed"
    },
    "conversation_sla_id": {
      "type": "string",
      "operator": "list"
    },
    "conversation_sla_breached": {
      "type": "boolean",
      "operator": "boolean"
    },
    "conversation_sla_breach_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_sla_satisfied_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
     "conversation_sla_breach_metric": {
      "type": "string",
      "enum": [
        "firstResponse",
        "nextReply",
        "totalCustomerWaitTime",
        "longestUnrespondedMessage",
        "totalConversationOpenTime"
      ],
      "operator": "list"
    },
    "conversation_first_done_created_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_last_done_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_last_done_created_by": {
      "$ref": "#/definitions/user",
      "operator": "list"
    },
    "conversation_last_done_created_by_teams": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "teams",
      "operator": "list"
    },
    "conversation_reply_channel": {
      "type": "string",
      "enum": ["sms", "chat", "email", "facebook", "voice", "twitter-dm", "twitter-tweet", "instagram", "whatsapp"],
      "operator": "list"
    },
    "conversation_queue": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "queues",
      "operator": "list"
    },
    "conversation_external_queue": {
      "type": "string",
      "enum": ["amazon-connect"],
      "operator": "list"
    },
    "conversation_ended": {
      "type": "boolean",
      "operator": "boolean"
    },
    "conversation_ended_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_ended_reason": {
      "type": "string",
      "operator": "string"
    },
    "conversation_imported_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "conversation_imported": {
      "type": "boolean",
      "operator": "boolean"
    },
    "kobject_any_text": {
      "type": "string",
      "operator": "any"
    },
    "kobject_created_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "kobject_updated_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "kobject_imported_at": {
      "type": "string",
      "format": "date-time",
      "operator": "datetime"
    },
    "kobject_imported": {
      "type": "boolean",
      "operator": "boolean"
    }
  },
  "definitions": {
    "user": {
      "type": "string",
      "pattern": "^(?=[A-Fa-f\\d]{24}$)(\\d+[A-Fa-f]|[A-Fa-f]+\\d)",
      "collection": "users"
    }
  },
  "additionalProperties": false
}

```

## About Search

Search finds customers, conversations, messages, companies, notes, custom objects and other records that match a set of criteria, the same way saved searches do in the agent desktop.

Search is how you query Kustomer by content rather than by ID: "open conversations with priority 4 or higher", "customers whose loyalty tier is gold", "orders over $100". It runs the same engine as the saved searches agents use in the agent desktop. You send criteria and get back one page of matching records.

Despite its path, `POST /v1/customers/search` isn't limited to customers. `queryContext` picks what to return: `customer`, `conversation`, `message`, `company`, `note`, `kobject`, `kobject_<klassName>`, `conversation_time`, `work_session` or `work_item`.

#### Criteria

The body combines criteria in `and` (every one must match), `or` (at least one must match) and `not` (exclude matches). Each criterion maps one attribute to one operator and value, such as `{ "conversation_status": { "equals": "open" } }`. Attribute names are `<object>_<attribute>` in snake case, and you can filter on related objects, for example a `customer` search on `conversation_status`. Custom attributes use `<object>_custom_<name>`, or `kobject_custom_<klassName>_<name>` for custom objects, and their suffix decides which operators apply. Which operators an attribute accepts (`equals`, `contains`, `in`, `gte`, `is_set` and so on) depends on its type; see [search concepts](https://developer.kustomer.com/docs/concepts/search) for the full list of attributes and operators.

Dates can be local (`2026-10-01`), interpreted in `timeZone` (GMT if omitted), or exact UTC timestamps. `fields` limits the attributes returned (up to 20), and `includeDeleted` includes deleted records.

#### Live and archived data

| Endpoint | Covers |
| --- | --- |
| Standard search | Records updated in the past two years, with every standard and custom attribute. |
| Archive search | Records older than that, filterable on a small set of attributes such as IDs, `created_at`, `updated_at` and any-text matches. Supports `customer`, `conversation`, `message`, `company` and KObject contexts. |

Conversation time data older than two years isn't searchable at all.

#### Which endpoint to use

| To | Call |
| --- | --- |
| Find records that match criteria | [`POST /v1/customers/search`](https://developer.kustomer.com/api/core-resources/create-customer-search) |
| Find records older than two years | [`POST /v1/customers/archive/search`](https://developer.kustomer.com/api/core-resources/create-customer-archive-search) |

Results page with `page` and `pageSize` (up to 500), and only the first 10,000 matches can be read: a request where `page` × `pageSize` is over 10,000 fails with `400`. To export more, split the query into windows on an `updated_at` attribute and run one search per window ([search recipes](https://developer.kustomer.com/docs/guides/search-recipes) shows how). `idsOnly=true` returns just the matching IDs, which is faster for large syncs. Pass a saved search's ID as `id` to run its stored query. Search is indexed asynchronously, so a record you just wrote may take a moment to appear; read it by ID when you need your own writes. API keys can make 100 search requests per minute; see [rate limits](https://developer.kustomer.com/docs/concepts/rate-limits).

Related: [Search concepts](https://developer.kustomer.com/docs/concepts/search), [Search recipes](https://developer.kustomer.com/docs/guides/search-recipes), [Saved searches](https://developer.kustomer.com/api/settings-and-configurations#search-filters)

### Recipes

#### 1. Export a large result set in time windows

Pull every conversation that matches a query into your warehouse, even when there are more matches than one search can page through.

**Step 1.** [`POST /v1/customers/search`](https://developer.kustomer.com/api/core-resources/create-customer-search.md). Count the matches first. With `pageSize=1` the response is tiny, `meta.total` holds the count, and `trackTotalHits=true` makes it exact. Only the first 10,000 matches of any one search can be read, so if the count is higher, split the query.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/customers/search?pageSize=1&trackTotalHits=true" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"queryContext": "conversation", "and": [{"conversation_updated_at": {"gte": "2026-09-01T00:00:00Z"}}, {"conversation_updated_at": {"lt": "2026-10-01T00:00:00Z"}}]}' \
  | jq '.meta.total'
```

**Step 2.** [`POST /v1/customers/search`](https://developer.kustomer.com/api/core-resources/create-customer-search.md). Run one search per window on `conversation_updated_at`, using `gte` the window's start and `lt` its end so adjacent windows neither overlap nor leave gaps. Pick windows small enough to stay under 10,000 matches each, and page with `pageSize` up to 500.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/customers/search?page=1&pageSize=500" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"queryContext": "conversation", "and": [{"conversation_updated_at": {"gte": "2026-09-01T00:00:00Z"}}, {"conversation_updated_at": {"lt": "2026-09-08T00:00:00Z"}}]}'
```

```bash title="kusty"
kusty api POST /v1/customers/search --query pageSize=500 --all --output jsonl \
  --data '{"queryContext": "conversation", "and": [{"conversation_updated_at": {"gte": "2026-09-01T00:00:00Z"}}, {"conversation_updated_at": {"lt": "2026-09-08T00:00:00Z"}}]}' \
  >> conversations.jsonl
```

> For later runs, search from the time your previous run started, and overlap the windows by a few minutes: the search index can lag writes slightly. [Search recipes](https://developer.kustomer.com/docs/guides/search-recipes) has a full incremental sync. Records not updated in the past two years are only in [archive search](https://developer.kustomer.com/api/core-resources/create-customer-archive-search).

#### 2. Run a saved search with extra filters

Reuse the query an admin maintains in a saved search, such as "Urgent open conversations", and narrow it for your own job.

**Step 1.** [`GET /v1/customers/searches`](https://developer.kustomer.com/api/settings-and-configurations/get-all-searches.md). Find the [saved search](https://developer.kustomer.com/api/settings-and-configurations#search-filters) by name.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/customers/searches?filter=all" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/customers/searches --query filter=all --all \
  | jq -r 'select(.data.attributes.name == "Urgent open conversations") | .data.id'
```

**Step 2.** [`POST /v1/customers/search`](https://developer.kustomer.com/api/core-resources/create-customer-search.md). Pass its ID as `id`. Kustomer runs the stored query and adds the `and` and `or` criteria you send to it; a `sort` you send replaces the stored one. An unknown `id` fails with `404`.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/customers/search?id=$SEARCH_ID&pageSize=100" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"queryContext": "conversation", "and": [{"conversation_created_at": {"gte": "2026-10-01T00:00:00Z"}}]}'
```

```bash title="kusty"
kusty api POST /v1/customers/search --query id=$SEARCH_ID --all \
  --data '{"queryContext": "conversation", "and": [{"conversation_created_at": {"gte": "2026-10-01T00:00:00Z"}}]}' \
  --fields id,attributes.name
```

#### 3. Close conversations nobody has touched in a month

Find stale open conversations and mark them done in bulk, for example as a nightly cleanup job.

**Step 1.** [`POST /v1/customers/search`](https://developer.kustomer.com/api/core-resources/create-customer-search.md). Search for open conversations last updated before the cutoff, with `idsOnly=true` so each result is just an `id` and `type`.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/customers/search?idsOnly=true&pageSize=500" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"queryContext": "conversation", "and": [{"conversation_status": {"equals": "open"}}, {"conversation_updated_at": {"lt": "2026-09-21T00:00:00Z"}}]}'
```

```bash title="kusty"
kusty api POST /v1/customers/search --query idsOnly=true --query pageSize=500 --all \
  --data '{"queryContext": "conversation", "and": [{"conversation_status": {"equals": "open"}}, {"conversation_updated_at": {"lt": "2026-09-21T00:00:00Z"}}]}' \
  | jq -r '.data.id' > stale.txt
```

**Step 2.** [`PUT /v1/conversations/{id}`](https://developer.kustomer.com/api/core-resources/update-conversation.md). Close each one. Search reflects an index that can trail writes slightly, so a conversation updated moments ago may still appear; the update itself is safe to repeat.

```bash title="cURL"
curl --request PUT "https://api.kustomerapp.com/v1/conversations/$CONVERSATION_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"status": "done"}'
```

```bash title="kusty"
while read -r id; do
  kusty api PUT /v1/conversations/$id --field status=done --fields id
done < stale.txt
```

> Collect all the IDs before you start closing: closing conversations changes the results, so paging through the search while updating would skip matches. API keys can make 100 search requests per minute.

### Permissions

Fewest roles for a read-only integration: any valid key. For every endpoint: `org.permission.search_global.create`.

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `page` | integer | no | Page number of results to return. |
| `pageSize` | integer | no | Number of results to return per page. |
| `idsOnly` | boolean | no | Set to `true` to return only matching IDs from search results. |
| `id` | string | no | Saved search ID used to execute a stored query before searching. |
| `withIntelliAggs` | boolean | no | Set to `true` to include intelligent aggregation data in customer search results. |
| `trackTotalHits` | boolean | no | Controls whether the search request tracks an exact total hit count. |

## Request body

Content type: `application/json` (required)

- `searchHash` (string)
- `queryContext` (string): (pattern ^(company|customer|message|conversation|conversation_time|note|kobject|kobject_.*|work_session|work_item)$)
- `includeDeleted` (boolean)
- `timeZone` (string)
- `and` (anyOf)
  - Any of:
    - object
    - array<object>
- `or` (anyOf)
  - Any of:
    - object
    - array<object>
- `not` (anyOf)
  - Any of:
    - object
    - array<object>
- `sort` (anyOf)
  - Any of:
    - object
    - array<object>
- `aggs` (object)
- `fields` (array<object>): (max items 20; unique items)

Example:

```json
{
  "searchHash": "string",
  "queryContext": "string",
  "includeDeleted": true,
  "timeZone": "string",
  "and": {},
  "or": {}
}
```

## Responses

### 200

Success

- `meta` (object, required)
  - `pageSize` (integer, required)
  - `page` (integer, required)
  - `total` (integer, required)
  - `totalPages` (integer, required)
  - `aggregations` (object, required)
- `data` (array<object>, required)
  - `type` (string, required)
  - `id` (string, required)
  - `attributes` (object, required)
    - `name` (string, required)
    - `displayName` (string, required)
    - `createdAt` (string, required)
    - `updatedAt` (string, required)
    - `lastActivityAt` (string, required)
    - `verified` (boolean, required)
    - `rev` (integer, required)
  - `relationships` (object, required)
    - `org` (object, required)
  - `links` (object, required)
    - `self` (string, required)
- `links` (object, required)
  - `self` (string, required)
  - `first` (string, required)
  - `prev` (string, required, nullable)
  - `next` (string, required)
  - `last` (string, required)

```json
{
  "meta": {
    "pageSize": 100,
    "page": 1,
    "total": 7503,
    "totalPages": 76,
    "aggregations": {}
  },
  "data": [
    {
      "type": "customer",
      "id": "576db7781126c61100824494",
      "attributes": {
        "name": "Dave Smith",
        "displayName": "Dave",
        "createdAt": "2016-06-24T22:43:04.298Z",
        "updatedAt": "2016-06-24T22:43:04.298Z",
        "lastActivityAt": "2016-06-24T22:43:04.298Z",
        "verified": true,
        "rev": 1
      },
      "relationships": {
        "org": {
          "links": {
            "self": "/v1/orgs/573f7702a1a00c10005adc2a"
          },
          "data": {
            "type": "org",
            "id": "573f7702a1a00c10005adc2a"
          }
        }
      },
      "links": {
        "self": "/v1/customers/576db7781126c61100824494"
      }
    },
    {
      "type": "customer",
      "id": "5771a9181126c611008253ff",
      "attributes": {
        "name": "Peter Johansen",
        "displayName": "Pete",
        "createdAt": "2016-07-27T22:30:48.939Z",
        "updatedAt": "2016-07-27T22:30:48.939Z",
        "lastActivityAt": "2016-07-27T22:30:48.939Z",
        "verified": true,
        "rev": 1
      },
      "relationships": {
        "org": {
          "links": {
            "self": "/v1/orgs/573f7702a1a00c10005adc2a"
          },
          "data": {
            "type": "org",
            "id": "573f7702a1a00c10005adc2a"
          }
        }
      },
      "links": {
        "self": "/v1/customers/5771a9181126c611008253ff"
      }
    }
  ],
  "links": {
    "self": "/v1/customers/search?page=1&pageSize=100",
    "first": "/v1/customers/search?page=1&pageSize=100",
    "prev": null,
    "next": "/v1/customers/search?page=2&pageSize=100",
    "last": "/v1/customers/search?page=76&pageSize=100"
  }
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

### 404

Not Found

## Example request

```bash
curl --request POST \
  --url 'https://api.kustomerapp.com/v1/customers/search' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "searchHash": "string",
  "queryContext": "string",
  "includeDeleted": true,
  "timeZone": "string",
  "and": {},
  "or": {}
}'
```
