JSON over HTTPS. No key while in testing; 10 rewrites a day per address. Scoring is unlimited and also runs entirely client-side if you load /lib.js and /model.json. Send a real User-Agent header naming your client; default library agents such as Python-urllib are blocked at the edge.
{"text":"..."}
โ {"score":73.2,"contributions":[{"key":"comma_per_sent","contribution":1.21,"value":2.4},...],
"spans":[{"kind":"tricolon","why":"three-item list (A, B, and C)","start":118,"end":160,"text":"..."}],
"rhythm":{"n_sent":9,"lengths":[...],"cv":0.31,"short_lt8":0}}
{"name":"Jeremiah","samples":["...","...","..."]} // 3+ samples of 40+ words each
โ {"id":"p_...","name":"Jeremiah","n":3,"stats":{...}}
{"text":"...","voice":"email"|"explainer"|"<profile id>","rounds":2,"candidates":3} // max 3 and 3
โ {"score_before":85.2,"score_after":5.0,"final":"...","brief":["- ..."],
"fidelity":{"ok":true,"invented_numbers":[],"invented_names":[],"dropped_numbers":[],"content_overlap":0.74},"model":"...","ms":41000}
If no candidate passes the fidelity gate, final is your original text and fidelity is null. That is deliberate.