The www2.deepl.com/jsonrpc backends behind LMT_handle_texts /
LMT_handle_jobs now sit behind aggressive WAF + per-IP throttling that
returns HTTP 429 (code 1042911 "Too many requests") within a handful of
calls from any single host — making the free path effectively unusable.
The official DeepL browser extension and iOS app skip that backend
entirely for stateless single-shot translation and POST to a separate
"oneshot" endpoint on a different host pool with its own (much looser)
rate limit. It accepts anonymous traffic with a literal
`Authorization: None` header, returns plain JSON, and supports the same
language pairs.
Switch the free path to:
POST https://oneshot-free.www.deepl.com/v1/translate
Authorization: None
{"text": ["..."], "target_lang": "de", "source_lang": "en"}
Pro users continue to hit oneshot-pro.www.deepl.com with their bearer
token (the `-s` flag now carries an OAuth access token rather than the
legacy dl_session cookie).
This removes:
- the JSON-RPC envelope (jsonrpc/method/id/params/timestamp wrapper)
- the `i`-count timestamp trick (getICount + getTimeStamp)
- the random-id body-spacing trick (handlerBodyMethod)
- the whatlanggo client-side detection (oneshot detects server-side)
The DeepLXTranslationResult contract is unchanged for service handlers;
Alternatives is now always nil because the oneshot endpoint does not
return alternative translations.
Verified against /translate, /v1/translate and /v2/translate routes
end-to-end (EN/DE/ZH/JA/FR pairs, multi-sentence input, autodetect, 10x
burst) — all 200 OK on an IP that was concurrently being 429'd by www2.
- Renamed makeRequest to makeRequestWithBody for clarity.
- Introduced new TextItem and TextResponse types for better structure in translation requests and responses.
- Updated translation logic to handle multiple texts and alternatives.
- Enhanced error handling for blocked requests and translation failures.
- Adjusted timestamp and random number generation for improved request uniqueness.