Glossary

A reference for the domain concepts and project-specific terms used throughout dip-bundestag-cli. The DIP domain is German; this glossary gives the English term used in the CLI/API (where one exists) alongside the original German.

Translation table. The CLI keeps the original German resource names (they are the API’s own paths), with the English meaning given here:

German English
Vorgang procedure / legislative process
Vorgangsposition procedure step / position within a procedure
Drucksache printed paper
Plenarprotokoll plenary protocol (minutes)
Aktivität activity
Person person (member / actor)
Wahlperiode electoral term / legislative period
Bundestag the federal parliament
Bundesrat the federal council (states’ chamber)

DIP

DIP — Dokumentations- und Informationssystem für Parlamentsmaterialien. (“Documentation and information system for parliamentary materials.”) The Bundestag’s catalogue of parliamentary process data: who proposed what, the documents involved, the plenary debates, and the people acting. Browsable at dip.bundestag.de; the machine API this tool wraps lives at search.dip.bundestag.de/api/v1.

Bundestag. The German federal parliament (the elected chamber). Bundesrat is the chamber representing the sixteen federal states (Länder). DIP covers materials from both bodies.

API key. DIP requires an API key, sent as the HTTP header Authorization: ApiKey <key>. The key is not bundled — supply it via --api-key or the DIP_API_KEY environment variable, else the header is omitted and the API returns 401. Flag, variable and library (apiKey) trim the key the same way (normaliseApiKey) and reject one an HTTP header cannot carry (exit 2, DipValidationError). The Bundestag publishes a public key on its DIP API help page (stated there in 2026 as valid until the end of May 2027); a personal key can be requested from parlamentsdokumentation@bundestag.de. The CLI’s obtain-key command reads that page’s key from the JSON document DIP’s content service serves behind it, falls back to the bundesAPI README, and verifies the key against the live API before printing it — so it fails rather than hand over a key the API rejects.


Resources (endpoints)

Each resource is exposed under /api/v1/<resource> with a list endpoint (/<resource>) and a single-item endpoint (/<resource>/<id>). The CLI mirrors this as <resource> list and <resource> get <id>.

Vorgang (procedure). A legislative or parliamentary process — e.g. a bill, a motion (Antrag), an interpellation (Anfrage) — tracked from introduction to conclusion. The central entity that ties documents, activities and people together. CLI: vorgang. Client: client.vorgaenge.

Vorgangsposition (procedure step). A single step within a Vorgang — one event in its history (e.g. a first reading, a committee referral, a vote). A Vorgang has many Vorgangspositionen. CLI: vorgangsposition. Client: client.vorgangspositionen.

Drucksache (printed paper). A formal parliamentary document — bills, motions, reports, answers to questions, etc. — identified by a paper number within an electoral term. CLI: drucksache. Client: client.drucksachen.

Drucksache-Text. The same Drucksachen, but with the extracted full text of the document included in the payload (a separate, heavier endpoint). CLI: drucksache-text. Client: client.drucksacheText.

Plenarprotokoll (plenary protocol). The stenographic minutes of a plenary sitting of the Bundestag or Bundesrat. CLI: plenarprotokoll. Client: client.plenarprotokolle.

Plenarprotokoll-Text. The Plenarprotokolle with the extracted full text of the minutes included. CLI: plenarprotokoll-text. Client: client.plenarprotokollText.

Aktivität (activity). A recorded action by a person within a procedure — e.g. a speech, a question, a signature on a motion. Links a Person to a Vorgang. CLI: aktivitaet. Client: client.aktivitaeten.

Person. A person appearing in the materials — typically a member of parliament (Abgeordnete:r), but also other actors. CLI: person. Client: client.personen.


Identifiers, filters & pagination

id. Every resource document has a numeric id, used by the get endpoint (drucksache get 123456) and by the f.id filter. The CLI’s --id flag is shorthand for f.id and is repeatable (a whole number, see below). The get id is trimmed first, so a copy-pasted "282486 " finds the document. A blank id, . or .. is rejected (CLI exit 2, library DipValidationError, same message) before any request: get("") or get(".") would otherwise request the collection endpoint and return the list, and get("..") the API root.

f.* filters (Filter). DIP filters are query parameters prefixed with f., e.g. f.titel (title), f.id, f.wahlperiode, f.datum.start / f.datum.end (date range), f.vorgangstyp, f.dokumentart, f.aktualisiert.start (last-updated range). Each list endpoint has its own set (LIST_FILTERS, from DIP’s OpenAPI description): f.vorgang exists only on vorgangsposition, f.person only on person and aktivitaet. DIP ignores an unknown filter and returns the whole unfiltered list, so the library’s list() and the CLI reject a key that is not in the resource’s set (the CLI with exit 2); list(params, { allowUnknownFilters: true }) sends one anyway, for a filter DIP added later. It passes the rest verbatim via --filter key=value (repeatable); only the first = splits key from value, so a value may itself contain =. Repeating the same key sends repeated query keys (?f.id=1&f.id=2), which DIP treats as an OR set. A blank filter value, --id or --cursor is rejected too (exit 2), and the library’s list() rejects a blank parameter name or value, an empty array and a blank array element with DipValidationError before any request: DIP treats an empty parameter as no filter. The integer filters (INTEGER_FILTERS: f.id, f.wahlperiode, f.vorgang, f.drucksache, f.plenarprotokoll, f.aktivitaet, f.person_id, f.vorgangsposition_id and f.vorgangstyp_notation, all integers in DIP’s OpenAPI description) take a non-negative whole number — plain digits on the command line (--id too), a string of digits or a number in the library; the CLI rejects anything else with exit 2 and list() with DipValidationError (integerFilterProblem), since DIP answers f.wahlperiode=abc with a misleading 400 … Invalid cursor.

