Job Opportunities API

Check the data. Then trust it.

Job Opportunities API in Python

Search jobs from Python with requests and cursor pagination in a few lines.

  • Official

Python 3 with requests · free key, no card

Set it up in 3 steps

You need a free API key (no card) — get one here.

  1. Set your key

    Put your free key in an environment variable so it never lands in code or version control.

    Shell
    export JOA_API_KEY=your_key_here
  2. Run the snippet

    Save as jobs.py and run python3 jobs.py. It fetches up to three pages, honours Retry-After on 429, and prints title, company, location and apply link (tested against the live API on 6 Oct 2026):

    jobs.py
    import os
    import time
    import requests
    
    API = "https://api.jobopportunitiesapi.org/v1/jobs"
    headers = {"Authorization": f"Bearer {os.environ['JOA_API_KEY']}"}
    params = {"country": "DE", "q": "engineer", "remote": "remote,hybrid", "limit": 20}
    
    jobs, pages = [], 0
    while pages < 3:  # every row returned is metered, so cap the pages
        r = requests.get(API, headers=headers, params=params, timeout=30)
        if r.status_code == 429:  # rate limited: wait as told, then retry
            time.sleep(int(r.headers.get("Retry-After", "5")))
            continue
        r.raise_for_status()
        body = r.json()
        jobs += body["data"]
        pages += 1
        if not body["has_more"] or not body["next_cursor"]:
            break
        params["cursor"] = body["next_cursor"]
    
    for job in jobs[:5]:
        print(job["title"], "|", job["company"], "|", job["location"], "|", job["apply_url"])
  3. Know the response

    Each page is an object with data, next_cursor and has_more. Fields can be absent; field_sources tells you which ones the employer published and which were inferred.

    Response shape
    {
      "data": [
        {
          "id": "…", "slug": "…",
          "title": "…", "company": "…", "location": "…", "country": "DE",
          "remote": "remote | hybrid | on_site | not_stated",
          "apply_url": "https://… (the employer's own apply page)",
          "posted_at": "2026-10-05T17:41:41Z",
          "field_sources": { "title": "published", "remote": "inferred", "…": "…" }
        }
      ],
      "next_cursor": "… (pass as ?cursor= for the next page)",
      "has_more": true
    }

Example: for job boards

Run the script from cron, upsert each job into your database by id, and render apply_url as the apply button; add posted_after to fetch only what is new since the last run.

Example: for AI agents

Wrap the loop in a function and register it as a tool in your agent framework (LangChain, LlamaIndex, the OpenAI or Anthropic SDKs), passing the model's filters straight through as query parameters.

Questions

Straight answers about plans, metering and what to show.

How is usage counted?

Every job row the API returns counts against your plan's monthly record allowance, exactly as a direct API call would. The free key has a small monthly allowance and needs no card, so start with small page sizes and a daily schedule rather than polling every few minutes. Your key's largest page size is in GET /v1/me (limits.max_page_size).

Where do I get an API key?

At jobopportunitiesapi.org/register. The Explore key is free and needs no card. Keep it in your tool's credential store or an environment variable, never in a shared file.

Where do applicants apply?

On the employer's own site. Every job carries apply_url, the employer's application page or applicant-tracking-system link. Job Opportunities API never sits between the candidate and the employer, so always use apply_url as the apply button.

Do I need to show any attribution?

Yes, one line where listings are shown publicly: a visible credit "Data: Job Opportunities API" linking to https://jobopportunitiesapi.org (see /terms — storing, displaying, reselling and redistributing within your key's plan limits are all allowed). In addition, jobs listed through Erioun for Teams carry an attribution field (for example "via Erioun for Teams") and a canonical_url: when attribution is present, show it with the listing and link to canonical_url.

See all integrations

Get a free API key

No card. The same key works for every integration on this site.

Get a free key →