Os endpoints
Todo pende de https://api.password.es. Dous responden e un aínda non — e ese dío na súa propia resposta.
- POST/v1/generate Xera un ou varios contrasinais e devolve a súa análise.
- GET/openapi.json A descrición da API, en OpenAPI 3.1.
-
POST/mcp
Servidor MCP para asistentes. Unha ferramenta:
generate_password. - POST/v1/check 501 Aínda non existe. O erro explica que falta e onde ir mentres tanto.
Xerar un contrasinal
O corpo é opcional: sen el saen 16 caracteres cos catro tipos activados. Con el, o que pidas.
curl -X POST https://api.password.es/v1/generate \
-H 'content-type: application/json' \
-d '{"length":20,"exclude_ambiguous":true}'
{
"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/"
}
}
Os parámetros
Todos opcionais. A táboa vai en inglés e é idéntica nas dezaoito linguas, a propósito: quen integra unha API escribe os nomes de campo tal como se escriben, e dezaoito traducións de exclude_ambiguous serían débeda, non alcance.
| Field | Type | Default | Notes |
|---|---|---|---|
| length | integer 4–64 | 16 | How many characters. The same range as the generator on this site. |
| count | integer 1–20 | 1 | How many passwords to return. passwords is always an array, including with count 1. |
| lower | boolean | true | Include a–z (26 characters). |
| upper | boolean | true | Include A–Z (26 characters). |
| digits | boolean | true | Include 0–9 (10 characters). |
| symbols | boolean | true | Include ~!@#$%^&*()_+-=[]{};:,./<>? — the same 27 as the slider on the home page, no more. |
| exclude_ambiguous | boolean | false | Drops 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_repeats | boolean | false | Avoids 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. |
| lang | string | en | Which 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. |
Que significa cada número
A mesma idea: a referencia en inglés, a explicación ao lado. Ningún destes números é novo — saen todos do mesmo motor que debuxa o medidor da portada.
| Field | Notes |
|---|---|
| passwords | An array of strings, always — including with count 1. |
| analysis.length | How many characters came back. |
| analysis.pool | The size of the alphabet the password was drawn from. |
| analysis.bits | H = L·log2(N), the same formula as the home page. With no_repeats it becomes log2(N)+(L-1)·log2(N-1). |
| analysis.log10_guesses | The expected work, as a base-10 logarithm: half the keyspace. |
| analysis.crack_time_log10_seconds | At 1012 guesses/s, offline, fast hash. The same attack model as the rest of the site. |
| analysis.crack_time | The same figure in words. unit follows the answer language: years, años… |
| analysis.level | 0–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.ceiling | false: the server generated the password, so the figure is exact and not a ceiling. The same flag the checker uses. |
| notice | The 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.burst | The rate limit actually enforced: limit requests per window_seconds. |
| _meta.quota | The reserved daily-quota slot. limit and remaining are null because nobody counts daily requests yet. |
| _meta.docs | A link back to the documentation. |
A lingua da resposta
Por defecto responde en inglés, que é o que agarda quen integra sen dicir nada. Cámbiase de tres formas, e se non coinciden gaña a primeira: ?lang= no URL, "lang" no corpo e a cabeceira Accept-Language.
Aquí hai unha asimetría que convén saber: as mensaxes existen en inglés e castelán; as ligazóns, nas dezaoito linguas do sitio. Pedir alemán dache as ligazóns en alemán e as mensaxes aínda en inglés.
curl -X POST 'https://api.password.es/v1/generate?lang=de' \
-H 'content-type: application/json' \
-d '{"length":20}'
"_meta": {
"lang": { "messages": "en", "links": "de" }
}
Non hai que adiviñalo: cada resposta declara en _meta.lang que se aplicou a cada metade. E unha lingua que non existe non é un erro — cae ao inglés, e _meta.lang dío.
Comprobar un contrasinal: aínda non
/v1/check devolve 501. Non é un fallo nin un descoido: está así a propósito, e a resposta explica que falta e onde ir mentres tanto. O checker_url apunta ao comprobador do sitio na lingua que pediras.
curl -X POST https://api.password.es/v1/check \
-H 'content-type: application/json' \
-d '{"password":"x"}'
{
"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" }
}
Os erros
Todos teñen a mesma forma: un error curto para o código, unha message en prosa —que é o que un asistente de IA lle le ao seu usuario—, ás veces o field que o provocou, un docs e o mesmo _meta de sempre.
| HTTP | error | Notes |
|---|---|---|
| 400 | invalid_length | length outside 4–64. field names it. |
| 400 | invalid_count | count outside 1–20. field names it. |
| 400 | empty_alphabet | All four character types turned off, so there is no alphabet to draw from. No field: it is the combination, not one parameter. |
| 400 | unknown_parameter | A parameter this endpoint does not accept. field gives the offending name. |
| 429 | rate_limited | Over 60 requests in a minute. Carries Retry-After and RateLimit-* headers, and limit / window_seconds in the body. |
| 501 | not_implemented | Only from /v1/check. Carries checker_url, pointing at the web checker in the answer language. |
Os límites
Un só, e é o que se aplica de verdade: 60 peticións por minuto e por IP. Non fai falta crer esta páxina: o número viaxa en cada resposta, dentro de _meta.limits.burst.
Ao pasarse, a resposta é un 429 con Retry-After e cabeceiras RateLimit-*, máis unha mensaxe en prosa que di que facer. Non leva ligazón a rexistro nin a prezos, porque non hai rexistro nin prezos.
En _meta verás ademais un bloque quota cos dous valores en null. Está así a propósito: é o oco reservado para cando existan as contas, e vai baleiro porque hoxe ninguén conta peticións por día. Un límite anunciado e non feito cumprir é peor que non anunciar ningún.
O servidor MCP
MCP é o protocolo co que asistentes como Claude ou ChatGPT usan ferramentas externas. Conecta este enderezo ao teu asistente e poderá xerar contrasinais con estes mesmos números en vez de inventalos. Sen rexistro e sen chave, co mesmo límite de 60 peticións por minuto.
É un servidor sen estado, e convén sabelo se vés doutros servidores MCP: o POST respóndese con JSON e non se abre ningún stream, Mcp-Session-Id non se emite nin se espera, unha notificación respóndese con 202 e sen corpo, e o GET devolve 405. A especificación 2025-06-18 permíteo explicitamente.
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"}}}'
Publica unha soa ferramenta, generate_password, cos mesmos parámetros da táboa de arriba máis lang. Non hai check_password_strength e non a haberá mentres /v1/check non exista: unha ferramenta que sempre devolve erro non é unha ferramenta, é unha promesa rota dentro do catálogo dun asistente.
O aviso de que isto é un antipatrón viaxa na descrición da ferramenta e en cada resultado. É deliberado: é o que o asistente acaba lendo a quen pediu o contrasinal.
A documentación que len as máquinas
Ademais desta páxina hai unha descrición en OpenAPI 3.1, e esa si está publicada: api.password.es/openapi.json. É o que le un xerador de clientes, un editor con autocompletado ou un axente que queira saber que campos existen sen que llo conte ninguén. Describe os mesmos parámetros da táboa de arriba, os códigos de erro e o porqué do quota baleiro.