API reference

The JobIndex API

Every open job we index, over plain HTTPS and JSON. Access comes with the API plan, which includes a commercial licence and the change feed, or the Data plan, which adds the bulk download.

Getting started

The base address is:

https://api.jobindex.space

Your first request, the five newest remote design jobs that state pay:

curl -H "Authorization: Bearer $JOBINDEX_KEY" "https://api.jobindex.space/v1/jobs?specialization=design&remote=remote&has_salary=true&sort=recent&limit=5"

Every response is JSON in UTF-8. Times are ISO 8601 in UTC. Salaries keep the currency and period the employer published (hour, day, week, month, year); we never convert them. apply_url always points at the employer or board that published the job: link to it, do not hide it.

Authentication

With an API or Data plan, create a key in your workspace and send it on every request:

curl -H "Authorization: Bearer jik_…" "https://api.jobindex.space/v1/jobs?q=nurse"

Keys start with jik_. They are shown once, when you create them; we keep only a hash. Revoke a key from the workspace at any time, and keep it out of browsers and public repositories: call the API from your server.

Rate limits

Limits are per minute. With a key they count per account, so all your keys share one budget.

PlanRequests per minuteAlso includes
API plan600 per accountCommercial licence, change feed, Pro
Data plan1,200 per accountEverything in API, bulk download

Every response says where you stand:

x-ratelimit-limit: 600
x-ratelimit-remaining: 587
x-ratelimit-reset: 42

Past the limit you get 429. Wait x-ratelimit-reset seconds, when the minute ends, and carry on.

Paging

Lists take page (1–1000) and limit (1–100) and answer with total, the exact number of matches, and has_more:

{ "data": [ … ], "page": 2, "limit": 100, "total": 13111, "has_more": true }

To copy more than a search can page through, use the bulk download once and then the change feed, which pages by cursor with no depth limit.

Errors

Errors use the HTTP status and a JSON body with a message you can show or log:

{ "error": "querystring/limit Too big: expected number to be <=100", "request_id": "req-9p" }
400

A parameter is missing or invalid. error names the parameter: "querystring/limit Too big: expected number to be <=100".

401

The endpoint needs an API key and none was sent, or the key is revoked or unknown.

402

The endpoint needs a plan your account does not have.

404

No job or company with that id.

429

Rate limit reached. Wait for x-ratelimit-reset seconds, or until the running download finishes.

5xx

Something failed on our side. Retry with backoff; include request_id if you contact us.

Jobs

Search the open roles and read one job with every place it was posted.

Search jobs

GET/v1/jobs

Every open job that matches all the filters you pass. Without q, results are newest first.

Query

qstring ≤ 200

Full-text search over title, company, place and description. Ranked by relevance unless you pass sort.

titlestring ≤ 200

Title contains any of these terms, separated by OR or commas: nurse OR caregiver.

companystring ≤ 200

Company name contains this text.

company_idinteger

Only this company’s jobs (exact, from /v1/companies).

locationstring ≤ 200

Place text: a city, region or country name (Berlin, Bavaria, Germany).

remoteonsite | hybrid | remote

Work arrangement stated by the posting.

employment_typeenum

full_time, part_time, contract, temporary, internship, volunteer, other.

specializationenum

Field of work, sorted from the title: software-engineering, data, engineering, healthcare, sales, marketing, design, customer-support, finance, operations-logistics, skilled-trades, hospitality, education, people-hr.

platformstring ≤ 50

Only jobs read from this platform (greenhouse, workday, lever …). Ids are listed by /v1/source-platforms.

posted_afterISO date or timestamp

Posted on or after this moment: 2026-11-01 or 2026-11-01T09:00:00Z.

has_salaryboolean

Only jobs whose posting states pay. Default false.

include_closedboolean

Also return jobs that have left their source. Default false.

sortrelevance | recent | added

relevance (the default with q), recent (posting date) or added (when we first saw it).

pageinteger 1–1000

Page number. Default 1.

limitinteger 1–100

Results per page. Default 20.

Example

curl "https://api.jobindex.space/v1/jobs?q=designer&remote=remote&has_salary=true&limit=1"

Response

