# ZipRecruiter Job Search

> ZipRecruiter Job Search is a paid API for AI agents from agents.openwebninja.com, paid per call via MPP, price unknown, status unknown (last checked 2026-10-14).

Search ZipRecruiter job postings by keyword with server-side filters for location, salary, employment type, experience level, and more, with optional full job detail enrichment.

## Facts

- Endpoint: GET https://agents.openwebninja.com/realtime-ziprecruiter-data/search?utm_source=zero.xyz
- Price: price unknown
- Payment: MPP
- Status: unknown
- Last checked: 2026-10-14
- Activations on Zero: 0
- Provider: agents.openwebninja.com
- Website: https://agents.openwebninja.com
- Canonical page: https://www.zero.xyz/c/agents-openwebninja-com-ziprecruiter-job-search-55ec0f30
- Structured record (JSON): https://api.zero.xyz/v1/capabilities/cap_Rl0778HQBsoIl0XNcEwsJ

Status and success rate cover calls made through Zero and Zero's own probes. Third-party monitors may report differently.

## How to call it through Zero

Zero handles the 402 payment challenge and records the run. With the Zero CLI installed (`npm i -g @zeroxyz/cli`):

```sh
zero fetch --capability agents-openwebninja-com-ziprecruiter-job-search-55ec0f30
```

Example prompt: Search ZipRecruiter for full-time senior software engineer jobs in Austin, TX within 40 km, posted in the last 7 days, paying at least $120k a year — and include the full job descriptions so I can see responsibilities and requirements.

## When to prefer this

Use this endpoint when you need to search ZipRecruiter job postings specifically, with ZipRecruiter's native filters (salary range, experience level, employment type, remote-only, ZipApply-only, company-specific). Prefer this over generic job search endpoints when you need ZipRecruiter-specific metadata such as ziprecruiter_company_id, ziprecruiter_apply_type, or ZipRecruiter canonical URLs. It is especially useful when the user wants to paginate through large result sets (up to 946 jobs) or needs full job details including employer FAQ and key responsibilities via include_details=true.

## Known failure modes

- Missing required 'query' parameter returns 400 error
- Providing two 'query' parameters returns 400 error
- num_pages > 5 when include_details=true returns 400 error
- Unknown field name in 'fields' projection returns 400 error
- page value outside 1-50 returns 400 error
- Invalid country code (not 'us' or 'ca') returns 400 error
- company_id filter without location may yield poor results due to ZipRecruiter server-side behavior
- Detail fields (job_description, highlights, etc.) return null when include_details is not set to true

## How this service works

Search ZipRecruiter job postings by keyword, with the filters ZipRecruiter honors
server-side: `location` with a kilometre `radius`, `date_posted`, `employment_types`,
`experience_level`, `salary_min` / `salary_max`, `remote_jobs_only`, `zipapply_only` and
`company_id`.

**`include_details` defaults to `false`, and this is the single most important thing to
understand about this endpoint.** A ZipRecruiter search card carries a roughly
200-character teaser and nothing more. `job_description`, `job_highlights`,
`employer_website`, `employer_reviews`, `job_onet_soc`, `ziprecruiter_description_html`,
`ziprecruiter_job_industry`, `ziprecruiter_valid_through`, `ziprecruiter_ats_identifier`,
`ziprecruiter_company_size`, `ziprecruiter_company_hq`, `ziprecruiter_company_industries`,
`ziprecruiter_key_responsibilities` and `ziprecruiter_employer_faq` are all detail-only and
come back `null` on a plain search. Set `include_details=true` to fill them. The teaser is
always published separately as `ziprecruiter_short_description`, so a card-only response
still carries usable copy.

Filling the details costs one extra upstream request per job, which is why it is opt-in.
With `include_details=true`, `num_pages` may be at most 5, which is 100 jobs; a larger
value returns a 400 error.

