> ## Documentation Index
> Fetch the complete documentation index at: https://docs.signalhire.com/llms.txt
> Use this file to discover all available pages before exploring further.

# People Search by Query Parameters

> Search for candidates in the SignalHire database using filters like title, location, company, and more.

## Overview

The Search API allows searching SignalHire's database of professionals using a wide variety of filters — job title, location, company, industry, experience, and more. Unlike the Person API, it does not require a known identifier. Results are returned as **brief profile overviews without contact details**, making it ideal for discovering new candidates or leads at scale.

Results are returned **synchronously** — the first batch is included directly in the response. For large result sets, subsequent batches are retrieved using a scroll mechanism similar to Elasticsearch: each response includes a `scrollId` that can be passed to the [Scroll Search](/search-api/scroll-search) endpoint to fetch the next batch.

A typical workflow:

1. Submit a `searchByQuery` request with filters — receive the first batch and a `scrollId`
2. Use [Scroll Search](/search-api/scroll-search) with the `scrollId` to page through remaining results
3. Pass interesting profile UIDs to the [Person API](/person-api/retrieve-person) to retrieve full contact details

<Info>
  Maximum **3 concurrent** Search API requests are allowed at a time.
</Info>

***

**Endpoint:** `POST https://www.signalhire.com/api/v1/candidate/searchByQuery`

## Request Parameters

**Header**

<ParamField header="apikey" type="string" required>
  Secret API key. See [Authentication](/authentication).
</ParamField>

**Body**

<ParamField body="currentTitle" type="string">
  Boolean query for current job title. Cannot be combined with `currentPastTitle` — if both are provided, `currentPastTitle` takes precedence. See [Boolean Query Guide](/search-api/boolean-query).
</ParamField>

<ParamField body="currentPastTitle" type="string">
  Boolean query for current or past job title. Takes precedence over `currentTitle` if both are provided.
</ParamField>

<ParamField body="location" type="string | array of strings">
  Geographical area for the search. Accepts a single city, state, or country as a string, or multiple locations as an array. Examples: `"Los Angeles, California"`, `["India", "Rome, Italy"]`. Returns `422` if the location cannot be recognized.
</ParamField>

<ParamField body="latitude" type="float">
  Latitude coordinate for geo-based search. Must be provided together with `longitude`. Searches within a 10km radius. Overrides `location` when set.
</ParamField>

<ParamField body="longitude" type="float">
  Longitude coordinate for geo-based search. Must be provided together with `latitude`.
</ParamField>

<ParamField body="coordinates" type="array of objects">
  Multiple geographic points to search around simultaneously. Each item must contain `latitude` and `longitude`. Overrides `location`. Used only when top-level `latitude`/`longitude` are not set. Each point uses a 10km radius.

  ```json theme={null}
  "coordinates": [
  { "latitude": 41.9028, "longitude": 12.4964 },
  { "latitude": 45.4642, "longitude": 9.1900 }
  ]
  ```
</ParamField>

<ParamField body="currentCompany" type="string">
  Boolean query for current company name.
</ParamField>

<ParamField body="currentPastCompany" type="string">
  Boolean query for current or past company name.
</ParamField>

<ParamField body="fullName" type="string">
  Search by full name.
</ParamField>

<ParamField body="keywords" type="string">
  Boolean query for skills, description, education, and other profile attributes.
</ParamField>

<ParamField body="industry" type="string">
  Filter by industry category. Returns `422` if the value is not recognized. See the full list of [allowed values](/search-api/industries).
</ParamField>

<ParamField body="industries" type="array of strings">
  Filter by multiple industry categories simultaneously. Each value must be a valid industry name from the [allowed values](/search-api/industries) list. Returns `422` if any value is not recognized. Use instead of `industry` when filtering by more than one industry.
</ParamField>

<ParamField body="yearsOfCurrentExperienceFrom" type="integer">
  Minimum years of experience in the current role and company.
</ParamField>

<ParamField body="yearsOfCurrentExperienceTo" type="integer">
  Maximum years of experience in the current role and company.
</ParamField>

<ParamField body="yearsOfCurrentPastExperienceFrom" type="integer">
  Minimum years of experience across all roles and companies.
</ParamField>

<ParamField body="yearsOfCurrentPastExperienceTo" type="integer">
  Maximum years of experience across all roles and companies.
</ParamField>

<ParamField body="education" type="string">
  Boolean query applied across university name, faculty, and degree. See [Boolean Query Guide](/search-api/boolean-query).
</ParamField>

<ParamField body="department" type="array of strings">
  Filter by department. Accepted values:
  `Marketing`, `Sales`, `Product & Project`, `Engineering / Development`, `Data & Analytics`, `Design / UX`, `HR & Recruitment`, `Finance & Accounting`, `Legal / Compliance`, `Customer Support / Success`, `Health, Beauty & Hospitality`, `Education & Training`, `Operations & Admin`, `Facility Services`, `Entertainment / Production`
</ParamField>

<ParamField body="level" type="array of strings">
  Filter by seniority level. Accepted values:
  `Intern / Entry Level`, `Junior`, `Mid-Level`, `Senior`, `Lead`, `Head`, `VP`, `C-Level`, `Founder / Owner`, `Board / Advisory`, `Directors`
</ParamField>

<ParamField body="openToWork" type="boolean">
  Filter by open-to-work status.
</ParamField>

<ParamField body="excludeRevealed" type="boolean">
  Exclude profiles for which contacts have already been fetched.
</ParamField>

<ParamField body="excludeWatched" type="boolean">
  Exclude profiles already viewed in the web app or browser extension.
