npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@maschinenlesbar.org/jobsuche-cli

v0.0.3

Published

TypeScript API client and CLI for the Bundesagentur für Arbeit Jobsuche API

Readme

jobsuche-cli

CI Release npm

Search Germany's federal job database from your terminal. jobsuche is a small command-line tool over the Bundesagentur für Arbeit Jobsuche API (rest.arbeitsagentur.de/jobboerse/jobsuche-service): find job listings by keyword, location, radius or employer, and fetch the full record for any posting — as clean JSON you can pipe straight into jq.

  • Just two commandssearch and details.
  • Clean JSON output — pretty-printed by default, --compact for one-line/scripting.
  • Needs one short setup step — supply the public, freely available API key once (see Authentication below).
  • Full-detail lookups — pass a refnr from any search result; the CLI base64-encodes it for the API automatically.

Want to use this as a TypeScript library or understand how it's built? See DEVELOPING.md.

Install

npm i -g @maschinenlesbar.org/jobsuche-cli

This installs the jobsuche command. Requires Node.js 20+.

Check it works:

jobsuche --help

Authentication

The Jobsuche API requires a static, publicly-documented X-API-Key (jobboerse-jobsuche). The key is not bundled — you supply it once via the JOBSUCHE_API_KEY environment variable or per-call via --api-key. With no key the header is omitted and the API answers 401/403 (exit code 3).

The public key is documented in the upstream bundesAPI/jobsuche-api repository. Set it in your shell profile for a seamless experience:

export JOBSUCHE_API_KEY="jobboerse-jobsuche"

Or fetch and export it in one step (handy for CI):

export JOBSUCHE_API_KEY="$(npm run --silent fetch-key --prefix $(npm root -g)/@maschinenlesbar.org/jobsuche-cli 2>/dev/null || echo jobboerse-jobsuche)"

Precedence is --api-key > JOBSUCHE_API_KEY env var. A blank/whitespace key is ignored (no header sent).

Quickstart

With the key set in your environment, your first search:

jobsuche search --was Informatiker --wo Berlin --size 10

--was is the keyword/title, --wo the location. The result is a JSON object with stellenangebote (the listings array), maxErgebnisse (total matches), page and size. Pull out just the titles with jq:

jobsuche search --was Informatiker --wo Berlin --size 10 \
  | jq '[.stellenangebote[] | {titel, arbeitgeber, ort: .arbeitsort.ort}]'

Take a listing's refnr from those results and fetch its full record:

jobsuche details 10001-1002716922-S

Commands

search   [filters…]     search job listings
details  <refnr>        full details for one listing

search filters

| Flag | Meaning | | --- | --- | | --was <text> | job title / keyword (was) | | --wo <text> | location (wo) | | --umkreis <km> | radius in km around --wo (Umkreis) | | --berufsfeld <text> | occupational field (Berufsfeld) | | --arbeitgeber <text> | employer name (Arbeitgeber) | | --veroeffentlicht-seit <days> | published within the last N days | | --angebotsart <code> | offer type code, e.g. 1 regular vacancy, 4 apprenticeship | | --zeitarbeit | include temp-work / staffing agencies | | --page <n> | 1-based page index | | --size <n> | page size |

The flag names mirror the API's German field names — the Glossary decodes every one.

details <refnr>

Pass the refnr from any search result (e.g. 10001-1002716922-S, a hex form like 14225-dafcdd47aabe512d-S, or a purely numeric 1002716922). The CLI base64-encodes it into the API's encryptedJobCode for you. An already-encoded code is also accepted and passed through unchanged.

Common tasks

A few recipes to get going — see Usage.md for the full, use-case-driven set.

# Jobs within 50 km of a city
jobsuche search --was Pflegefachkraft --wo "München" --umkreis 50

# Only listings published in the last 7 days
jobsuche search --was Data --wo Hamburg --veroeffentlicht-seit 7

# Regular vacancies vs. apprenticeships (angebotsart code)
jobsuche search --was Mechatroniker --wo Stuttgart --angebotsart 1
jobsuche search --was Mechatroniker --wo Stuttgart --angebotsart 4

# Page through a large result set (1-based pages)
jobsuche search --was Kaufmann --size 25 --page 1
jobsuche search --was Kaufmann --size 25 --page 2

