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

# Batch matching

> Submit up to 1,000 companies, poll job status or receive a webhook, then page through results.

Use the batch API when you have a list. One submit request queues the work; matching runs asynchronously.

## 1. Submit

```bash theme={null}
curl -sS -X POST "https://datamatcher-api.thedatacity.com/api/v1/match/batch" \
  -H "Authorization: Bearer dm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "companies": [
      {"input_name": "Sainsbury'\''s Supermarkets Ltd", "id": "demo-001"},
      {"input_name": "John Lewis plc", "id": "demo-002"},
      {"input_name": "Holmes Joinery Partners LLP", "id": "demo-003"}
    ]
  }'
```

Response (`202 Accepted`):

```json theme={null}
{
  "job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "queued",
  "total": 3
}
```

Maximum batch size: **1,000** companies. Larger payloads return `422`.

Jobs are retained for **30 days** from creation (`expires_at` on the status payload).

## 2. Poll status

```bash theme={null}
curl -sS "https://datamatcher-api.thedatacity.com/api/v1/match/batch/{job_id}" \
  -H "Authorization: Bearer dm_live_YOUR_KEY"
```

```json theme={null}
{
  "job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "running",
  "total": 3,
  "completed_count": 1,
  "error_count": 0,
  "error_message": null,
  "created_at": "2026-08-17T12:00:00Z",
  "started_at": "2026-08-17T12:00:01Z",
  "finished_at": null,
  "expires_at": "2026-09-16T12:00:00Z"
}
```

| Status      | Meaning                                                         |
| ----------- | --------------------------------------------------------------- |
| `queued`    | Accepted, not started                                           |
| `running`   | Matching in progress (partial results may already be available) |
| `completed` | Finished                                                        |
| `failed`    | Job-level failure — see `error_message`                         |

Poll every few seconds. Avoid tight polling loops.

## 3. Fetch results

Results are available once status is `running`, `completed`, or `failed`. Requesting them while still `queued` returns `409`.

```bash theme={null}
curl -sS "https://datamatcher-api.thedatacity.com/api/v1/match/batch/{job_id}/results?skip=0&limit=100" \
  -H "Authorization: Bearer dm_live_YOUR_KEY"
```

| Query   | Default | Notes                       |
| ------- | ------- | --------------------------- |
| `skip`  | `0`     | Offset into the result list |
| `limit` | `100`   | Page size, max **1000**     |

Each item in `data` uses the same fields as `POST /match`. See [Response reference](/company-matching/guides/response-reference).

## 4. Completion webhook

Optional. Pass `callback_url` on submit to receive one `POST` when the job reaches `completed` or `failed`. Polling still works.

```bash theme={null}
curl -sS -X POST "https://datamatcher-api.thedatacity.com/api/v1/match/batch" \
  -H "Authorization: Bearer dm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "callback_url": "https://example.com/hooks/datamatcher",
    "webhook_secret": "at-least-16-chars",
    "companies": [
      {"input_name": "Sainsbury'\''s Supermarkets Ltd", "id": "demo-001"}
    ]
  }'
```

`callback_url` must be `https` (http is allowed only in local development). Private, loopback, and link-local hosts are rejected outside local development. Cloud metadata addresses such as `169.254.169.254` are always rejected.

The webhook body is the same shape as `GET /match/batch/{job_id}`, plus `event`:

```json theme={null}
{
  "event": "job.completed",
  "job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "completed",
  "total": 3,
  "completed_count": 3,
  "error_count": 0,
  "error_message": null,
  "created_at": "2026-08-17T12:00:00Z",
  "started_at": "2026-08-17T12:00:01Z",
  "finished_at": "2026-08-17T12:00:10Z",
  "expires_at": "2026-09-16T12:00:00Z"
}
```

`event` is `job.completed` or `job.failed`.

If you set `webhook_secret` (16–128 characters), the request includes:

```text theme={null}
X-DataMatcher-Signature: sha256=<hex>
```

The hex digest is HMAC-SHA256 of the **raw JSON body** using your secret. Verify against the bytes you received; do not re-serialise the JSON first.

Respond with `2xx`. Delivery is attempted once. A failed webhook does not fail the job — poll status if you miss it.

Retrying misses on a finished job queues it again; a second webhook fires when that run finishes.

## Ownership

Jobs are scoped to the user who owns the API key. Another account's `job_id` returns `404`.