{
  "data": [
    {
      "id": 4152,
      "title": "Designer",
      "company": "The Planet Group",
      "company_id": 4138,
      "company_slug": "the-planet-group",
      "location": "New Orleans, Louisiana",
      "countries": ["US"],
      "remote": null,
      "employment_type": "contract",
      "salary": { "min": 25, "max": 40, "currency": "USD", "period": "hour" },
      "posted_at": "2026-10-30T00:00:00.000Z",
      "first_seen_at": "2026-10-31T20:46:28.027Z",
      "last_seen_at": "2026-11-02T10:52:56.404Z",
      "is_open": true,
      "apply_url": "mailto:applications@staffingfuture.com",
      "source_count": 1,
      "has_logo": true,
      "blurb": "Distribution Designer, contract to hire …",
      "tags": ["Excel", "SAP", "Agile"]
    }
  ],
  "page": 1,
  "limit": 1,
  "total": 13111,
  "has_more": true
}
  • total is exact. has_more tells you whether another page exists; the deepest page is 1000.
  • For more than 100,000 results, narrow the filters, or use the change feed or the bulk download.

Get a job

GET/v1/jobs/{id}

One job with every source posting behind it (each board it was found on), the full description and its change history.

Path

idrequiredinteger

The job id from search.

Example

curl "https://api.jobindex.space/v1/jobs/4152"

Response

{
  "id": 4152,
  "title": "Designer",
  "company": "The Planet Group",
  "salary_min": 25, "salary_max": 40, "salary_currency": "USD", "salary_period": "hour",
  "is_open": true,
  "postings": [
    {
      "platform": "wpjobmanager",
      "source_key": "careers.theplanetgroup.com",
      "external_id": "12426",
      "locations": [{ "raw": "New Orleans, Louisiana", "city": "New Orleans", "region": "Louisiana", "country": "US" }],
      "source_url": "https://careers.theplanetgroup.com/job/653020-designer-new-orleans-louisiana/",
      "salary": { "min": 25, "max": 40, "raw": "$25-$40", "period": "hour", "currency": "USD" },
      "department": null,
      "last_checked_at": "2026-11-05T05:47:35.932Z",
      "closed_at": null,
      "description_html": "<p>Distribution Designer …</p>"
    }
  ],
  "history": [ … ]
}
  • Descriptions are the employer’s own text. Treat them as untrusted input: sanitise HTML before you show it.

Find a job by its posting link

GET/v1/jobs/by-url

The indexed job behind a posting page or apply link, if we have it.

Query

urlrequiredURL

A posting or apply address.

Example

curl "https://api.jobindex.space/v1/jobs/by-url?url=https://boards.greenhouse.io/acme/jobs/123"

Live stream of new jobs

GET/v1/feed/recent

Server-sent events: one event for each job as it is added to the index. Keep the connection open.

Example

curl -N "https://api.jobindex.space/v1/feed/recent"

Typeahead

GET/v1/suggest

Title completions, matching open jobs and companies for a partly typed query.

Query

qrequiredstring ≤ 100

What the user has typed so far.

Example

curl "https://api.jobindex.space/v1/suggest?q=data%20eng"

Companies and facets

The employers behind the jobs, and the values you can filter by, with counts.

List companies

GET/v1/companies

Companies with open jobs, with hiring signals: open, new, remote and pay-stating roles, countries and top fields.

Query

qstring ≤ 200

Company name contains this text.

countryISO 3166 code

Companies with an open job in this country: DE, US, KE …

remoteboolean

Companies with at least one open remote job. Default false.

hiring_nowboolean

Companies that added a job in the last 7 days. Default false.

has_salaryboolean

Companies with at least one open job that states pay. Default false.

specializationenum

Companies with an open job in this field.

pageinteger 1–1000

Page number. Default 1.

limitinteger 1–100

Results per page. Default 20.

Example

curl "https://api.jobindex.space/v1/companies?country=DE&hiring_now=true&limit=1"

Response

{
  "data": [
    {
      "id": 92727,
      "name": "Svetness Personal Training",
      "slug": "svetness-personal-training",
      "domain": null,
      "open_jobs": 5032,
      "new_jobs": 8,
      "remote_jobs": 0,
      "salary_jobs": 5020,
      "countries": ["US"],
      "specializations": [{ "id": "education", "label": "Education", "count": 10 }],
      "latest": { "id": 94485, "title": "Personal Trainer", "posted_at": "2026-11-05T09:47:54.486Z" },
      "last_seen_at": "2026-11-05T09:47:54.486Z",
      "has_logo": false
    }
  ],
  "total": 41147, "page": 1, "limit": 1, "has_more": true
}

Get a company