# Search at a specific employer
jobsuche search --arbeitgeber "Deutsche Bahn AG" --wo Frankfurt --umkreis 30

Output & scripting

Every command prints pretty JSON to stdout. Errors and diagnostics go to stderr, so piping stdout into jq stays clean.

# How many total matches for a query?
jobsuche search --was Pflege --wo Berlin | jq '.maxErgebnisse'

# Sort radius results by distance
jobsuche search --was Pflege --wo "München" --umkreis 50 \
  | jq '.stellenangebote | sort_by(.arbeitsort.entfernung)
        | .[] | {titel, ort: .arbeitsort.ort, km: .arbeitsort.entfernung}'

# Chain search → details without copy-pasting a refnr
jobsuche details "$(jobsuche search --was Informatiker --wo Berlin --size 1 \
  | jq -r '.stellenangebote[0].refnr')"

Use --compact for single-line JSON in pipelines and logs:

jobsuche --compact search --was Informatiker --size 5

--compact (and every global option) works before or after the command — both jobsuche --compact search … and jobsuche search … --compact do the same thing.

Exit codes make the CLI easy to use in scripts:

| Code | Meaning | | --- | --- | | 0 | success (also --help / --version) | | 2 | bad usage / invalid argument (nothing was sent) | | 3 | request rejected (401/403) — usually a missing or wrong API key | | 4 | listing not found (404) | | 1 | any other error (network/transport failure, JSON parse error, etc.) |

Troubleshooting

  • command not found: jobsuche — the global npm bin directory isn't on your PATH. Run npm bin -g to find it and add it, or run via npx @maschinenlesbar.org/jobsuche-cli ….
  • Exit 3 / "request rejected" — the API declined the request. The most common cause is a missing or incorrect key. Check that JOBSUCHE_API_KEY is set and non-empty, or pass --api-key explicitly. The public key is jobboerse-jobsuche (see bundesAPI/jobsuche-api).
  • Exit 4 / "not found" — the listing no longer exists. Listings expire; re-run a fresh search to get current refnr values.
  • Exit 1 / "Network error" — connectivity, DNS, or a timeout. Try again or raise the limit with --timeout 60000.
  • Empty stellenangebote — the search matched nothing; broaden --was, widen --umkreis, or drop filters.

Global options

These apply to every command and may be given before or after it:

| Option | Description | | --- | --- | | -V, --version | Print the version number | | -h, --help | Show help for the program or a command | | --compact | Print JSON on a single line instead of pretty-printed | | --api-key <key> | Override or supply the X-API-Key (env JOBSUCHE_API_KEY) | | --base-url <url> | API base URL (default https://rest.arbeitsagentur.de) | | --timeout <ms> | Per-request timeout (default 30000) | | --user-agent <ua> | User-Agent header value | | --max-retries <n> | Retries for transient 429/503 responses (default 2) | | --max-response-bytes <n> | Cap response body size in bytes (0 = unlimited; default 100 MiB) |

Advanced — pointing at a proxy or staging host

If you need to point at a proxy or staging server instead of the live API:

jobsuche --base-url https://proxy.internal.example search --was Pflege

If the API redirects across an origin boundary (different scheme/host/port), the tool strips your key before following, so it never leaks to another host.

Learn more

  • SKILLS.md — Claude Code Agent Skills bundled with this repo (market scan, job hunt, employer watch), installable as a plugin.
  • Usage.md — full use-case-driven cookbook.
  • GLOSSARY.md — every flag and domain term explained.
  • DEVELOPING.md — TypeScript library usage, architecture, testing, CI.

Data license

This CLI is a client — it accesses data it does not own or redistribute. The upstream data is © its provider and licensed separately from this tool's code. See DATA_LICENSE.md.

[!WARNING] Not open data. Bundesagentur für Arbeit — full copyright, use restricted to job-placement purposes, automated access forbidden by the terms. Personal lookup only; no redistribution or commercial reuse. Records may contain personal data (GDPR applies).

License

Dual-licensed — use it under either:

  • AGPL-3.0-or-later (default, free). Note the AGPL's §13 network clause: if you run a modified version as a network service, you must offer that modified source to the service's users.
  • Commercial license (paid), for closed-source / proprietary or SaaS use without the AGPL's obligations.

See LICENSING.md for details, and CONTRIBUTING.md for the contribution policy (this project does not accept external code contributions). Commercial enquiries: [email protected].