API

Referenz der Passwort-API

Die Referenz zu api.password.es: jeder Parameter, jedes Feld der Antwort, jeder Fehlercode und die Grenzen. Die Beispiele lassen sich so, wie sie dastehen, ins Terminal einfügen.

Wenn du wissen willst, was das ist, für wen und wann man es besser nicht benutzt, fang bei der API-Seite an.

Die Endpunkte

Alles hängt an https://api.password.es. Zwei antworten und einer noch nicht — und der eine sagt es in seiner eigenen Antwort.

Ein Passwort erzeugen

Der Body ist optional: ohne ihn bekommst du 16 Zeichen mit allen vier Zeichenarten. Mit ihm das, was du verlangst.

Die Anfrage
curl -X POST https://api.password.es/v1/generate \
  -H 'content-type: application/json' \
  -d '{"length":20,"exclude_ambiguous":true}'
Die Antwort
{
  "passwords": [
    "P#f.aK+w4pcsx]}Gx;*>"
  ],
  "analysis": {
    "length": 20,
    "pool": 83,
    "bits": 127.50078862693852,
    "log10_guesses": 38.08053185185735,
    "crack_time_log10_seconds": 26.08053185185735,
    "crack_time": {
      "value": "3.8 × 10¹⁸",
      "unit": "years"
    },
    "level": 4,
    "level_scale": "time",
    "ceiling": false
  },
  "notice": "Generated on someone else's machine, which is a security antipattern even though we store nothing. For a password you will actually use, the generator at https://password.es/en/ runs entirely in your browser and sends nothing.",
  "_meta": {
    "plan": "anonymous",
    "lang": {
      "messages": "en",
      "links": "en"
    },
    "limits": {
      "burst": {
        "limit": 60,
        "window_seconds": 60
      }
    },
    "quota": {
      "limit": null,
      "remaining": null,
      "reset": "2026-09-01T00:00:00.000Z"
    },
    "docs": "https://password.es/api/"
  }
}

Die Parameter

Alle optional. Die Tabelle steht auf Englisch und ist in allen achtzehn Sprachen identisch, mit Absicht: wer eine API einbindet, tippt die Feldnamen genau so, wie sie geschrieben sind, und achtzehn Übersetzungen von exclude_ambiguous wären Schuld, nicht Umfang.

FieldTypeDefaultNotes
lengthinteger 4–6416How many characters. The same range as the generator on this site.
countinteger 1–201How many passwords to return. passwords is always an array, including with count 1.
lowerbooleantrueInclude a–z (26 characters).
upperbooleantrueInclude A–Z (26 characters).
digitsbooleantrueInclude 0–9 (10 characters).
symbolsbooleantrueInclude ~!@#$%^&*()_+-=[]{};:,./<>? — the same 27 as the slider on the home page, no more.
exclude_ambiguousbooleanfalseDrops 0 O 1 I l | o. Six of them in practice, not seven: | is not in the symbol set to begin with. That is why pool reads 83 above instead of 89.
no_repeatsbooleanfalseAvoids adjacent repeated characters. Not an absolute guarantee: it retries ten times, exactly as the web generator does. At length 64 that lets a repeat through about 0.1% of the time.
langstringenWhich language to answer in. One of the site's eighteen. Also accepted as ?lang= in the URL, which wins over this field; without either, Accept-Language is read. An unknown value is not an error — it falls back to English. See the section below: messages exist in English and Spanish, links in all eighteen.

Was jede Zahl bedeutet

Dasselbe: die Referenz auf Englisch, die Erklärung daneben. Keine dieser Zahlen ist neu — sie kommen alle aus demselben Motor, der auf der Startseite die Anzeige zeichnet.

FieldNotes
passwordsAn array of strings, always — including with count 1.
analysis.lengthHow many characters came back.
analysis.poolThe size of the alphabet the password was drawn from.
analysis.bitsH = L·log2(N), the same formula as the home page. With no_repeats it becomes log2(N)+(L-1)·log2(N-1).
analysis.log10_guessesThe expected work, as a base-10 logarithm: half the keyspace.
analysis.crack_time_log10_secondsAt 1012 guesses/s, offline, fast hash. The same attack model as the rest of the site.
analysis.crack_timeThe same figure in words. unit follows the answer language: years, años
analysis.level0–4. The same scale as the checker, ever since the site unified the two it used to have.
analysis.level_scale"time". Says where the level came from, so that a future divergence is visible instead of having to be inferred by comparing numbers.
analysis.ceilingfalse: the server generated the password, so the figure is exact and not a ceiling. The same flag the checker uses.
noticeThe antipattern warning, in every single response.
_meta.plan"anonymous". The only lane there is; the others arrive with accounts.
_meta.lang{ "messages", "links" } — which language each half actually came back in. They can differ, and that is why the API says so instead of leaving you to guess.
_meta.limits.burstThe rate limit actually enforced: limit requests per window_seconds.
_meta.quotaThe reserved daily-quota slot. limit and remaining are null because nobody counts daily requests yet.
_meta.docsA link back to the documentation.

Die Sprache der Antwort

Standardmäßig antwortet sie auf Englisch — das erwartet, wer ohne weitere Angabe einbindet. Drei Wege, das zu ändern, und bei Widerspruch gewinnt der erste: ?lang= in der URL, "lang" im Body und der Header Accept-Language.