GET/v1/companies/{id}

One company by id. /v1/companies/by-slug/{slug} does the same by its slug.

Path

idrequiredinteger

Company id.

Example

curl "https://api.jobindex.space/v1/companies/by-slug/the-planet-group"

Filter values with counts

GET/v1/filter-values

The values of one facet across the jobs matching your other filters, most common first. Use it to build filter menus.

Query

filterrequiredcountries | remote | employment_type | platform | company

The facet to count.

containsstring ≤ 100

Only values containing this text.

…

Any job filter from Search jobs narrows the counts.

Example

curl "https://api.jobindex.space/v1/filter-values?filter=countries&q=nurse"

Response

{ "filter": "countries", "values": [{ "value": "US", "count": 18204 }, { "value": "GB", "count": 2210 }] }

Fields of work

GET/v1/specializations

Open-job counts per specialization.

Example

curl "https://api.jobindex.space/v1/specializations"

Market figures

GET/v1/market

Counts, top employers and places for any search. Takes the same filters as Search jobs.

Example

curl "https://api.jobindex.space/v1/market?specialization=data&location=Germany"

Salary figures

GET/v1/salaries

Pay ranges stated in the jobs that match, by currency and period. Takes the same filters as Search jobs.

Example

curl "https://api.jobindex.space/v1/salaries?title=backend%20engineer&location=Berlin"

Sync and bulk

Keep your own copy of the catalogue current. Both need a paid plan and an API key.

Change feedAPI plan

GET/v1/changes

Jobs added, closed or changed since a cursor, oldest change first, in the same shape as search results plus change_seq.

Query

sinceinteger

The next_cursor from your previous call. 0 starts at the beginning of the feed. Default 0.

limitinteger 1–500

Changes per call. Default 100.

Example

curl -H "Authorization: Bearer $JOBINDEX_KEY" "https://api.jobindex.space/v1/changes?since=0&limit=500"

Response

{
  "data": [
    { "id": 4152, "title": "Designer", "is_open": false, "change_seq": 1882041, … }
  ],
  "next_cursor": 1882041,
  "has_more": true
}
  • Store next_cursor and pass it as since next time. Repeat while has_more is true, then poll every few minutes.
  • A job that changed twice appears once, at its latest position. is_open: false means it has closed.
  • Start from the bulk download or a search, then follow the feed: the feed only holds changes since it began.

Bulk downloadData plan

GET/v1/export/jobs.ndjson.gz

Every open job, one JSON object per line, gzipped and streamed. Load it once, then stay current with the change feed.

Example

curl -H "Authorization: Bearer $JOBINDEX_KEY" -o jobs.ndjson.gz "https://api.jobindex.space/v1/export/jobs.ndjson.gz"
gunzip -c jobs.ndjson.gz | head -1
  • Four downloads per account per day. One download runs at a time across the service; if another is running you get 429, try again in a few minutes.
  • Each line has the search-result shape. Note the largest change_seq you have seen and follow /v1/changes from there.

Index and status

Catalogue totals

GET/v1/stats

Exact counts of open jobs, companies and sources, and when they were computed.

Example

curl "https://api.jobindex.space/v1/stats"

Response

{ "unique_jobs": 906444, "companies": 40934, "sources": 166, "ats_platforms": 101, "computed_at": "2026-11-06T09:05:57.259Z" }

Sources

GET/v1/source-platforms

Every platform the index reads, with its boards, open jobs, everything ever ingested and when it was last read.

Example

curl "https://api.jobindex.space/v1/source-platforms"

Live figures

GET/v1/pulse

Flow, freshness, fields, places, pay and sources of the open roles, as shown on the market pulse page.

Example

curl "https://api.jobindex.space/v1/pulse"

Uptime

GET/v1/status

Uptime of the API and the website, and recent incidents.

Example

curl "https://api.jobindex.space/v1/status"

MCP for AI agents

The same search is available to AI assistants over the Model Context Protocol, at https://api.jobindex.space/mcp (public, no account) and https://api.jobindex.space/mcp/account (your saved jobs and searches, after you connect). Setup for Claude, ChatGPT and others.

OpenAPI

A machine-readable description of every public endpoint, for code generators and API clients:

https://api.jobindex.space/docs/json

Using the data

The API and Data plans let you show JobIndex data in your own products and services. Whichever plan you use, keep each job’s link to where it was published, and do not present jobs as your own listings. See the terms.