**Pagination** is 20 jobs per page. The ceiling is `ceil(total_results / 20)`, where
`total_results` is ZipRecruiter's own count of matches, and the largest result set observed
was 946 jobs. Duplicates ZipRecruiter repeats across adjacent pages are removed, so a page
may yield fewer than 20 new jobs. The response is a flat array, so a call returning fewer
than `num_pages` x 20 jobs is how you know you have reached the end of the result set.

**Scoping to one company** is what `company_id` is for, and the value is the
`ziprecruiter_company_id` carried on every job. ZipRecruiter fails this filter OPEN in two
ways, both silent: a bad id returns the full unfiltered search, and a valid one
intermittently drops the filter. Send `location` alongside `company_id`: that is what keeps
the drop rare. Measured on one id with five interleaved repeats per arm, the filter held
5/5 with a location and 1/5 without, and the misses returned 6, 4 and 20 distinct
employers. So every returned card is checked against the requested id, a page that fails
the check is refetched, and an id that stays unscoped returns a 404 error.
`total_results` is omitted for a company-scoped search: ZipRecruiter's count there swings
from 1 to 540 across 20 identical calls. Note that roughly a third of postings carry the
placeholder id `zr_missing_company_default`, ZipRecruiter's marker for a posting whose
company record is missing; it returns a 404 error here, so pick an id off a job whose
`employer_name` is the company you want.

**Sorting.** Results come back in ZipRecruiter's own relevance order. `sort_by`, `sort`,
`order` and a `company` NAME each return a 400 error, because ZipRecruiter accepts and
then ignores them.

**Billing:** `Requests` counts one per requested SERP page, plus one per detail page when
`include_details=true`. Extra pages walked to refill a page after deduplication, and
retries of a blocked page, are absorbed.

## Output

Returns a paginated array of job postings from ZipRecruiter. Each result includes job ID, title, employer name, location, employment type, salary info, apply link, and a short teaser description. When include_details=true, also returns full job description, highlights, employer website, employer reviews, company size, company HQ, key responsibilities, valid through date, ATS identifier, and employer FAQ. Also includes total_results count and request metadata.

## Request schema (JSON Schema)

```json
{
 "type": "object",
 "required": [
  "query"
 ],
 "properties": {
  "page": {
   "type": "integer",
   "default": 1,
   "maximum": 50,
   "minimum": 1,
   "description": "1-based page of results to start from. ZipRecruiter returns 20 jobs per page. The real\nceiling is `ceil(total_results / 20)`, and the largest result set observed was 946\njobs.\n\n**Allowed values:** `1-50`\n\n**Default:** `1`"
  },
  "query": {
   "type": "string",
   "example": "software engineer",
   "description": "Free-text job search query, for example `software engineer` or `registered nurse`.\nExactly one `query` is accepted; a second one returns a 400 error."
  },
  "fields": {
   "type": "string",
   "description": "Comma-separated projection over the job object, for example\n`job_title,employer_name,job_apply_link`. `job_id` and `job_title` are always included.\nAn unknown field name returns a 400 error."
  },
  "radius": {
   "type": "integer",
   "minimum": 1,
   "description": "Search radius around `location`, in KILOMETRES, converted to the miles ZipRecruiter\nexpects. Any positive integer is accepted. Requires `location`. ZipRecruiter's own\ndefault is 25 miles."
  },
  "country": {
   "enum": [
    "us",
    "ca"
   ],
   "type": "string",
   "default": "us",
   "description": "Country market to search. Only `us` and `ca` are served.\n\n**Allowed values:** `us`, `ca`\n\n**Default:** `us`"
  },
  "location": {
   "type": "string",
   "description": "Free-text location, for example `New York, NY` or `Toronto, ON`. This is what drives\ngeography on ZipRecruiter. Omit it to search the whole country."
  },
  "num_pages": {
   "type": "integer",
   "default": 1,
   "maximum": 20,
   "minimum": 1,
   "description": "Number of consecutive pages to fetch starting at `page`. Each page is 20 jobs.\nDuplicate listings ZipRecruiter repeats across pages are removed, so a page may yield\nfewer than 20 new jobs.\n\n**Allowed values:** `1-20`\n\n**Default:** `1`"
  },
  "company_id": {
   "type": "string",
   "description": "Return only jobs from one company, identified by the `ziprecruiter_company_id` carried\non a previous `/search` result. Send `location` too: ZipRecruiter applies this filter\nfar more reliably with one. Every card is verified, and an unknown id returns a 404\nerror."
  },
  "salary_max": {
   "type": "integer",
   "minimum": 0,
   "description": "Maximum ANNUAL salary in whole dollars, for example `150000`. Must be greater than or\nequal to `salary_min`."
  },
  "sa
… (truncated)
```

