> ## 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.

# Full People Search Example with Code

> End-to-end example of fetching all search results using searchByQuery and scrollSearch.

## Overview

This example shows how to fetch all matching profiles from a search query by combining `searchByQuery` with `scrollSearch`. Each batch is saved to the database immediately as it arrives — rather than collecting everything in memory first — to minimize memory usage and avoid data loss if the process is interrupted.

The pattern is:

1. Send the initial `searchByQuery` request — save the first batch, get a `scrollId`
2. Loop: save each batch, send `scrollSearch` with the new `scrollId`
3. Stop when no `scrollId` is returned in the response

<Warning>
  The next `scrollSearch` request must be sent within **15 seconds** of the previous response. Do not perform slow operations (heavy processing, external API calls) between scroll requests — save to the database and immediately request the next batch.
</Warning>

<CodeGroup>
  ```python Python theme={null}
  import requests
  import psycopg2
  import json

  API_KEY = "your_secret_api_key"
  BASE_URL = "https://www.signalhire.com/api/v1/candidate"
  HEADERS = {"apikey": API_KEY, "Content-Type": "application/json"}

  def save_batch(cur, profiles: list):
  for profile in profiles:
  cur.execute(
  """
  INSERT INTO candidates (uid, full_name, location, skills, open_to_work, raw_data)
  VALUES (%s, %s, %s, %s, %s, %s)
  ON CONFLICT (uid) DO UPDATE SET
  full_name = EXCLUDED.full_name,
  location = EXCLUDED.location,
  skills = EXCLUDED.skills,
  open_to_work = EXCLUDED.open_to_work,
  raw_data = EXCLUDED.raw_data
  """,
  (
  profile["uid"],
  profile.get("fullName"),
  profile.get("location"),
  json.dumps(profile.get("skills", [])),
  profile.get("openToWork", False),
  json.dumps(profile),
  )
  )

  def search_and_save(query: dict):
  conn = psycopg2.connect("postgresql://user:password@localhost/mydb")
  cur = conn.cursor()
  total_saved = 0

  # Initial search
  response = requests.post(f"{BASE_URL}/searchByQuery", headers=HEADERS, json=query)
  response.raise_for_status()
  data = response.json()

  request_id = data["requestId"]
  scroll_id = data.get("scrollId")
  total = data["total"]
  print(f"Total profiles found: {total}")

  save_batch(cur, data.get("profiles", []))
  conn.commit()
  total_saved += len(data.get("profiles", []))
  print(f"Saved {total_saved} / {total}")

  # Scroll through remaining batches
  while scroll_id:
  response = requests.post(
  f"{BASE_URL}/scrollSearch/{request_id}",
  headers=HEADERS,
  json={"scrollId": scroll_id}
  )
  response.raise_for_status()
  data = response.json()

  save_batch(cur, data.get("profiles", []))
  conn.commit()
  total_saved += len(data.get("profiles", []))
  scroll_id = data.get("scrollId")
  print(f"Saved {total_saved} / {total}")

  cur.close()
  conn.close()
  print("Done")

  search_and_save({
  "currentTitle": "(Software AND Engineer) OR Developer",
  "location": "New York, New York, United States",
  "keywords": "PHP AND JavaScript",
  "size": 50
  })
  ```

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

  const API_KEY = 'your_secret_api_key';
  const BASE_URL = 'https://www.signalhire.com/api/v1/candidate';
  const HEADERS = { apikey: API_KEY, 'Content-Type': 'application/json' };

  const pool = new Pool({ connectionString: 'postgresql://user:password@localhost/mydb' });

  async function saveBatch(client, profiles) {
  for (const profile of profiles) {
  await client.query(
  `INSERT INTO candidates (uid, full_name, location, skills, open_to_work, raw_data)
     VALUES ($1, $2, $3, $4, $5, $6)
     ON CONFLICT (uid) DO UPDATE SET
       full_name = EXCLUDED.full_name,
       location = EXCLUDED.location,
       skills = EXCLUDED.skills,
       open_to_work = EXCLUDED.open_to_work,
       raw_data = EXCLUDED.raw_data`,
  [
  profile.uid,
  profile.fullName ?? null,
  profile.location ?? null,
  JSON.stringify(profile.skills ?? []),
  profile.openToWork ?? false,
  JSON.stringify(profile),
  ]
  );
  }
  }

  async function searchAndSave(query) {
  const client = await pool.connect();
  let totalSaved = 0;

  try {
  // Initial search
  const initial = await axios.post(`${BASE_URL}/searchByQuery`, query, { headers: HEADERS });
  const { requestId, total } = initial.data;
  let scrollId = initial.data.scrollId;

  console.log(`Total profiles found: ${total}`);

  await client.query('BEGIN');
  await saveBatch(client, initial.data.profiles);
  await client.query('COMMIT');
  totalSaved += initial.data.profiles.length;
  console.log(`Saved ${totalSaved} / ${total}`);

  // Scroll through remaining batches
  while (scrollId) {
  const response = await axios.post(
  `${BASE_URL}/scrollSearch/${requestId}`,
  { scrollId },
  { headers: HEADERS }
  );

  scrollId = response.data.scrollId;

  await client.query('BEGIN');
  await saveBatch(client, response.data.profiles);
  await client.query('COMMIT');
  totalSaved += response.data.profiles.length;
  console.log(`Saved ${totalSaved} / ${total}`);
  }

  console.log('Done');
  } catch (err) {
  await client.query('ROLLBACK');
  throw err;
  } finally {
  client.release();
  await pool.end();
  }
  }

  searchAndSave({
  currentTitle: '(Software AND Engineer) OR Developer',
  location: 'New York, New York, United States',
  keywords: 'PHP AND JavaScript',
  size: 50,
  }).catch(console.error);
  ```

  ```java Java theme={null}
  import java.net.http.*;
  import java.net.URI;
  import java.sql.*;
  import com.fasterxml.jackson.databind.ObjectMapper;
  import java.util.*;

  public class SignalHireSearch {
  private static final String API_KEY = "your_secret_api_key";
  private static final String BASE_URL = "https://www.signalhire.com/api/v1/candidate";
  private static final HttpClient client = HttpClient.newHttpClient();
  private static final ObjectMapper mapper = new ObjectMapper();

  static void saveBatch(Connection conn, List<Map<String, Object>> profiles) throws Exception {
  String sql = """
  INSERT INTO candidates (uid, full_name, location, open_to_work, raw_data)
  VALUES (?, ?, ?, ?, ?::jsonb)
  ON CONFLICT (uid) DO UPDATE SET
  full_name = EXCLUDED.full_name,
  location = EXCLUDED.location,
  open_to_work = EXCLUDED.open_to_work,
  raw_data = EXCLUDED.raw_data
  """;
  try (PreparedStatement stmt = conn.prepareStatement(sql)) {
  for (Map<String, Object> profile : profiles) {
  stmt.setString(1, (String) profile.get("uid"));
  stmt.setString(2, (String) profile.get("fullName"));
  stmt.setString(3, (String) profile.get("location"));
  stmt.setBoolean(4, Boolean.TRUE.equals(profile.get("openToWork")));
  stmt.setString(5, mapper.writeValueAsString(profile));
  stmt.addBatch();
  }
  stmt.executeBatch();
  }
  }

  static Map<String, Object> post(String path, Object body) throws Exception {
  String json = mapper.writeValueAsString(body);
  HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(BASE_URL + path))
  .header("apikey", API_KEY)
  .header("Content-Type", "application/json")
  .POST(HttpRequest.BodyPublishers.ofString(json))
  .build();
  HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
  return mapper.readValue(response.body(), Map.class);
  }

  public static void searchAndSave(Map<String, Object> query) throws Exception {
  try (Connection conn = DriverManager.getConnection(
  "jdbc:postgresql://localhost/mydb", "user", "password")) {

  conn.setAutoCommit(false);
  int totalSaved = 0;

  // Initial search
  Map<String, Object> data = post("/searchByQuery", query);
  int requestId = (int) data.get("requestId");
  int total = (int) data.get("total");
  String scrollId = (String) data.get("scrollId");

  System.out.println("Total profiles found: " + total);

  saveBatch(conn, (List) data.get("profiles"));
  conn.commit();
  totalSaved += ((List) data.get("profiles")).size();
  System.out.println("Saved " + totalSaved + " / " + total);

  // Scroll through remaining batches
  while (scrollId != null) {
  Map<String, Object> scrollData = post(
  "/scrollSearch/" + requestId,
  Map.of("scrollId", scrollId)
  );
  List<Map<String, Object>> profiles = (List) scrollData.get("profiles");
  scrollId = (String) scrollData.get("scrollId");

  saveBatch(conn, profiles);
  conn.commit();
  totalSaved += profiles.size();
  System.out.println("Saved " + totalSaved + " / " + total);
  }

  System.out.println("Done");
  }
  }

  public static void main(String[] args) throws Exception {
  Map<String, Object> query = new HashMap<>();
  query.put("currentTitle", "(Software AND Engineer) OR Developer");
  query.put("location", "New York, New York, United States");
  query.put("keywords", "PHP AND JavaScript");
  query.put("size", 50);

  searchAndSave(query);
  }
  }
  ```

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

  API_KEY = 'your_secret_api_key'
  BASE_URL = 'https://www.signalhire.com/api/v1/candidate'

  def api_post(path, body)
  uri = URI("#{BASE_URL}#{path}")
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  request = Net::HTTP::Post.new(uri)
  request['apikey'] = API_KEY
  request['Content-Type'] = 'application/json'
  request.body = body.to_json
  JSON.parse(http.request(request).body)
  end

  def save_batch(conn, profiles)
  profiles.each do |profile|
  conn.exec_params(
  <<~SQL,
      INSERT INTO candidates (uid, full_name, location, open_to_work, raw_data)
      VALUES ($1, $2, $3, $4, $5)
      ON CONFLICT (uid) DO UPDATE SET
      full_name = EXCLUDED.full_name,
      location = EXCLUDED.location,
      open_to_work = EXCLUDED.open_to_work,
      raw_data = EXCLUDED.raw_data
      SQL
      [
      profile['uid'],
      profile['fullName'],
      profile['location'],
      profile['openToWork'] ? 't' : 'f',
      profile.to_json
      ]
      )
  end
  end

  def search_and_save(query)
  conn = PG.connect(dbname: 'mydb', user: 'user', password: 'password', host: 'localhost')
  total_saved = 0

  # Initial search
  data = api_post('/searchByQuery', query)
  request_id = data['requestId']
  total = data['total']
  scroll_id = data['scrollId']
  puts "Total profiles found: #{total}"

  conn.transaction { save_batch(conn, data['profiles']) }
  total_saved += data['profiles'].size
  puts "Saved #{total_saved} / #{total}"

  # Scroll through remaining batches
  while scroll_id
  data = api_post("/scrollSearch/#{request_id}", { scrollId: scroll_id })
  scroll_id = data['scrollId']

  conn.transaction { save_batch(conn, data['profiles']) }
  total_saved += data['profiles'].size
  puts "Saved #{total_saved} / #{total}"
  end

  conn.close
  puts 'Done'
  end

  search_and_save(
  currentTitle: '(Software AND Engineer) OR Developer',
  location: 'New York, New York, United States',
  keywords: 'PHP AND JavaScript',
  size: 50
  )
  ```
</CodeGroup>
