API keys
Allow-list of `key` query-string values. Missing key → HTTP 200 {"status":"error","short_message":"error_missing_parameters","detail_message":"key"}; unknown key → error_invalid_parameters / "key" (verified against the live API).
Latency, quota, plan
Latency delays every API response. Quota: leave empty for unlimited (-1); a number decrements per successful scoring call and 0 answers error_out_of_quota. Plan sets audio limits (15 s/1.9 MB · 45 s/2.5 MB · 120 s/3.8 MB) and whether score/speech, score/task and score/writing are available (premium only).
Forced failure
Every API call answers a documented error body until cleared. HTTP status only (429 → error_too_many_requests, 500/502/503/504 → error_internal, 403 → error_feature_unavailable, 401/402/400 → error_invalid_parameters/key) or an explicit short_message (answered with HTTP 200, like the real service).
Scoring rules
Runtime rules (kept across restarts, wiped by reset) come before config rules; first match wins; no match → deterministic default. Rule JSON: {"match":{"text":{"contains":"cat"},"endpoint":"text"},"level":"poor","scores":{"pronunciation":55},"words":[{"word":"cat","score":30}]}.
Recent scorings
Last 50 API calls: endpoint, text, audio fingerprint, level, matched rule and outcome.