## Response schema (JSON Schema)

```json
{
 "type": "object",
 "required": [
  "status",
  "request_id",
  "parameters",
  "data"
 ],
 "properties": {
  "data": {
   "type": "array",
   "items": {
    "type": "object",
    "required": [
     "job_id",
     "job_title",
     "employer_name",
     "employer_logo",
     "employer_website",
     "job_publisher",
     "job_employment_type",
     "job_employment_types",
     "job_apply_link",
     "job_apply_is_direct",
     "apply_options",
     "job_description",
     "job_is_remote",
     "job_posted_at",
     "job_posted_at_timestamp",
     "job_posted_at_datetime_utc",
     "job_location",
     "job_city",
     "job_state",
     "job_country",
     "job_latitude",
     "job_longitude",
     "job_benefits",
     "job_benefits_strings",
     "job_google_link",
     "job_salary",
     "job_salary_string",
     "job_min_salary",
     "job_max_salary",
     "job_salary_period",
     "job_highlights",
     "job_onet_soc",
     "job_onet_job_zone",
     "employer_reviews",
     "job_uid",
     "ziprecruiter_listing_key",
     "ziprecruiter_short_description",
     "ziprecruiter_description_html",
     "ziprecruiter_share_url",
     "ziprecruiter_canonical_job_url",
     "ziprecruiter_updated_at",
     "ziprecruiter_is_new",
     "ziprecruiter_apply_type",
     "ziprecruiter_apply_host",
     "ziprecruiter_salary_source",
     "ziprecruiter_salary_is_estimated",
     "ziprecruiter_location_type",
     "ziprecruiter_location_county",
     "ziprecruiter_location_postal_code",
     "ziprecruiter_location_id",
     "ziprecruiter_company_id",
     "ziprecruiter_company_slug",
     "ziprecruiter_company_size",
     "ziprecruiter_company_hq",
     "ziprecruiter_company_industries",
     "ziprecruiter_job_industry",
     "ziprecruiter_valid_through",
     "ziprecruiter_ats_identifier",
     "ziprecruiter_key_responsibilities",
     "ziprecruiter_employer_faq"
    ],
    "properties": {
     "job_id": {
      "type": "string",
      "example": "emlwcmVjcnVpdGVyOjkzNjIxNWNiNTAzZDhiZTI",
      "description": "Stable, opaque id for this posting. Pass it straight back to `/job-details`. Encodes\nZipRecruiter's own seat id, so it survives re-fetches and is the same on every surface."
     },
     "job_uid": {
      "type": "string",
      "example": "936215cb503d8be2",
      "description": "ZipRecruiter's own raw seat id, 16 hex characters. Stable across surfaces and\nre-fetches, accepted directly by `/job-details`, and the right key for an enrichment\ncache."
     },

… (truncated)
```

## More

- Live health (JSON, refreshed every minute): https://www.zero.xyz/c/agents-openwebninja-com-ziprecruiter-job-search-55ec0f30/health.json
- [Zero catalog index](https://www.zero.xyz/llms.txt)
- [Other services from agents.openwebninja.com](https://www.zero.xyz/host/agents.openwebninja.com/llms.txt)