Hier gibt es eine Schieflage, die man kennen sollte: die Meldungen gibt es auf Englisch und Spanisch; die Links in allen achtzehn Sprachen der Website. Wer Deutsch verlangt, bekommt deutsche Links und Meldungen weiterhin auf Englisch.

Die Anfrage
curl -X POST 'https://api.password.es/v1/generate?lang=de' \
  -H 'content-type: application/json' \
  -d '{"length":20}'
Die Antwort
"_meta": {
  "lang": { "messages": "en", "links": "de" }
}

Raten muss man nicht: jede Antwort erklärt in _meta.lang, was auf welche Hälfte angewandt wurde. Und eine Sprache, die es nicht gibt, ist kein Fehler — sie fällt auf Englisch zurück, und _meta.lang sagt es.

Ein Passwort prüfen: noch nicht

/v1/check gibt 501 zurück. Weder Bug noch Versehen: es ist Absicht, und die Antwort erklärt, was fehlt und wohin man solange geht. checker_url zeigt auf den Checker der Website in der angeforderten Sprache.

Die Anfrage
curl -X POST https://api.password.es/v1/check \
  -H 'content-type: application/json' \
  -d '{"password":"x"}'
Die Antwort
{
  "error": "not_implemented",
  "message": "/v1/check does not exist yet. Returning the same numbers as the password.es checker requires its very same pattern engine, and that costs between 11 ms and 3.6 s of CPU per request depending on the input: it is waiting on a plan cap decision and on a length cap. Meanwhile the web checker does exactly this in your browser, sending nothing: https://password.es/en/checker/",
  "checker_url": "https://password.es/en/checker/",
  "docs": "https://password.es/api/",
  "_meta": { "…": "igual que arriba" }
}

Die Fehler

Alle haben dieselbe Form: ein kurzer error als Code, ein message in Klartext —das ist es, was ein KI-Assistent seinem Nutzer vorliest—, manchmal das field, das ihn ausgelöst hat, ein docs und dasselbe _meta wie immer.

HTTPerrorNotes
400invalid_lengthlength outside 4–64. field names it.
400invalid_countcount outside 1–20. field names it.
400empty_alphabetAll four character types turned off, so there is no alphabet to draw from. No field: it is the combination, not one parameter.
400unknown_parameterA parameter this endpoint does not accept. field gives the offending name.
429rate_limitedOver 60 requests in a minute. Carries Retry-After and RateLimit-* headers, and limit / window_seconds in the body.
501not_implementedOnly from /v1/check. Carries checker_url, pointing at the web checker in the answer language.

Die Grenzen

Eine, und es ist die, die wirklich durchgesetzt wird: 60 Anfragen pro Minute und IP. Man muss dieser Seite nicht glauben: die Zahl reist in jeder Antwort mit, in _meta.limits.burst.

Wer darüber hinausgeht, bekommt einen 429 mit Retry-After und RateLimit-*-Headern, dazu eine Nachricht in Klartext, die sagt, was zu tun ist. Sie enthält keinen Link auf Registrierung oder Preise, weil es weder Registrierung noch Preise gibt.

In _meta steht außerdem ein Block quota, beide Werte auf null. Das ist Absicht: der reservierte Platz für den Tag, an dem es Konten gibt — leer, weil heute niemand Anfragen pro Tag zählt. Eine angekündigte und nicht durchgesetzte Grenze ist schlimmer, als gar keine anzukündigen.

Der MCP-Server

MCP ist das Protokoll, mit dem Assistenten wie Claude oder ChatGPT externe Werkzeuge nutzen. Verbinde diese Adresse mit deinem Assistenten, und er erzeugt Passwörter mit genau diesen Zahlen, statt sie zu erfinden. Ohne Registrierung, ohne Schlüssel und mit demselben Limit von 60 Anfragen pro Minute.

Es ist ein zustandsloser Server, und das ist wichtig zu wissen, wenn du von anderen MCP-Servern kommst: Der POST wird mit JSON beantwortet, ohne Stream, Mcp-Session-Id wird weder gesendet noch erwartet, eine Notification erhält 202 ohne Body, und der GET liefert 405. Die Spezifikation 2025-06-18 erlaubt das ausdrücklich.

curl -X POST https://api.password.es/mcp \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"generate_password",
                 "arguments":{"length":20,"lang":"es"}}}'

Er veröffentlicht ein einziges Werkzeug, generate_password, mit denselben Parametern wie in der Tabelle oben plus lang. Es gibt kein check_password_strength und wird keines geben, solange /v1/check nicht existiert: Ein Werkzeug, das immer einen Fehler zurückgibt, ist kein Werkzeug, sondern ein gebrochenes Versprechen im Katalog eines Assistenten.

Der Hinweis, dass dies ein Antipattern ist, reist in der Werkzeugbeschreibung und in jedem Ergebnis mit. Das ist Absicht: Es ist das, was der Assistent demjenigen vorliest, der nach dem Passwort gefragt hat.

Die Dokumentation, die Maschinen lesen

Neben dieser Seite gibt es eine OpenAPI-3.1-Beschreibung, und die ist veröffentlicht: api.password.es/openapi.json. Sie ist das, was ein Client-Generator, ein Editor mit Autovervollständigung oder ein Agent liest, um zu erfahren, welche Felder es gibt, ohne dass es ihm jemand sagt. Sie beschreibt dieselben Parameter wie die Tabelle oben, die Fehlercodes und den Grund für das leere quota.