Skip to content

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

Job Opportunities API — worked examples

Runnable, tested integrations for jobopportunitiesapi.org: a ledger of open job vacancies collected directly from employer applicant-tracking systems, employers' own careers pages and public employment agencies — where every field says whether the employer stated it or we inferred it.

Everything here has been run against the live API. run_all.sh runs every example and fails on any non-2xx; CI runs the keyless half on every push. That gate exists for a reason, and the reason is in Why this repo has a test suite.

Python 3.9+, no dependencies — standard library only, so git clone and python3 examples/... is the whole setup.

git clone https://github.com/lucagiftzek/joa-examples
cd joa-examples

# Needs nothing at all — /public/ is a real, bounded mirror of the same rows
bash examples/00_curl_cookbook.sh

# Free key, no card, no expiry: https://jobopportunitiesapi.org/register
export JOA_KEY=your_key
python3 examples/01_daily_country_pull.py --country DE --category Engineering

The examples

what it does plan
00_curl_cookbook.sh 17 requests in plain curl. The first nine need no key at all. none
01_daily_country_pull.py New roles for a country, daily, incrementally. Cron-ready, resumable, idempotent. free
02_watch_a_company.py Watch employers by the domain already in your CRM. Prints what opened and what closed, with the closure reason from the API rather than a guess. free
03_salary_benchmark.py Percentiles from employer-published salaries only. Nothing modelled, and it prints its own denominator. free
04_sync_to_spreadsheet.py Flatten to CSV with the provenance in columns beside the values. free
05_vector_store.py Embedding-ready chunks with provenance in the metadata, for RAG that can cite. free
06_agent_tool.py A tool definition for Claude or GPT, plus the executor — closed vocabularies, compact output, provenance marks. free
07_mirror_with_changes.py Keep a SQLite mirror in sync from the delta feed. Handles withdrawn, which is the change type that breaks mirrors. Growth+

Every script takes --help, and every script's docstring explains why it is written the way it is — which parameter it chose over the obvious one, and what went wrong when it did the obvious thing first.

The one thing to understand before you write any code

Every listing carries a field_sources object:

"field_sources": {
  "remote": "published", "salary": "published", "category": "inferred",
  "seniority": "inferred", "employment_type": "absent", "location": "published"
}
  • published — the source carried it. An employer or agency wrote it.
  • inferred — we derived it. Ours, not theirs.
  • absent — there is none. Not zero, not false: none.

category and seniority are always inferred; they are read off the job title by a classifier. remote may be either — ?remote_confirmed=true narrows to the ones an employer actually stated.

This is the reason to use this API rather than a scrape, and it is the first thing a naive integration throws away. Every example here carries it through to the output: into a CSV column, into vector metadata, into the string a model sees. If your pipeline drops it, your model will state our inference as the employer's claim.

Integration brief for an LLM

PROMPT.md is a copy-pasteable block that gives a model or a coding agent everything it needs: the real endpoints, the parameters that actually exist, the plan gating so it does not propose a 403, the provenance object, the rate-limit headers and all three of the API's cursors.

Plans, and what is actually free

plan records/month requests/day delta feed bulk export
Explore (free, no card) 1,000 5,000 no no
Growth 60,000 100,000 yes no
Signal 400,000 400,000 yes yes
Scale 2,000,000 1,000,000 yes yes

Live matrix: GET /public/plans. Your own: GET /v1/me.

On the free plan /v1/changes, /v1/jobs/expired and /v1/export return 403 — example 07 exits cleanly and tells you so rather than crashing. /v1/jobs/closed is available on every plan including free, and it is the free substitute for the delta feed: it is what example 02 uses to say why a role disappeared.

Records are charged per row returned, so limit is a budget. Every example prints what it spent.

Why this repo has a test suite

On 2026-08-16 the first external evaluation this API had ever had followed the documentation page and sent:

?provider=greenhouse,lever&exclude_provider=eures

HTTP 422. There is no provider with the slug eures — it had left /public/providers the day before, and the documentation had not noticed. Nothing anywhere was comparing what we published against what worked.

A broken example is worse than no example. It fails in the reader's terminal, it costs them the twenty minutes they had set aside to evaluate you, and it turns every other claim on the page into something they now have to check by hand.

So: run_all.sh runs all of it, .github/workflows/examples.yml runs the keyless half on every push and every day, and nothing lands here that has not gone through both.

Licence

MIT for the code in this repository. The data returned by the API is governed by the API terms.

Links

About

Runnable, tested integrations for the Job Opportunities API — every example is run against the live API before it ships.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages