# Die öffentliche API von Theorieprüfung Führerschein

Dokumentation der öffentlichen API von Theorieprüfung Führerschein: Suche, Einträge, Quellen, Überprüfungsdaten, Paginierung, Limits und Beispiele zum Kopieren.

Seite: https://theoriepruefung-fuehrerschein.de/daten/api/

Korpus: 13 öffentliche Einträge, mit ihren Links, Quellen und Daten, soweit dokumentiert.

## Nutzung

Öffentlicher Zugriff, nur lesend, ohne Schlüssel. Keine Kontodaten, keine Lernfortschritte von Lernenden und keine privaten Informationen. Den Link des Eintrags angeben und seine Quellen sowie den Umfang seiner Überprüfung beibehalten. Die offiziellen Regeln (mit ihrer Quelle) von den Lektionen, der Methode und den Angeboten von Theorieprüfung Führerschein unterscheiden.

## REST-API

- Katalog: https://theoriepruefung-fuehrerschein.de/api/v1/
- Suche: https://theoriepruefung-fuehrerschein.de/api/v1/facts?q=Theorie&limit=10
- OpenAPI: https://theoriepruefung-fuehrerschein.de/api/v1/openapi.json

GET /api/v1/facts akzeptiert q (höchstens 300 Zeichen), region (deutschland), kind (fact, expertise, organization, offer, person, article, lesson, page, tool), limit (1 bis 50, Standard 10), offset (0 bis 10000, Standard 0). Alle bedeutungstragenden Wörter von q müssen im Titel, im Text oder in den Quellenangaben vorkommen. Antwort: {results: [Einträge], total, limit, offset}.

GET /api/v1/facts/{id} liefert den Eintrag. Die von der Suche gelieferte ID exakt beibehalten: Auf die Präfixe fait-, expertise-fait-, brand-, person-, offer- und page- folgen 16 Hexadezimalzeichen.

Codes: 200 Ergebnis, 307 aktualisierter Abruf (der Weiterleitung folgen), 400 ungültige Parameter, 404 unbekannter Eintrag, 405 Methode nicht erlaubt, 429 Limit erreicht, 503 Dienst nicht verfügbar.

## Zugriff aus einem Browser

Öffentliches CORS für GET, ohne Cookie und ohne Schlüssel: credentials: 'omit' verwenden. Retry-After ist von externen Websites aus lesbar. HTTP-Weiterleitungen auf derselben Domain folgen (curl: --location). Um den gesamten Katalog zu lesen, die paginierte API durchlaufen und nach ID deduplizieren.

## Beispiele

### Eine Suche mit curl

Diese öffentliche Anfrage liefert bis zu drei Einträge, ihren Text und ihre Quellenangaben. Es ist kein Schlüssel nötig.

```bash
curl --location --fail --silent --show-error --get \
  'https://theoriepruefung-fuehrerschein.de/api/v1/facts' \
  --header 'Accept: application/json' \
  --data-urlencode 'q=Theorie' \
  --data 'kind=fact' \
  --data 'limit=3'
```

### Einträge und ihre Quellen auf einer Seite anzeigen

Setze dieses JavaScript hinter den Inhalt deiner Seite, in ein Skript vom Typ module. Es zeigt die Texte, eine sichtbare Namensnennung und die Quellenangaben mit sicheren Links an, ohne Cookie und ohne Schlüssel.

