# Count jobs

> How many jobs match a filter set without paying for the rows — the identical filters as /v1/jobs, returning a single number instead of a page of payloads.

Source: https://hyperjobs.io/docs/api-reference/jobs-count

<EndpointHeader method="GET" path="/v1/jobs/count" />

The size of a query, and nothing else. It takes the **identical filter set** to
[`/v1/jobs`](/docs/api-reference/jobs-list) and returns a single number — the
cheap way to size a query before you commit to paging through it, or to build
dashboards and facet counts without hauling job payloads around.

<CodeGroup>
```bash title="cURL"
curl -G https://api.hyperjobs.io/v1/jobs/count \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "skill=python" \
  --data-urlencode "work_arrangement=Remote" \
  --data-urlencode "country=United States"
```

```js title="Node"
const qs = new URLSearchParams({
  skill: "python",
  work_arrangement: "Remote",
  country: "United States",
});

const res = await fetch(`https://api.hyperjobs.io/v1/jobs/count?${qs}`, {
  headers: { Authorization: `Bearer ${process.env.HYPERJOBS_KEY}` },
});
const { count } = await res.json();
```

```python title="Python"
import os, requests

res = requests.get(
    "https://api.hyperjobs.io/v1/jobs/count",
    params={"skill": "python", "work_arrangement": "Remote", "country": "United States"},
    headers={"Authorization": f"Bearer {os.environ['HYPERJOBS_KEY']}"},
    timeout=30,
)
res.raise_for_status()
count = res.json()["count"]
```
</CodeGroup>

## Query parameters

Every **filter** parameter from [`/v1/jobs`](/docs/api-reference/jobs-list#query-parameters)
works here with identical semantics — `title`, `skill`, `country`,
`salary_gte`, `source`, `created_gte`, all of them. The tables aren't repeated
on this page; the jobs-list page is the contract for both endpoints.

<Note>
  **Shape parameters are rejected.** `limit`, `offset`, `cursor`, `collapse`,
  and `description_format` control how rows come back — and there are no rows
  here, so sending any of them is a `400`. If you want a count *and* the first
  page, one `/v1/jobs` call gives you both: its `total` is the same number.
</Note>

## Response

<Fields>
  <ResponseField name="count" type="integer">
    Live matches for the filter set — non-duplicate, non-expired, same
    population `/v1/jobs` reports as `total`.
  </ResponseField>
</Fields>

```json title="Response"
{
  "count": 21497
}
```

## Errors

| Status | Cause |
| --- | --- |
| `400` | Invalid parameter or value — the body names the `param` and carries a `hint`. |
| `401` | Missing, unknown, or revoked key. |
| `429` | [Rate limit](/docs/rate-limits) or monthly quota exceeded. |
| `500` | Server error. Retry with backoff. |

Validation is strict — a misspelled filter is a `400`, never a
misleadingly small count.

## Next

<CardGroup cols={2}>
  <Card title="List jobs" icon="List" href="/docs/api-reference/jobs-list">
    The full filter vocabulary this endpoint shares.
  </Card>
  <Card title="Filtering" icon="Funnel" href="/docs/guides/filtering">
    How the filters combine, and how to debug an unexpected count.
  </Card>
</CardGroup>
