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

# Batch Submit Hiring Manager Contacts

> Queue hiring-contact research for up to 100 postings in one request.

> [!WARNING]
>
> **Requires the Hiring Manager API add-on**, like [Hiring Manager Contacts](https://www.hirebase.org/docs/api-reference/jobs/contacts.md).

Queue up to 100 postings in one request instead of one request each. Every
posting becomes its own `contacts_extraction` task, researched and billed
exactly like a [single submit](https://www.hirebase.org/docs/api-reference/jobs/contacts.md): \$0.30 for each
search that finds at least one contact, plus any reveals found, settled when
each task finishes. Postings that find no one, or fail, cost nothing.

The whole batch counts as **one request** against your rate limit. Poll the
tasks with [List Tasks](https://www.hirebase.org/docs/api-reference/tasks/list-tasks.md), which returns every
task with its result in one call, or with [Get Task Status](https://www.hirebase.org/docs/api-reference/tasks/get-task-status.md)
one by one. Task reads have their own budget of 600 requests per minute.

## Endpoint

```bash theme={null}
POST /v2/jobs/contacts/batch
```

## Request Body

**job\_ids** `string[]` *required*

1 to 100 Hirebase job ids (`_id` from any [Search Jobs](https://www.hirebase.org/docs/api-reference/jobs/search-post.md)
result). Duplicates are queued once. Expired postings are accepted on the
same terms as a [single submit](https://www.hirebase.org/docs/api-reference/jobs/contacts.md#request-body).

**functions** `string[]`

Only return people in these functions, on every posting. Same values and
behaviour as on [Hiring Manager Contacts](https://www.hirebase.org/docs/api-reference/jobs/contacts.md#request-body).

**relationships** `string[]`

Only return people with these relationships to the role (`hiring_manager`,
`function_leader`, `recruiter`, `hr`, `executive`, `other`), on every
posting. Same values and behaviour as on [Hiring Manager Contacts](https://www.hirebase.org/docs/api-reference/jobs/contacts.md#request-body).

**exclude** `object`

People you already have (`linkedin_urls`, `emails`; up to 10,000 entries in
total), applied to every posting in the batch. Send it once per batch rather
than splitting it. See [Hiring Manager Contacts](https://www.hirebase.org/docs/api-reference/jobs/contacts.md#request-body).

**reveal\_email** `boolean` (default: false)

Also look up a work email for every contact found, on every posting. \$0.05 per email actually found.

**reveal\_phone** `boolean` (default: false)

Also look up a direct phone number for every contact found, on every posting. \$0.40 per number actually found.

## Response

**tasks** `object[]`

One entry per posting that was queued, in the order you sent them.

**properties**

**job\_id** `string`

The posting.

**task\_id** `string`

Task to poll.

**state** `string`

Always `"queued"`.

**errors** `object[]`

One entry per id that was not queued. Nothing is charged for these.

**properties**

**job\_id** `string`

The id you sent.

**code** `string`

`job_not_found`: no live or archived posting has this id.

**detail** `string`

The reason in words.

## Example

```bash cURL theme={null}
curl -X POST "https://api.hirebase.org/v2/jobs/contacts/batch" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{ "job_ids": ["6a6efd8c5c1df030c3de5da7", "6a7bb93280574f78dddadccc", "linkedin-4012345"] }'
```

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

H = {"x-api-key": "YOUR_API_KEY"}
job_ids = ["6a6efd8c5c1df030c3de5da7", "6a7bb93280574f78dddadccc"]  # up to 100
batch = requests.post("https://api.hirebase.org/v2/jobs/contacts/batch", headers=H,
                      json={"job_ids": job_ids}).json()
pending = {t["task_id"] for t in batch["tasks"]}

while pending:
    time.sleep(30)
    tasks = requests.get("https://api.hirebase.org/v2/tasks/", headers=H,
                         params={"task_type": "contacts_extraction", "limit": 1000}).json()
    for task in tasks:
        if task["id"] in pending and task["state"] in ("finished", "failed"):
            pending.discard(task["id"])
            if task["state"] == "finished":
                print(task["input"]["job_id"], len(task["result"]["contacts"]), "contacts")
            elif task["retryable"]:
                print(task["input"]["job_id"], "temporary failure, submit again")
            else:
                print(task["input"]["job_id"], "skipped:", task["error_code"])
```

```json Response theme={null}
{
  "tasks": [
    { "job_id": "6a6efd8c5c1df030c3de5da7", "task_id": "7b2bc000-02d7-420b-8654-36a8e54f6e4f", "state": "queued" },
    { "job_id": "6a7bb93280574f78dddadccc", "task_id": "c614df14-a990-46ed-8c99-2ac3fc193258", "state": "queued" }
  ],
  "errors": [
    {
      "job_id": "linkedin-4012345",
      "detail": "No live or archived posting has the id 'linkedin-4012345'. Use the _id of a Hirebase job.",
      "code": "job_not_found"
    }
  ]
}
```

## Error Responses

> **402 Payment Required**
>
> Your last Hiring Manager API charge failed; nothing in the batch is queued. Same body and fix as on [Hiring Manager Contacts](https://www.hirebase.org/docs/api-reference/jobs/contacts.md#error-responses).

> **403 Forbidden**
>
> Your key doesn't have the Hiring Manager API add-on (`X-Billing-Code: feature_missing`).

> **422 Unprocessable Entity**
>
> `job_ids` is empty, has more than 100 ids, or the body has an unknown field.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.