cursor. DIP list endpoints are cursor-paginated. A list response carries a cursor; pass it back via --cursor (CLI) or { cursor } (library) to fetch the next page. The cursor is opaque — treat it as a token, not a number. When the returned cursor stops changing, you have reached the end. Send the same filters again with every cursor: DIP does not bind a cursor to the query it came from, so a cursor sent without them pages through the whole unfiltered list. So a cursor without any filter is refused: the CLI’s --cursor without a --filter or --id is a usage error (exit 2), and the library’s list() throws DipValidationError (cursorWithoutFiltersProblem) unless { allowUnfilteredCursor: true } is passed to page the unfiltered list on purpose.

numFound. The total number of documents matching a list query (across all pages), returned in the list envelope alongside the current page’s documents.

documents. The array of resource documents in the current page of a list response. Each is exposed as a faithful raw JsonObject (the per-resource payloads are large and resource-specific, so they are not narrowed to typed fields).

Wahlperiode (electoral term). The numbered legislative period of the Bundestag (e.g. the 20th Wahlperiode). Most resources carry a wahlperiode field and can be filtered with f.wahlperiode; document numbers are scoped to a Wahlperiode.

Vorgangstyp (procedure type). The classification of a Vorgang (e.g. Gesetzgebung — legislation, Antrag — motion, Kleine Anfrage — minor interpellation). Filterable via f.vorgangstyp.

Dokumentart (document type). Whether a document is a Drucksache or a Plenarprotokoll. Filterable via f.dokumentart on vorgang, vorgangsposition and aktivitaet. The kind of Drucksache (Antrag, Gesetzentwurf, Antwort, …) is drucksachetyp, filterable via f.drucksachetyp.

Datum (date). The date a document/activity is dated. Date-range filtering uses f.datum.start and f.datum.end (ISO YYYY-MM-DD). The query builder serialises Date values to full ISO-8601 instants in UTC (2024-01-01T00:00:00.000Z), which DIP accepts for f.aktualisiert.* but not for f.datum.* (HTTP 400 Invalid date). Library users pass f.datum.* as a "YYYY-MM-DD" string: a Date is an instant, and a local midnight such as new Date(2024, 0, 1) in Berlin is 2023-12-31T23:00:00.000Z, the day before.

Zuordnung (assignment). Some resources can be filtered by chamber/assignment (f.zuordnung), distinguishing Bundestag (BT) from Bundesrat (BR) materials.


API behaviour & errors

Base URL. Defaults to https://search.dip.bundestag.de; override with --base-url (CLI) or baseUrl (library). All resource paths are under /api/v1, which the client adds: the base URL is the host (plus any mirror path prefix) without it. The CLI and the library (validateBaseUrl) reject one that does not parse, is not http:/https:, ends in /api/v1, has surrounding whitespace or whitespace inside, has a query or fragment, or has a % in the user name or password that is not an escape (a literal % is written %25), before any request, with the same reason (library: DipValidationError, not DipNetworkError). Userinfo in it (user:password@) is sent, but redacted to ***@ in everything the CLI prints and in the library’s errors.

Rate limiting. DIP limits the request rate; the API returns 429 when it is exceeded. The client retries 429 and 503, and a connection reset mid-request, automatically (--max-retries, 0–10, default 2), backing off linearly, or waiting the response’s Retry-After when that is longer (never shorter, so Retry-After: 0 causes no burst). A Retry-After over 30 s is not retried, and the error names the requested wait. Each retry is a WARN record of dip.http (HTTP 503 from host: retry 1 of 3 in 2 s); the library offers it as onRetry. The library holds the same bound (MAX_RETRIES, maxRetries) and rejects a value outside it with DipValidationError, as it does a negative or fractional timeout or size cap.

Credential stripping on redirect. The API key (and X-API-Key / Cookie, and a base URL’s user:password@) goes only to the base URL’s origin. A redirect to another origin — another host, port or scheme, http→https included — drops it, so the key is never leaked to a host other than the one you targeted. Same-origin redirects keep it, with an absolute Location too. A 401 after such a redirect is not about the key, and the error says so (“use an https base URL” for http→https).

Error types. errors.ts: DipApiError (non-2xx, carries status/detail/url/method/body, with isRetryable for 429/503), DipNetworkError (transport failure/timeout, never a bad base URL), DipParseError (bad JSON, or a 2xx body that is not a DIP list or document: null, [], an error object), DipUsageError (a usage error, no request made) and its subclass DipValidationError (the library rejected an input before any request: Invalid <name>: <reason>), all extending DipError. Exit codes: 0 success, 2 usage errors, 4 on a 404, 1 for any other runtime error (including 401 when the key is missing/expired).

Log record. Every diagnostic line the CLI writes to stderr: a timestamp, a level (ERROR, WARN, INFO) and a topic dip.<area>, as text (log4j style) or with --log-format jsonl as one JSON object per line. The areas: cli (usage errors, commander’s messages, unexpected errors), api (the API’s answers: an error status, and a malformed answer — bad JSON, the wrong shape, an empty body), http (the connection, the cleartext warning, and one WARN per retry before it waits), config, obtain-key and output (the -o file, stdout failures). A record is always one line; control characters in it are escaped.


Library & internals. Terms for the TypeScript client and its internals — DipClient, resource groups, the request engine, transport, retry/backoff, error types, query builder — now live in DEVELOPING.md.

View the source on GitHub →