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

# Enrich IP lists

> Use bulk lookup to add bounded context to up to 100 IP addresses

Use bulk lookup when a pipeline, alert, or case contains several IP addresses
and each input needs a bounded result. Do not build a large `OR` query for this
workflow.

## Choose the enrichment

| Route                         | Returns per IP                                |
| ----------------------------- | --------------------------------------------- |
| `POST /search/hosts/batch`    | Host context and bounded service summaries    |
| `POST /search/services/batch` | Matching service details                      |
| `POST /search/dns/batch`      | DNS records observed with the IP as an answer |
| `POST /search/osint/batch`    | Reports associated with the IP                |

## Look up service context

```bash theme={null}
curl --request POST \
  --url "https://api.infrawatch.com/api/v1/search/services/batch" \
  --header "Content-Type: application/json" \
  --header "X-API-Key: ${INFRAWATCH_API_KEY}" \
  --data '{
    "ip_addresses": ["1.1.1.1", "8.8.8.8"],
    "limit_per_ip": 10
  }'
```

The request accepts between 1 and 100 addresses. Services, DNS, and OSINT accept
`limit_per_ip` up to 25.

## Handle the response

Bulk responses preserve the original input order and duplicates. Each result
has one stable status:

| Status      | Meaning                                                       |
| ----------- | ------------------------------------------------------------- |
| `ok`        | The lookup returned one or more dataset-specific results      |
| `not_found` | The lookup completed and found no results                     |
| `error`     | That input could not be completed and includes a stable error |

`partial: true` means at least one per-IP lookup has `status: error`. A complete
upstream failure returns `503` instead of manufacturing per-IP results.

<Warning>
  Treat `not_found` as a valid enrichment result, not as a request failure.
</Warning>

## Preserve correlation

Correlate by array position rather than building a map keyed only by IP. If the
input contains the same address twice, the response contains two corresponding
positions.

```javascript theme={null}
const response = await fetch(
  "https://api.infrawatch.com/api/v1/search/hosts/batch",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": process.env.INFRAWATCH_API_KEY,
    },
    body: JSON.stringify({
      ip_addresses: ["1.1.1.1", "8.8.8.8", "1.1.1.1"],
    }),
  },
);

if (!response.ok) throw new Error(`Infrawatch request failed: ${response.status}`);

const body = await response.json();
for (const [index, result] of body.results.entries()) {
  console.log(index, result.ip_address, result.status);
}
```

## When to use search instead

Use the normal search endpoint when you need:

* A result page that leads the user into the search interface.
* InfraQL filters beyond exact IP membership.
* Pagination across an unbounded matching population.
* Counts or aggregations over the complete result set.

<Card title="Search and pagination" icon="https://mintcdn.com/infrawatch/gCEz_Bv1hOrMPG8n/images/products/search.svg?fit=max&auto=format&n=gCEz_Bv1hOrMPG8n&q=85&s=e80dbe9b7724f88ce870e69cb367b435" href="/search" width="32" height="32" data-path="images/products/search.svg">
  Learn when to use result search, count, aggregate, schema, validation, and bulk
  lookup.
</Card>