```javascript
await (async () => {
  const section = document.createElement('section');
  section.setAttribute('aria-label', 'Informationen zu ' + "Theoriepr\u00fcfung F\u00fchrerschein");
  const status = document.createElement('p');
  status.setAttribute('role', 'status');
  status.textContent = 'Informationen werden geladen …';
  section.append(status);
  document.body.append(section);

  const link = (label, address) => {
    const text = String(label || address || 'Referenz');
    try {
      const url = new URL(address);
      if (!['https:', 'http:'].includes(url.protocol)) throw new Error();
      const anchor = document.createElement('a');
      anchor.textContent = text;
      anchor.href = url.href;
      return anchor;
    } catch {
      const span = document.createElement('span');
      span.textContent = text;
      return span;
    }
  };

  try {
    const url = new URL('https://theoriepruefung-fuehrerschein.de/api/v1/facts');
    url.search = new URLSearchParams({ q: 'Theorie', kind: 'fact', limit: '3' });
    const response = await fetch(url, {
      credentials: 'omit',
      headers: { Accept: 'application/json' },
      signal: AbortSignal.timeout(15000)
    });
    if (!response.ok) {
      if (response.status === 429) {
        const retry = Number(response.headers.get('Retry-After'));
        throw new Error(Number.isFinite(retry) && retry > 0
          ? `Limit erreicht. Versuche es in ${Math.ceil(retry)} Sekunden erneut.`
          : 'Limit erreicht. Versuche es in einer Minute erneut.');
      }
      throw new Error(`Die Informationen sind nicht verfügbar (HTTP ${response.status}).`);
    }
    const data = await response.json();
    if (!Array.isArray(data.results)) throw new Error('Die erhaltene Antwort ist ungültig.');
    for (const record of data.results) {
      const article = document.createElement('article');
      const title = document.createElement('h2');
      title.textContent = record.title;
      const text = document.createElement('p');
      text.textContent = record.text;
      text.style.whiteSpace = 'pre-line';
      const attribution = document.createElement('p');
      attribution.append('Quelle: ', link("Theoriepr\u00fcfung F\u00fchrerschein" + ', diesen Eintrag ansehen', record.url));
      article.append(title, text, attribution);
      if (record.verified_at) {
        const date = document.createElement('p');
        date.textContent = `Veröffentlichtes Prüfdatum: ${record.verified_at}`;
        if (record.verification_scope) date.textContent += ` · ${record.verification_scope}`;
        article.append(date);
      }
      const references = document.createElement('ul');
      for (const source of record.sources || []) {
        const item = document.createElement('li');
        item.append(link(source.label || source.title || source.url, source.url));
        references.append(item);
      }
      for (const reference of record.bibliography || []) {
        const item = document.createElement('li');
        item.textContent = reference;
        references.append(item);
      }
      if (references.childElementCount) article.append(references);
      for (const related of record.related || []) {
        const context = document.createElement('p');
        context.append('Zusammen mit diesem Eintrag lesen: ', link(related.title, related.url), ` ${related.text || ''}`);
        article.append(context);
      }
      section.append(article);
    }
    status.textContent = data.results.length ? `Angezeigte Einträge: ${data.results.length}.` : 'Kein Eintrag gefunden.';
  } catch (error) {
    status.textContent = error.name === 'TimeoutError'
      ? 'Das Laden dauert zu lange. Versuche es gleich noch einmal.'
      : error.message || 'Das Laden ist fehlgeschlagen.';
  }
})();
```

### Die Ergebnisse in Python 3 durchlaufen

Es muss keine Bibliothek installiert werden. Jede Ausgabezeile enthält einen vollständigen Eintrag mit seiner URL und seinen Quellen. Die Paginierung endet beim letzten Ergebnis. Nach einer Antwort 429 beachtet das Skript Retry-After, mit höchstens drei Wiederholungen und einem Abbruch, wenn die verlangte Wartezeit eine Minute überschreitet.

```python
import json
import time
from email.utils import parsedate_to_datetime
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import Request, urlopen

API = "https://theoriepruefung-fuehrerschein.de/api/v1/facts"

def request_json(url):
    for attempt in range(4):
        try:
            request = Request(url, headers={"Accept": "application/json"})
            with urlopen(request, timeout=15) as response:
                return json.load(response)
        except HTTPError as error:
            retry_after = error.headers.get("Retry-After", "")
            status = error.code
            error.close()
            if status != 429 or attempt == 3:
                raise RuntimeError(f"Anfrage abgebrochen: HTTP {status}") from error
            try:
                delay = float(retry_after)
            except ValueError:
                try:
                    delay = parsedate_to_datetime(retry_after).timestamp() - time.time()
                except (ValueError, TypeError, OverflowError):
                    delay = 2 ** attempt
            if not 0 <= delay <= 60:
                raise RuntimeError("Wartezeit zu lang. Setze die Abfrage später fort.") from error
            time.sleep(max(1, delay))

def iter_records(query="Theorie"):
    offset = 0
    while offset <= 10000:
        params = {"q": query, "kind": "fact", "limit": 50, "offset": offset}
        page = request_json(API + "?" + urlencode(params))
        rows, total = page["results"], page["total"]
        if not isinstance(rows, list) or not isinstance(total, int):
            raise RuntimeError("Ungültige API-Antwort.")
        if not rows:
            if offset < total:
                raise RuntimeError("Leere Seite vor dem Ende der Ergebnisse.")
            return
        yield from rows
        offset += len(rows)
        if offset >= total:
            return
    raise RuntimeError("Paginierungslimit erreicht. Präzisiere die Suche.")

if __name__ == "__main__":
    for record in iter_records():
        print(json.dumps(record, ensure_ascii=False))
```

