> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.brightmove.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.brightmove.com/_mcp/server.

# Search applicants

POST https://app.brightmove.com/ATS/api/v1/applicants/search
Content-Type: application/json

Runs a full-text and filter-based search across applicants visible to the authenticated user.

The request's `fields` list contains one entry per searchable field. Each field carries its own modifiers:

- `required` — AND
- `excluded` — NOT
- optional exact-match, date and numeric ranges
- nested OR-grouped sub-fields

Pagination is controlled with `pageSize` and `startRecord`.


Reference: https://docs.brightmove.com/public/applicants/search/search-3

## Authentication

- `Authorization` header (bearer token, required) — BrightMove OAuth2 client_credentials - use the client_id/client_secret from User > API Keys (or an admin-managed client).

## Request

### Body (application/json)

This endpoint expects an ApplicantSearchRequest.

- `fields` (list of SearchField, optional) — List of per-field criteria. An empty or omitted list returns all applicants visible to the authenticated user, subject to pagination.
- `pageSize` (integer, optional) — Number of results to return per page. Defaults to 25 if omitted. Capped at 100 by the server.
- `startRecord` (integer, optional) — Zero-based offset of the first record to return. Use multiples of 'pageSize' to page through results.
- `orderBy` (string, optional) — Name of the field to sort by. Defaults to 'score' (relevance) when omitted.
- `orderDir` (string, optional) — Sort direction: 'asc' or 'desc'.
- `location` (string, optional) — Geo-spatial centre point for radius searches (postal code or city/state).
- `radius` (integer, optional) — Geo-spatial search radius in miles, applied around 'location'.
- `searchChildCompanies` (boolean, optional) — When true, also search applicants belonging to the authenticated user's managed child companies.
- `searchDeleted` (boolean, optional) — When true, include soft-deleted applicants in the results.
- `returnFields` (list of string, optional) — Optional list of additional field names to populate on each hit, on top of the default set that is always returned. Field names must come from the catalog returned by GET /api/v1/applicants/search/fields and only entries flagged returnable=true in that catalog can be projected — fields with returnable=false are searchable but not stored, so listing them here has no effect on the response. The default set (always returned, regardless of this parameter) is: guid, applicant_gk, company_gk, first_name, last_name, status_id, vendor_gk, vendor_name, placement_start_date, placement_ending_date, placement_type_id, email_allowed, email, avatar_url, do_not_hire, score. When 'searchChildCompanies' is true, 'company_name' is also included by default. Use this parameter to pull in extra fields such as additional applicant attributes or UDFs.

## Response

### 200

Search results returned

## Types

### SearchField

A single field-level search criterion. Combine multiple entries inside ApplicantSearchRequest.fields to build a multi-criteria search.

- `field` (string, required) — The indexed field to search against (e.g. 'first_name', 'last_name', 'resume_text', 'applstat_name', 'current_title'). Use GET /api/v1/applicants/search/fields to enumerate the valid values.
- `term` (string, optional) — The search term or value to match against the field. For date and numeric range criteria use the dedicated startDate/endDate or numberQueryStart/numberQueryEnd fields instead.
- `displayTerm` (string, optional) — Optional human-readable rendering of the term for display in UIs. The server treats this as informational only; matching is performed against 'term'.
- `fieldLabel` (string, optional) — Optional human-readable label for the field, used by clients for UI rendering.
- `fieldTypeId` (integer, optional) — Optional explicit data-type hint. When omitted, the server infers the type from the criterion's other populated inputs: a present startDate/endDate implies DATE, a present numberQueryStart/numberQueryEnd implies NUMBER, and anything else is treated as TEXT. Specify explicitly only when you need to override the inferred default (for example to search a CURRENCY field). Allowed values: 1=TEXT, 2=TEXTAREA, 3=CHECKBOX, 4=SELECT, 5=NUMBER, 6=CURRENCY, 7=DATE, 8=TIME.
- `required` (boolean, optional) — When true the criterion must match (AND clause). Mutually exclusive with 'excluded'.
- `excluded` (boolean, optional) — When true the criterion must NOT match (NOT clause). Mutually exclusive with 'required'.
- `exactMatch` (boolean, optional) — When true the term is treated as an exact phrase rather than a tokenised match.
- `startDate` (string, optional) — Inclusive lower bound for date-typed criteria, as an ISO-8601 instant.
- `endDate` (string, optional) — Inclusive upper bound for date-typed criteria, as an ISO-8601 instant.
- `before` (boolean, optional) — Date-range operator: match records whose value is strictly before 'startDate'.
- `after` (boolean, optional) — Date-range operator: match records whose value is strictly after 'startDate'.
- `between` (boolean, optional) — Date-range operator: match records whose value falls between 'startDate' and 'endDate'.
- `numberQueryStart` (integer, optional) — Inclusive lower bound for numeric range criteria.
- `numberQueryEnd` (integer, optional) — Inclusive upper bound for numeric range criteria.
- `location` (boolean, optional) — Flags this criterion as a geo-spatial filter. Use the top-level 'location' and 'radius' on ApplicantSearchRequest to supply the centre point and search radius.
- `subFields` (list of SearchField, optional) — Optional OR-grouped sub-criteria. When present, the parent criterion matches if any of the subFields match. Sub-fields follow the same schema and may themselves be nested.

## Examples

**Request**

```json
{}
```

**Response**

```json
{}
```

**SDK Code**

```python
import requests

url = "https://app.brightmove.com/ATS/api/v1/applicants/search"

payload = {}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://app.brightmove.com/ATS/api/v1/applicants/search';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://app.brightmove.com/ATS/api/v1/applicants/search"

	payload := strings.NewReader("{}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://app.brightmove.com/ATS/api/v1/applicants/search")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://app.brightmove.com/ATS/api/v1/applicants/search")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://app.brightmove.com/ATS/api/v1/applicants/search', [
  'body' => '{}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://app.brightmove.com/ATS/api/v1/applicants/search");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://app.brightmove.com/ATS/api/v1/applicants/search")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```