# Jobs

Section: API reference
Source: https://platform.metix.ai/docs/api/jobs
Every page in one file: https://platform.metix.ai/llms-full.txt

Search active job postings with a Query Spec tree and read the postings you select. Openings are a demand signal: who is hiring, for what, where, and at what pay.

Routes: 2. Search: /v1/jobs/query. Search returns: encrypted IDs. Detail batch: up to 100 IDs.

- `POST /v1/jobs/query`: Query Spec search (MCP tool `metix_query_jobs`)
- `POST /entity/v1/jobs/detail-by-id`: Fetch job records (MCP tool `metix_get_jobs`)

## Search, then fetch

Search never returns postings. It returns encrypted string job IDs, and you pass up to 100 of them to the detail route to read the records. There is no one-shot endpoint, so plan for two calls.

```bash
# 1. Search. Returns encrypted IDs, never postings.
curl -X POST "https://mira-api.metix.ai/v1/jobs/query" \
  -H "Authorization: Bearer $METIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "where": {"all": [
      {"field": "title", "match": "machine learning platform"},
      {"field": "country_iso_2", "eq": "US"},
      {"field": "posted", "gte": "now-30d"},
      {"any": [
        {"field": "seniority", "eq": "Mid-Senior level"},
        {"field": "seniority", "eq": "Director"}
      ]}
    ]},
    "size": 25
  }'

# 2. Read the postings, up to 100 IDs per call.
curl -X POST "https://mira-api.metix.ai/entity/v1/jobs/detail-by-id" \
  -H "Authorization: Bearer $METIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "job_ids": ["Jb71xKcAoP", "Jb0mQ4ZtRe"],
    "_source": ["id", "title", "company_name", "location", "seniority", "posted"]
  }'
```

> **Two calls, always**
>
> A search response carries IDs and nothing else. If your code expects records back from a search, it will read an empty payload and conclude there is no data. Send the IDs to the detail route, in batches of up to 100.

## When to use it

- Measure hiring demand by role, function, seniority, company, or location.
- Find who is hiring for a capability, then pivot to the companies and people behind it.
- Filter by salary band or posting date to separate live demand from stale listings.

## Request parameters and limits

| Parameter | Type | Notes |
| --- | --- | --- |
| where | object | Query Spec tree. Required by /v1/jobs/query |
| size | integer (1-10000) | Job IDs in one page. Omitting it returns 100 |
| after | string | Cursor. Pass the next value from the previous response |
| job_ids | string[] (1-100) | IDs from a search, sent to the detail route |
| _source / source | array, object, or boolean | Optional field selection on detail |

- One operator per leaf. A salary band is an all of two leaves, not gte and lte in one node.
- A field name that is not in this dataset's list is refused, so a typo is visible rather than returning a record without it. The three datasets do not share one vocabulary.
- Search returns at most 10,000 IDs per page and 100 when size is omitted; detail accepts at most 100 IDs per request.
- Jobs declare no scope nodes. One document is one posting, so there is nothing to group.
- The response carries IDs and a cursor, not a match count. Page until next is absent if you need the size of a set.
- The index holds daily active postings. A posting closed since your search can come back in not_found.

> **Credit cost**
>
> Job search costs ceil(returned IDs / 25) Credits, and 0 when it returns nothing. Job detail costs ceil(found records / 5) Credits, and not_found rows are free.

## Queryable fields