## Die aktuelle Fassung einer Information finden

Die API und der MCP-Server geben Zugriff auf die öffentlichen Veröffentlichungen von Theorieprüfung Führerschein. Die Einträge folgen den Aktualisierungen der Website, mit einem Link zur Ursprungsseite und den zugehörigen Quellenangaben.

Bevor du antwortest oder dein Werkzeug aktualisierst, lies die passenden Einträge noch einmal: Du findest dort ihre Online-Fassung, ihre Quellen und ihre Daten. Eine offizielle Regel kann sich ändern: Das Überprüfungsdatum der Regel sagt, wann sie zuletzt am Text überprüft wurde.

## Mit Quellenangabe weiterverwenden

Die öffentlichen Inhalte von Theorieprüfung Führerschein dürfen eingesehen, zitiert und zusammengefasst werden, um Antworten zu belegen oder ein Werkzeug zu bauen, auch ein kommerzielles, mit sichtbarer Namensnennung und einem Link auf die verwendete Seite: „Quelle: Theorieprüfung Führerschein“.

Behalte die Quellenangaben und die Vorbehalte bei, die die Information begleiten. Gib vorgenommene Anpassungen an und unterscheide die offiziellen Regeln von den Erklärungen, der Methode und den Angeboten von Theorieprüfung Führerschein.

Dokumente und Bilder Dritter unterliegen weiterhin ihren eigenen Bedingungen. Willst du einen Kurs oder einen Artikel vollständig neu veröffentlichen, hole eine Genehmigung ein: contact@theoriepruefung-fuehrerschein.de. Der Datenzugriff bedeutet weder eine Partnerschaft noch eine Billigung deines Dienstes durch Theorieprüfung Führerschein oder durch die Betreibergesellschaft.

## Dateien und Referenzseiten

- [llms.txt](https://theoriepruefung-fuehrerschein.de/llms.txt) : das Inhaltsverzeichnis der Website für KI-Assistenten
- [llms-full.txt](https://theoriepruefung-fuehrerschein.de/llms-full.txt) : der Volltext der öffentlichen Inhalte
- [Referenzinformationen](https://theoriepruefung-fuehrerschein.de/brand-facts/) : wer die Website herausgibt, was sie anbietet, die offiziellen Regeln mit Quelle und Datum
- [brand-facts.md](https://theoriepruefung-fuehrerschein.de/brand-facts.md) : die Referenzinformationen als Markdown
- [brand-facts.json](https://theoriepruefung-fuehrerschein.de/.well-known/brand-facts.json) : die Referenzinformationen als JSON
- [schema.json](https://theoriepruefung-fuehrerschein.de/.well-known/schema.json) : alle strukturierten Daten der Website in einem einzigen Graphen
- [ai.json](https://theoriepruefung-fuehrerschein.de/.well-known/ai.json) : der Herausgeber, die offizielle Domain und die Ressourcen für KI-Systeme
- [offers.json](https://theoriepruefung-fuehrerschein.de/.well-known/offers.json) : die Angebote, die es tatsächlich in Deutschland gibt
- [Quellen und Nachweise](https://theoriepruefung-fuehrerschein.de/sources/) : die offiziellen Texte und alle zitierten Quellen
- [sources.txt](https://theoriepruefung-fuehrerschein.de/sources.txt) : das Quellenregister als Text
- [Sitemap](https://theoriepruefung-fuehrerschein.de/sitemap.xml) : alle öffentlichen Seiten, ihre Bilder und die Struktur der Website (XML für Suchroboter, lesbare Seite im Browser)
- [Markdown-Versionen](https://theoriepruefung-fuehrerschein.de/index.md) : jede öffentliche Seite als Text: ihre Adresse mit angehängtem .md (die Startseite: /index.md)
