Setup#
The API is Pro-only and uses Bearer-token auth. Create a key from your Pro dashboard → API tab, then include it on every request:
Authorization: Bearer hmw_<your-key> Content-Type: application/json
Base URL: https://www.humanizemywriting.com. All endpoints accept and return JSON.
Rate limits
API calls share your daily Pro quota (200 humanize/day). Each /v1/humanize, /v1/detect, and bypass attempt counts as one. When exhausted, you’ll get a 429 with a Retry-After header.
Privacy
Inputs to /v1/humanize, /v1/detect, and /v1/bypass are processed in memory and discarded — never logged, never used for training. Voice profile samples (when you POST to /v1/voices) are the documented exception; they’re retained on your account. See /privacy.
Posting non-trivial inputs from curl
Shell escaping bites with multi-line prose. Two reliable patterns:
# Pattern A: prose file + jq for escaping
cat > /tmp/prose.txt <<'PROSE_END'
<paste your text here, line breaks and quotes are fine>
PROSE_END
jq -n --rawfile text /tmp/prose.txt \
'{text: $text, intensity: 4, mode: "academic"}' \
| curl -X POST https://www.humanizemywriting.com/api/v1/humanize \
-H "Authorization: Bearer hmw_..." \
-H "Content-Type: application/json" \
--data @-# Pattern B: python3 one-liner (no jq required)
python3 -c "import json, sys; print(json.dumps({
'text': open('/tmp/prose.txt').read(),
'intensity': 4
}))" | curl -X POST https://www.humanizemywriting.com/api/v1/humanize \
-H "Authorization: Bearer hmw_..." \
-H "Content-Type: application/json" \
--data @-POST /api/v1/humanize#
Rewrites text into a more natural, human-sounding version. Accepts all the dials the dashboard exposes — intensity, mode, voice, reference — in one call.
Body
| Field | Type | Default | Description |
|---|---|---|---|
text | string | — | Required. The input. |
intensity | 1–5 | 3 | How aggressively to rewrite. 5 = maximum restructuring. |
mode | string | standard | academic preserves direct quotations and in-text citations verbatim. |
voice_id | uuid | — | Apply a saved voice profile. |
reference_text | string | — | 100–2000 words. One-off style match. Wins over voice_id if both are sent. |
include_detectors | bool | false | Run the 5-detector strip on the output in the same response. |
Example
curl -X POST https://www.humanizemywriting.com/api/v1/humanize \
-H "Authorization: Bearer hmw_..." \
-H "Content-Type: application/json" \
-d '{
"text": "In today\'s rapidly evolving landscape...",
"intensity": 4,
"mode": "academic",
"include_detectors": true
}'Response
{
"original": "...",
"humanized": "...",
"diff": [{ "type": "kept"|"removed"|"added", "text": "..." }],
"word_count_in": 87,
"word_count_out": 91,
"latency_ms": 8432,
"model": "claude-sonnet-4-5",
"prompt_version": "v3",
"prompt_source": "db",
"detectors": { // only if include_detectors=true
"detectors": [
{ "id": "gptzero", "score": 0.18, "source": "live", "status": "ok", ... },
...
],
"passed": 4,
"total": 5,
"disclaimer": "..."
}
}POST /api/v1/detect#
Runs the 5-detector strip on a piece of text. Returns per-detector scores plus a passed/total summary. Max 2000 words.
curl -X POST https://www.humanizemywriting.com/api/v1/detect \
-H "Authorization: Bearer hmw_..." \
-d '{ "text": "..." }'gptzero is live when GPTZERO_API_KEY is configured on the server, plus an in-house detector. The others (Originality, Turnitin, Copyleaks) are deterministic stubs derived from the in-house score — each response’s source field discriminates live vs stub.
POST /api/v1/bypass#
The full bypass loop run server-side: humanize → detect → check against target, ramping intensity until either every detector lands at or below target_score, the output stops improving, or attempts run out.
Body
| Field | Type | Default | Description |
|---|---|---|---|
text | string | — | Required. |
target_score | 0–1 | 0.3 | All detectors must land at or below this value to "pass." |
max_attempts | 1–5 | 5 | Upper bound on iterations. |
intensity_start | 1–5 | 3 | Each attempt bumps +1, capped at 5. |
mode | string | standard | Same as humanize. |
curl -X POST https://www.humanizemywriting.com/api/v1/bypass \
-H "Authorization: Bearer hmw_..." \
-d '{ "text": "...", "target_score": 0.2, "max_attempts": 5 }'Response
{
"attempts": [
{
"number": 1, "intensity": 3, "humanized": "...",
"max_score": 0.41, "status": "miss",
"detectors": [ ... ]
},
...
],
"best": { ...the winning or lowest-score attempt... },
"target_score": 0.2,
"stopped_reason": "pass" | "ceiling" | "exhausted" | "rate_limited" | "error"
}Each attempt counts as a humanize call against your daily quota; the loop short-circuits if you hit it mid-run (status: rate_limited, partial attempts still returned).
Voices#
Voices are persistent style fingerprints. Create one with a sample of your writing, then pass its id as voice_id in humanize/bypass requests.
GET /api/v1/voices
curl https://www.humanizemywriting.com/api/v1/voices \ -H "Authorization: Bearer hmw_..."
POST /api/v1/voices
curl -X POST https://www.humanizemywriting.com/api/v1/voices \
-H "Authorization: Bearer hmw_..." \
-d '{ "name": "My thesis voice", "sample_text": "..." }'Sample must be 100–2000 words. The analyzer runs synchronously (~5–10s) and returns a status of ready or failed. Max 8 voices per user.
PATCH /api/v1/voices/{id}
Body: { "is_active": true | false }. Marking a voice active makes it the default for the dashboard’s Humanize Pro tab. API callers should pass voice_id explicitly — the active flag is UI sugar.
DELETE /api/v1/voices/{id}
Hard-deletes the voice (sample + style fingerprint).
Combination recipes#
1. Humanize with a saved voice + academic mode
{
"text": "...",
"voice_id": "uuid-from-/v1/voices",
"mode": "academic",
"intensity": 4
}2. Humanize + verify (single round-trip)
{
"text": "...",
"intensity": 4,
"include_detectors": true
}Cheaper than calling /v1/humanize then /v1/detect separately — one HTTP hop, one log line, atomic.
3. Style match by reference, one-off
{
"text": "...",
"reference_text": "<paste 100-2000 words of the style you want>"
}If you have both voice_id and reference_text, the reference wins. Use one or the other per request.
4. Loop until target, then stop
POST /api/v1/bypass
{
"text": "...",
"target_score": 0.2,
"max_attempts": 5,
"intensity_start": 3
}Use when you want guaranteed best-effort without orchestrating calls yourself.
Errors#
| Status | Meaning |
|---|---|
400 | Validation error — check the error field. |
401 | Missing, malformed, or revoked key. |
403 | Authenticated but not Pro. |
404 | Resource not found (e.g. voice_id missing). |
409 | Conflict — cap reached (e.g. 8 voices, 5 API keys). |
413 | Payload too large (detector input caps at 2000 words). |
429 | Rate-limit hit — check Retry-After. |
503 | Upstream (Anthropic) busy — try again in ~30s. |