API

Riferimento dell'API delle password

Il riferimento di api.password.es: ogni parametro, ogni campo della risposta, ogni codice di errore e i limiti. Gli esempi si incollano in un terminale così come sono.

Se quello che cerchi è che cosa sia, per chi e quando non conviene usarlo, parti da la pagina dell'API.

Gli endpoint

Tutto pende da https://api.password.es. Due rispondono e uno non ancora — e quello lo dice nella propria risposta.

Generare una password

Il corpo è facoltativo: senza, escono 16 caratteri con tutti e quattro i tipi attivi. Con, quello che chiedi.

La richiesta
curl -X POST https://api.password.es/v1/generate \
  -H 'content-type: application/json' \
  -d '{"length":20,"exclude_ambiguous":true}'
La risposta
{
  "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/"
  }
}

I parametri

Tutti facoltativi. La tabella è in inglese ed è identica in tutte e diciotto le lingue, di proposito: chi integra un'API scrive i nomi dei campi esattamente come sono, e diciotto traduzioni di exclude_ambiguous sarebbero debito, non portata.

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.

Che cosa significa ogni numero

Stessa idea: il riferimento in inglese, la spiegazione accanto. Nessuno di questi numeri è nuovo — escono tutti dallo stesso motore che disegna l'indicatore in home page.

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.

La lingua della risposta

Per impostazione predefinita risponde in inglese, che è ciò che si aspetta chi integra senza dire nulla. Si cambia in tre modi, e se sono in disaccordo vince il primo: ?lang= nell'URL, "lang" nel corpo e l'intestazione Accept-Language.

Qui c'è un'asimmetria che conviene conoscere: i messaggi esistono in inglese e spagnolo; i link, in tutte e diciotto le lingue del sito. Chiedere il tedesco dà link in tedesco e messaggi ancora in inglese.

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

Non serve indovinare: ogni risposta dichiara in _meta.lang che cosa è stato applicato a ciascuna metà. E una lingua che non esiste non è un errore — ricade sull'inglese, e _meta.lang lo dice.

Controllare una password: non ancora

/v1/check restituisce 501. Non è un bug né una dimenticanza: è voluto, e la risposta spiega che cosa manca e dove andare nel frattempo. checker_url punta al controllo del sito nella lingua che hai chiesto.

La richiesta
curl -X POST https://api.password.es/v1/check \
  -H 'content-type: application/json' \
  -d '{"password":"x"}'
La risposta
{
  "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" }
}

Gli errori

Hanno tutti la stessa forma: un error breve per il codice, un message in chiaro —è quello che un assistente di IA legge al suo utente—, a volte il field che l'ha causato, un docs e lo stesso _meta di sempre.

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.

I limiti

Uno solo, ed è quello che viene davvero applicato: 60 richieste al minuto per IP. Non serve credere a questa pagina: il numero viaggia in ogni risposta, dentro _meta.limits.burst.

Superandolo, la risposta è un 429 con Retry-After e intestazioni RateLimit-*, più un messaggio in chiaro che dice che cosa fare. Non contiene link a registrazione o prezzi, perché non ci sono né registrazione né prezzi.

In _meta c'è anche un blocco quota con entrambi i valori a null. È voluto: è lo spazio riservato a quando esisteranno gli account, ed è vuoto perché oggi nessuno conta le richieste al giorno. Un limite annunciato e non fatto rispettare è peggio che non annunciarne nessuno.

Il server MCP

MCP è il protocollo con cui assistenti come Claude o ChatGPT usano strumenti esterni. Collega questo indirizzo al tuo assistente e genererà password con questi stessi numeri invece di inventarle. Senza registrazione e senza chiave, con lo stesso limite di 60 richieste al minuto.

È un server senza stato, ed è bene saperlo se vieni da altri server MCP: il POST riceve una risposta JSON senza aprire alcuno stream, Mcp-Session-Id non viene emesso né atteso, una notifica riceve 202 senza corpo, e il GET restituisce 405. La specifica 2025-06-18 lo consente esplicitamente.

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"}}}'

Pubblica un solo strumento, generate_password, con gli stessi parametri della tabella qui sopra più lang. Non c'è check_password_strength e non ci sarà finché /v1/check non esisterà: uno strumento che restituisce sempre un errore non è uno strumento, è una promessa rotta nel catalogo di un assistente.

L'avviso che questo è un antipattern viaggia nella descrizione dello strumento e in ogni risultato. È deliberato: è ciò che l'assistente finisce per leggere a chi ha chiesto la password.

La documentazione che leggono le macchine

Oltre a questa pagina c'è una descrizione in OpenAPI 3.1, e quella sì è pubblicata: api.password.es/openapi.json. È ciò che legge un generatore di client, un editor con autocompletamento o un agente che voglia sapere quali campi esistono senza che glielo dica nessuno. Descrive gli stessi parametri della tabella qui sopra, i codici d'errore e il perché del quota vuoto.