</ParamField>

<ParamField body="excludeInLists" type="boolean">
  Exclude profiles already added to a list.
</ParamField>

<ParamField body="excludeInProgress" type="boolean">
  Exclude profiles already added to a job.
</ParamField>

<ParamField body="excludeEmailed" type="boolean">
  Exclude profiles already emailed.
</ParamField>

<ParamField body="size" type="integer">
  Number of profiles to return per batch. Default: `10`, must be between `1` and `100`. Returns `422` if outside this range.
</ParamField>

<Warning>
  At least one non-exclude filter must be provided — an empty request returns `422`. Exclude filters (`excludeRevealed`, `excludeWatched`, etc.) cannot be used as the only filters.
</Warning>

## Location Formats

The `location` filter supports three levels of granularity. The value is resolved in this order:

**Country** — pass the full English country name. Searches the entire country.

```json theme={null}
"location": "Germany"
"location": ["India", "Brazil"]
```

**State or Province** — supported for the United States and Canada. The country suffix is optional.

```json theme={null}
"location": "California"
"location": "California, United States"
"location": "Ontario, Canada"
```

**City** — pass a city name with enough context to identify it unambiguously. Searches within a 10km radius of the city center.

```json theme={null}
"location": "Miami, Florida"
"location": "London, United Kingdom"
"location": "Berlin, Germany"
```

If the value cannot be resolved to any known location, the request returns HTTP `422` with `"Location is not recognized"`.

For precise geo-based search, use `latitude`/`longitude` or `coordinates` instead — they bypass text resolution entirely.

## Request Example

This example searches for profiles in New York whose current job title contains "Software Engineer" or "Developer", and who have both PHP and JavaScript mentioned in their profile.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://www.signalhire.com/api/v1/candidate/searchByQuery \
  -H 'apikey: your_secret_api_key' \
  --data '{
  "currentTitle": "(Software AND Engineer) OR Developer",
  "location": "New York, New York, United States",
  "keywords": "PHP AND JavaScript"
  }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
  "https://www.signalhire.com/api/v1/candidate/searchByQuery",
  headers={"apikey": "your_secret_api_key"},
  json={
  "currentTitle": "(Software AND Engineer) OR Developer",
  "location": "New York, New York, United States",
  "keywords": "PHP AND JavaScript"
  }
  )
  ```

  ```javascript Node.js theme={null}
  const axios = require('axios');

  const response = await axios.post(
  'https://www.signalhire.com/api/v1/candidate/searchByQuery',
  {
      currentTitle: '(Software AND Engineer) OR Developer',
      location: 'New York, New York, United States',
      keywords: 'PHP AND JavaScript'
  },
  {
      headers: { apikey: 'your_secret_api_key' }
  }
  );
  ```

  ```java Java theme={null}
  import java.net.http.*;
  import java.net.URI;

  HttpClient client = HttpClient.newHttpClient();

  String body = """
  {
      "currentTitle": "(Software AND Engineer) OR Developer",
      "location": "New York, New York, United States",
      "keywords": "PHP AND JavaScript"
  }
  """;

  HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://www.signalhire.com/api/v1/candidate/searchByQuery"))
  .header("apikey", "your_secret_api_key")
  .header("Content-Type", "application/json")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();

  HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
  ```

  ```ruby Ruby theme={null}
  require 'net/http'
  require 'json'

  uri = URI('https://www.signalhire.com/api/v1/candidate/searchByQuery')
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri)
  request['apikey'] = 'your_secret_api_key'
  request['Content-Type'] = 'application/json'
  request.body = {
      currentTitle: '(Software AND Engineer) OR Developer',
      location: 'New York, New York, United States',
      keywords: 'PHP AND JavaScript'
  }.to_json

  response = http.request(request)
  ```
</CodeGroup>

## Response Example (HTTP 200)

```http theme={null}
HTTP/2 200
Content-Type: application/json
X-Credits-Left: 243
```

```json theme={null}
{
    "requestId": 3,
    "total": 12,
    "scrollId": "abc123",
    "profiles": [
    {
        "uid": "10000000000000000000000000001006",
        "fullName": "Aaron Smith",
        "location": "London, United Kingdom",
        "experience": [
            { "company": "Saward Dawson", "title": "Accountant" }
        ],
        "skills": ["Accounting", "Analysis"],
        "contactsFetched": null,
        "openToWork": false
    }
]
}
```

### Response Fields

| Field       | Description                                                                                                                         |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `requestId` | ID of this search. Required for [Scroll Search](/search-api/scroll-search).                                                         |
| `total`     | Total matching profiles across all pages.                                                                                           |
| `profiles`  | First batch of results. See [Search Profile Object](/search-api/search-profile-object) for field reference.                         |
| `scrollId`  | Present when `total > size`. Pass to [Scroll Search](/search-api/scroll-search) to fetch the next batch. Expires in **15 seconds**. |

For other possible response codes see [Response Codes](/response-codes).

## Search Quota

Search requests are not billed per credit — they count against a **daily search quota**. This quota is shared between the SignalHire website and the API, so searches made in either place consume from the same daily limit.

The daily quota covers two dimensions independently: the **number of search queries** and the **total number of profiles returned** across all searches. Both are tracked separately and either can be exhausted first depending on usage patterns.

When the daily quota is exhausted, further search requests return HTTP `402` with an error message. The quota resets daily.

There is also a concurrency limit: a maximum of **3 Search API requests** can be in progress at the same time. Exceeding this returns HTTP `429`.
