Website: English · Deutsch — command reference, guides and API docs
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.
search and details.--compact for one-line/scripting.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.
npm i -g @maschinenlesbar.org/jobsuche-cli
This installs the jobsuche command. Requires Node.js 20+.
Check it works:
jobsuche --help
The Jobsuche API requires a static X-API-Key. No key is bundled with this
package — 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).
Precedence is --api-key > JOBSUCHE_API_KEY env var. A blank/whitespace key
is ignored (no header sent). You do not have to go and find the key yourself —
see Obtain key.
The Bundesagentur für Arbeit publishes one static key for public use. It is
not a secret — it is the same value for everyone, printed in the upstream
bundesAPI/jobsuche-api README — but
finding and copying it shouldn't be your job either. obtain-key reads it from
that published source at run time and prints it:
jobsuche obtain-key # -> jobboerse-jobsuche (provenance note on stderr)
From obtaining the key to having it where it is used, in one line:
# this shell only
eval "$(jobsuche obtain-key --export)"
# or keep it for later — appends one `export …` line to your shell profile
jobsuche obtain-key --export >> ~/.zshrc # ~/.bashrc on bash
--export prints a single shell-quoted export JOBSUCHE_API_KEY='…' line on
stdout (the "obtained from …" note goes to stderr, so it never lands in your
profile). The plain form composes too:
export JOBSUCHE_API_KEY="$(jobsuche obtain-key)"
Because the key is fetched rather than compiled in, a rotated key needs no
release of this CLI. If the upstream source is unreachable or stops publishing a
key, obtain-key fails loudly with a non-zero exit rather than printing a guess
— it will never invent a value.
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
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.
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
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) — a missing or wrong API key, or a refused network |
4 |
listing not found (404) |
1 |
any other error (network/transport failure, JSON parse error, etc.) |
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 ….3 / "request rejected" — the API declined the request. Check that
JOBSUCHE_API_KEY is set and non-empty, or pass --api-key explicitly —
jobsuche obtain-key gives you the current public value (see
Obtain key). A 403 with an empty body is ambiguous: the gateway
sends the same response for a wrong key and for a network it refuses. If the key
matches what obtain-key returns, try from another network.4 / "not found" — the listing no longer exists. Listings expire;
re-run a fresh search to get current refnr values.1 / "Network error" — connectivity, DNS, or a timeout. Try again
or raise the limit with --timeout 60000.stellenangebote — the search matched nothing; broaden --was,
widen --umkreis, or drop filters.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; at most 2147483647) |
--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) |
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.
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.
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).
Dual-licensed — use it under either:
See LICENSING.md for details, and CONTRIBUTING.md for the contribution policy (this project does not accept external code contributions). Commercial enquiries: sebs@2xs.org.