These are the only names a leaf may put in `field`. The grammar around them, including composition, one operator per leaf, and relative dates, is on the [Query Spec](https://platform.metix.ai/docs/api/query-spec.md) page. What a response may contain is a separate, wider list: a field can be returnable without being queryable.

`title``description``company_name`What the posting is and who posted it.Operators: match, eq, in, exists `seniority``employment_type``functions``industries`How the posting is classified.Operators: match, eq, in, exists `city``state``country``location``regions`Where the job is. country takes a name; country_iso_2 takes the code.Operators: match, eq, in, exists `country_iso_2``application_active`ISO 3166-1 alpha-2 code such as US. application_active is true on every posting in the index today, so it narrows nothing.Operators: eq, in, exists `salary_min``salary_max`Advertised pay. exists separates postings that state a salary from those that do not.salary_min, salary_max read on a record; filtering on them is being improved.Operators: gte, lte, existsAsk for salary_min and salary_max in _source and they come back on the record as normal. Using them as a filter answers with an error for now, rather than a set that looks right and is not, while we make the comparison reliable. Narrow with the other fields in this group and sort what comes back. Everything else here filters normally. `salary_currency`Currency of the advertised pay. Compare salary figures only within one currency.Operators: match, eq, in, exists `applicants_count``required_months_of_experience`Competition for the role, and the experience the posting asks for.applicants_count reads on a record; filtering on it is being improved.Operators: gte, lte, existsAsk for applicants_count in _source and it comes back on the record as normal. Using it as a filter answers with an error for now, rather than a set that looks right and is not, while we make the comparison reliable. Narrow with the other fields in this group and sort what comes back. Everything else here filters normally. `posted``created_at``updated_at`Posting dates. Take YYYY-MM-DD or a relative offset such as now-30d.posted reads on a record; filtering on it is being improved.Operators: gte, lte, existsAsk for posted in _source and it comes back on the record as normal. Using it as a filter answers with an error for now, rather than a set that looks right and is not, while we make the comparison reliable. Narrow with the other fields in this group and sort what comes back. Everything else here filters normally.

## Fields with a fixed set of values

These are matched against the whole stored value, so the spelling and the capitalisation both have to match. Getting either wrong is the one mistake in the grammar that raises no error: the query is valid, it costs nothing, and it returns zero, which reads as an answer about the data rather than about the query.

| Field | Values |
| --- | --- |
| seniority | `Associate``Director``Entry level``Executive``Internship``Mid-Senior level``Not Applicable` |
| employment_type | `Contract``Full-time``Internship``Other``Part-time``Temporary``Volunteer` |

> **Not every category field is a fixed set**
>
> functions and industries look like fixed sets and are not: each runs to several hundred values. Ask them with match.

## Response shape

Successful responses use the public envelope with `code`, `msg`, and `data`.

Search returns IDs, and a `next` cursor while more pages remain:

```json
{
  "code": 200,
  "msg": "ok",
  "data": {
    "job_ids": ["Jb71xKcAoP", "Jb0mQ4ZtRe"],
    "next": "WzE3MjQwMDAwMDAsIkpiNzF4S2NBb1AiXQ"
  }
}
```

Detail returns the records, and names the IDs it could not resolve:

```json
{
  "code": 200,
  "msg": "ok",
  "data": {
    "total": 2,
    "found": 1,
    "not_found": ["Jb0mQ4ZtRe"],
    "results": [{
      "id": "Jb71xKcAoP",
      "title": "Machine Learning Platform Engineer",
      "company_name": "Example Corp",
      "location": "San Francisco, CA",
      "seniority": "Mid-Senior level",
      "posted": "2026-08-02"
    }]
  }
}
```

The record itself is a page of its own: [every field it can carry](https://platform.metix.ai/docs/api/jobs/record.md), what each one holds, and a whole one to read.

## Access surfaces

| Surface | How to use this capability |
| --- | --- |
| REST | POST /v1/jobs/query; POST /entity/v1/jobs/detail-by-id |
| Metix AI skill | metix-job-search |
| MCP | Use the MCP setup page to expose the same REST capability. Capability-specific tool names remain pending schema verification. |
| Natural-language prompt | Find US machine-learning platform openings posted in the last 30 days, fetch the postings, and rank the hiring companies by how many they have open. |

Common next step: [look up the companies doing the hiring](https://platform.metix.ai/docs/api/companies.md).
