You can search for multiple contacts by the value of their attributes in order to fetch exactly who you want.
To search for contacts, you need to send a POST request to https://api.intercom.io/contacts/search. This will accept a query object in the body which will define your filters in order to search for contacts.
If a contact has recently been created, there is a possibility that it will not yet be available when searching. This means that it may not appear in the response. This delay can take a few minutes. If you need to be instantly notified then you could use webhooks instead, which you'd currently have to iterate on to see if they match your search filters.
You should provide the following parameters within a query object:
| Parameter | Required? | Description |
|---|---|---|
| field | Yes | The fields associated to a customer that you can search for. See all accepted fields below. |
| operator | Yes | The operator that you want to compare by. See all accepted operators below. |
| value | Yes | The value you want to search by. |
You can search with multiple filters by combining a list of single filter objects within a value array and saying whether you want to ensure all given values match (AND), or only one of these match (OR). The query object should contain these parameters.
| Parameter | Required? | Description |
|---|---|---|
| operator | Yes | The operator (AND or OR) by which to query the combined values. |
| value | Yes | An array of single query objects. |
If you're only using OR to check that one matches out of the values, you could instead use IN as the operator in a single filter query. You could also use NIN to say that it does not match one of the values.
You can nest these filters in order to get even more granular insights that pinpoint exactly what you need. Example: (1 OR 2) AND (3 OR 4).\n\nThere are some limitations to the amount of multiple's there can be:\n\n_ There's a limit of max 2 nested filters\n_ There's a limit of max 15 filters for each AND or OR group
{\n \"query\": {\n \"field\": \"custom_attributes.salesforce_status\",\n \"operator\": \"~\",\n \"value\": \"open\"\n }\n}{\n \"query\": {\n \"operator\": \"AND\",\n \"value\": [\n {\n \"field\": \"custom_attributes.social_network\",\n \"operator\": \"=\",\n \"value\": \"facebook\"\n }, \n {\n \"field\": \"custom_attributes.social_network\",\n \"operator\": \"=\",\n \"value\": \"twitter\"\n },\n {\n \"field\": \"custom_attributes.social_network\",\n \"operator\": \"=\",\n \"value\": \"instagram\"\n }\n ]\n }\n}{\n \"query\": {\n \"field\": \"custom_attributes.social_network\",\n \"operator\": \"IN\",\n \"value\": [\"facebook\", \"twitter\", \"instagram\"]\n }\n}{\n \"query\": {\n \"operator\": \"AND\",\n \"value\": [\n {\n \"operator\": \"OR\",\n \"value\": [\n {\n \"field\": \"created_at\",\n \"operator\": \">\",\n \"value\": 1560436650\n }, \n {\n \"field\": \"signed_up_at\",\n \"operator\": \">\",\n \"value\": 1560436784\n }\n ]\n },\n {\n \"operator\": \"OR\",\n \"value\": [\n {\n \"field\": \"custom_attributes.salseforce_status\",\n \"operator\": \"~\",\n \"value\": \"Open\"\n }, \n {\n \"field\": \"custom_attributes.salesforce_object_type\",\n \"operator\": \"=\",\n \"value\": \"Lead\"\n }\n ]\n }\n ]\n }\n}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "bad_request",
"message": "bad 'random_param' parameter"
}
]
}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "invalid_query",
"message": "Invalid query. Ensure 'field', 'operator', 'value' are present for field queries. Ensure 'operator' and 'value' for composite queries."
}
]
}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "invalid_values",
"message": "Value depth exceeds 10 items"
}
]
}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "invalid_value",
"message": "123 is not a valid string"
}
]
}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "invalid_field",
"message": "not_a_field is not a valid field"
}
]
}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "invalid_operator",
"message": "Composite operators must be of type AND or OR "
}
]
}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "invalid_operator",
"message": "email does not support operator: >"
}
]
}HTTP/1.1 400 BAD REQUEST
{
"type": "error.list",
"request_id": null,
"errors": [
{
"code": "invalid_value",
"message": "Number of elements in composite query is greater than 15, please try again with a smaller list"
}
]
}Contacts that have been merged are excluded from search results. If a contact was recently merged into another, it will no longer appear in queries filtered by updated_at or any other field. Only the target contact from the merge remains searchable.
All timestamp fields (created_at, updated_at etc.) and Date custom attributes are indexed as Dates for Contact Search queries; Datetime queries are not currently supported. This means you can only query for timestamp fields by day - not hour, minute or second. A contact's value is placed in a day using your workspace's timezone, so the same query can return different results across workspaces in different timezones.
Because the value is truncated to a day, = matches the whole day, > matches from the start of the next day (not from the instant you submitted), and < matches everything before the start of that day. The !=, >=, <=, IN and NIN operators are not supported on Date fields and return an error.
For example, on a workspace set to UTC, searching for all Contacts with a created_at value greater (>) than 1577869200 (the Unix timestamp for January 1st, 2020 9:00 AM UTC) interprets that value as 1577836800 (January 1st, 2020 12:00 AM UTC). Because > starts at the next day, the results include Contacts created from January 2nd, 2020 12:00 AM UTC onwards - not from 9:00 AM on January 1st. To get Contacts created on January 1st, search with a created_at value equal (=) to 1577836800 instead.
On a workspace in another timezone, the same query truncates to that timezone's midnight instead, so both boundaries shift.
This behaviour applies only to timestamps used in search queries. The search results will still contain the full Unix timestamp and be sorted accordingly.
Most key listed as part of the Contacts Model are searchable, whether writeable or not. The value you search for has to match the accepted type, otherwise the query will fail (ie. as created_at accepts a date, the value cannot be a string such as "foorbar").
| Field | Type |
|---|---|
| id | String |
| role | String Accepts user or lead |
| name | String |
| avatar | String |
| owner_id | Integer |
| String | |
| phone | String |
| external_id | String |
| created_at | Date (Unix timestamp in seconds) |
| signed_up_at | Date (Unix timestamp in seconds) |
| updated_at | Date (Unix timestamp in seconds) |
| last_seen_at | Date (Unix timestamp in seconds) |
| last_contacted_at | Date (Unix timestamp in seconds) |
| last_replied_at | Date (Unix timestamp in seconds) |
| last_email_opened_at | Date (Unix timestamp in seconds) |
| last_email_clicked_at | Date (Unix timestamp in seconds) |
| language_override | String |
| browser | String |
| browser_language | String |
| os | String |
| location.country | String |
| location.region | String |
| location.city | String |
| unsubscribed_from_emails | Boolean |
| marked_email_as_spam | Boolean |
| has_hard_bounced | Boolean |
| ios_last_seen_at | Date (Unix timestamp in seconds) |
| ios_app_version | String |
| ios_device | String |
| ios_app_device | String |
| ios_os_version | String |
| ios_app_name | String |
| ios_sdk_version | String |
| android_last_seen_at | Date (Unix timestamp in seconds) |
| android_app_version | String |
| android_device | String |
| android_app_name | String |
| andoid_sdk_version | String |
| segment_id | String |
| tag_id | String |
| custom_attributes.{attribute_name} | String |
The table below shows the operators you can use to define how you want to search for the value. The operator should be put in as a string ("="). The operator has to be compatible with the field's type (eg. you cannot search with > for a given string value as it's only compatible for integer's and dates).
| Operator | Valid Types | Description |
|---|---|---|
| = | All | Equals |
| != | All except Date | Doesn't Equal |
| IN | All except Date | In Shortcut for OR queriesValues must be in Array |
| NIN | All except Date | Not In Shortcut for OR ! queriesValues must be in Array |
| > | Integer Date (Unix timestamp in seconds) | Greater than On Date fields, matches from the start of the next day |
| < | Integer Date (Unix timestamp in seconds) | Lower than On Date fields, matches before the start of the day |
| >= | Integer | Greater than or equal to Not supported on Date fields |
| <= | Integer | Lower than or equal to Not supported on Date fields |
| ~ | String | Contains |
| !~ | String | Doesn't Contain |
| ^ | String | Starts With |
| $ | String | Ends With |
A JSON payload with a list of Contact model that match the search query, with a total_count integer saying how many models have been returned.