> For a complete page index, fetch https://developer.close.com/llms.txt # Advanced Filtering ### Tutorial The Advanced Filtering API allows you to use arbitrary filters to find Leads or Contacts with specific attributes. To use the Advanced Filtering API, make a POST request to `/api/v1/data/search/` with your JSON filters in the request body. Let’s consider a simple example of finding all Contacts with CEOs you have on file in Close. The example POST request data with the query would look like this: ```json { "query": { "type": "and", "queries": [ { "type": "object_type", "object_type": "contact" }, { "type": "field_condition", "field": { "type": "regular_field", "object_type": "contact", "field_name": "title" }, "condition": { "type": "text", "mode": "full_words", "value": "CEO" } } ] } } ``` The request consists of a top level "and" query which combines two constraints on what would be returned: - An `object_type` query that tells the API that you’re interested in finding Contacts. - A `field_condition` query that asks for Contacts that have a title value containing a word `"CEO"`. Every query has a "type" that distinguishes the way you filter through objects. The first part of the example query is `"type": "object_type"`. It specifies that you only want objects of type Contact returned in the response. The second part of the example query is `"field_condition"`. Field condition queries specify the field you want to match against (in this case `"title"`), and the values you want to match it to (i.e. `"CEO"`). The `field` in this example is a `"regular_field"` named `"title"` on a `"contact"` object. There can be other kinds of fields as well, like [Contact Custom Fields](https://developer.close.com/api/resources/custom-fields/custom-fields-contact/list). The field `condition` here is a simple "text" condition. It matches against the text "CEO", so any contact that have a title containing word "CEO" will be returned. Here’s an example response: ```json { "data": [ { "__object_type": "contact", "id": "cont_PtENYt1P6sRWkcnqoGnIj6hcZammGPdVbTXJWqdTvpV" }, { "__object_type": "contact", "id": "cont_HjTcJFiNli2AKf5fioygQDVSpA9nJILI9SkKv3nBk0A" }, { "__object_type": "contact", "id": "cont_LXQqW8mvD0BbCR6qhRPbzPZF7gCbXQIw6GD8vqKipss" } ], "cursor": null } ``` ### More complex query A more complicated example would be finding CEOs of SaaS companies that have at least one email address. ```json { "query": { "type": "and", "queries": [ { "type": "object_type", "object_type": "contact" }, { "type": "field_condition", "field": { "type": "regular_field", "object_type": "contact", "field_name": "emails_count" }, "condition": { "type": "number_range", "gt": 1 } }, { "type": "field_condition", "field": { "type": "regular_field", "object_type": "contact", "field_name": "title" }, "condition": { "type": "text", "mode": "full_words", "value": "CEO" } }, { "type": "has_related", "this_object_type": "contact", "related_object_type": "lead", "related_query": { "type": "field_condition", "field": { "type": "custom_field", "custom_field_id": "cf_B57sofuEB7OBneH86SJctTr7hfiAiQcgkGRbAQfha0Z" }, "condition": { "type": "term", "values": ["Software as a service"] }, "negate": false } } ] } } ``` In this query you can see several new concepts: - A different condition for a field that represents a `"number_range"` as opposed to just textual match. `gt: 1` means greater than one. - A field type "custom_field" that references a Lead Custom Field by its id. - A `"has_related"` query that lets you match on data from a different related object rather than the one you want returned, in this case a Lead. If the examples here don't cover your use case, check out [Visual Query Builder](#visual-query-builder) for help with building a query structure tailored to your needs. ### Visual Query Builder Instead of composing the JSON query structure by hand, you can build your query visually on the [Leads Page](https://app.close.com/leads/) or [Contacts page](https://app.close.com/contacts/) in Close app, and then copy the JSON query structure by clicking the triple-dot menu on the top right and selecting "Copy Filters". ![Advanced Filtering](/_fern-files/close.docs.buildwithfern.com/1e53f0c1bf29f5de058f69b9a2d0036f84a5f9eea01670427af10c905befa90d/docs/pages/resources/assets/copy_filters.gif) ### Output control By default, the Advanced Filtering API only returns the IDs of the matched objects to improve performance. If you want to get more the data for the object, you will need to pass a `_fields` object to specify which fields you want returned for the object you're filtering for. For example: ```json { "query": ..., "_fields": { "contact": ["id", "name", "title"] } } ``` The fields are exactly the same as ones in REST API for corresponding object types. This results in the following: ```json { "data": [ { "__object_type": "contact", "id": "cont_HjTcJFiNli2AKf5fioygQDVSpA9nJILI9SkKv3nBk0A", "name": "Bruce Wayne", "title": "The Dark Knight" }, { "__object_type": "contact", "id": "cont_LXQqW8mvD0BbCR6qhRPbzPZF7gCbXQIw6GD8vqKipss", "name": "Steli Efti", "title": "CEO & Co-Founder" } ] } ``` ### Results limit If you want to only get first N results, you can specify a results limit. Limiting results might be useful if you have 1000 objects but you want to act only on the first 100. ```json { "query": ..., "results_limit": 100, } ``` Note that this limits the number returned in the overall result set and is separate from pagination. ### Results count Sometimes you might want to know how many results there are. For performance, they are not included by default. Request them explicitly with `include_counts` flag. ```json { "query": ..., "include_counts": true, } ``` In the response, you'll get a `count` object. ```json { "data": [...], "count": { "limited": 3, "total": 3 } } ``` If you don't need the actual results but only care about the number, set the [`results_limit`](#results-limit) to zero. ```json { "query": ..., "include_counts": true, "results_limit": 0 } ``` In the response, the `total` count is the number you're interested in. ```json { "data": [], "count": { "limited": 0, "total": 3 } } ``` ### Sorting You can sort the objects returned using a `sort` field whose value is a list of fields and their respective sort directions. In this example, we sort Contacts by title. ```json { "query": ..., "sort": [ { "direction": "asc", "field": { "object_type": "contact", "type": "regular_field", "field_name": "title" } } ] } ``` Sorting can be in either `asc` or `desc` direction. Only numbers, dates, and text fields that belong directly to an object can be used for sorting. References/ID fields or fields from other objects cannot be used for sorting. ### Pagination A single request only returns a page worth of results. You can control how many results you want on one page using the `_limit` field, and ask for the next pages by sending the `cursor` field populated with a value from a previous response. ```js { "query": ..., "_limit": 10, "cursor": "" // <- cursor value from previous response } ``` When the cursor value you're received in your most recent response is `null`, it means that you've reached the last page and no more results are available. Cursors expire after 30 seconds; if you try to use an expired cursor you'll get an `Expired cursor` error. We have a hard limit of 10,000 objects when paginating. If you need to paginate for more than 10,000 results, update your query to return smaller batches of objects. A popular method to do this would be to use the `date_created` field as a range, and make multiple requests while incrementing or decrementing the date. Note: When paginating, be sure to use a sort that won’t change often like `date_created`, so that you won’t miss any results if the sort order changes between individual page requests. ### Available query types #### ID query Matches a single object directly by its ID. ```json { "type": "id", "value": "cont_abcdef" } ``` #### Object type Specify the object type that the API should return (i.e. `contact` or `lead`) ```json { "object_type": "contact", "type": "object_type" } ``` #### Text query Filter for text across most text-like fields on an object. ```json { "type": "text", "value": "Bruce", "mode": "full_words" } ``` The two available modes are: - `full_words` searches all specified words anywhere in the text but disregards position of the words. - `phrase` searches the words in specified order next to each other. #### Has related A `has_related` query lets you filter for a Contact based on data of the Lead they belong to, as well as individual email address and phone number records. ```json { "type": "has_related", "this_object_type": "contact", "related_object_type": "lead", "related_query": { "field": { "object_type": "lead", "type": "regular_field", "field_name": "source" }, "condition": ..., } ``` #### Query negation All queries support negation. By specifying `"negate": true`, everything that **matches** the query will not be returned, and everything that doesn't match the query will. #### Combining queries with AND/OR To get objects that match multiple conditions all at once (AND) or at least one of the conditions, use and/or queries. ```json { "type": "and", "queries": [ query1, query2, query3 ] } { "type": "or", "queries": [ query1, query2, query3 ] } ``` #### Field Value Condition Query Match Contacts where the value in a specific field fits the Field Condition. ```json { "type": "field_condition", "field": { "type": "regular_field", "object_type": "contact", "field_name": "emails_count" }, "condition": { "type": "number_range", "gt": 1 } } ``` There can be two field types: regular fields and custom fields. ```json { "field": { "type": "regular_field", "object_type": "contact", "field_name": "name" } } ``` Custom fields: ```json { "field": { "type": "custom_field", "custom_field_id": "cf_abcdef" } } ``` If you're unsure what query type to use, try the [Visual Query Builder](#visual-query-builder). ### Field Conditions Field Conditions are conditions that apply to individual field values as opposed to entire object. #### Boolean A yes/no value. ```json { "type": "boolean", "value": true } ``` #### Current user Represents a reference to a currently authenticated user, also known as "me". Use with fields like `created_by`. ```json { "type": "current_user" } ``` #### Exists Matches if the field is set to some value. Null or missing fields do not match. ```json { "type": "exists" } ``` #### Text Filters for text in the field value. Similar to Text query. ```json { "type": "text", "value": "Bruce", "mode": "full_words" } ``` #### Term Matches one or multiple specific Enumeration or Choices values. ```json { "type": "term", "values": ["draft", "sent"] } ``` #### Reference Matches specific object IDs in reference fields like User ID or Lead Status IDs. ```json { "type": "reference", "reference_type": "user", "object_ids": ["user_abc", "user_def"] } ``` ### Most commonly used fields **For Contact:** Object type: `contact` - `created_by`: User ID - `date_created`: datetime - `date_updated`: datetime - `emails_count`: integer - `lead_id`: Lead ID - `phones_count`: integer - `title`: text - `updated_by`: User ID - `urls_count`: integer **For Lead:** Object type: `lead` - `addresses_count`: integer - `all_urls_count`: integer - `created_by`: User ID - `date_created`: datetime - `date_updated`: datetime - `description`: text - `display_name`: text - `status_id`: Lead Status ID - `updated_by`: User ID - `url`: url **For Contact Phones:** Object type: `contact_phone` - `type`: text - `phone`: text **For Contact Emails:** Object type: `contact_email` - `type`: text - `email`: email address **For Contact URLs:** Object type: `contact_url` - `type`: text - `url`: url **For Addresses:** Object type: `address` - `address_1`: text - `address_2`: text - `city`: text - `country`: text - `location`: text - `state`: text - `zipcode`: text > Use the Advanced Filtering API to find Leads or Contacts matching arbitrary filter criteria.