API Reference
Documentation
Everything you need to integrate the HumanizeThisAI API. Authentication, endpoints, error handling, rate limits, and working code examples.
Quick Start
Three steps to your first humanized output.
Get your API key
Sign up, subscribe to a plan, and generate a key from your dashboard.
Send a request
POST to /v1/humanize with your text, mode, and tone.
Handle the response
Parse the JSON response and use the humanized text.
Request
curl -X POST https://api.humanizethisai.com/v1/humanize \
-H "Authorization: Bearer htai_live_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-d '{
"text": "Artificial intelligence has revolutionized the way we interact with technology.",
"mode": "standard",
"tone": "casual"
}'Response
{
"object": "humanization",
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"humanized_text": "AI has completely changed how we deal with tech day to day.",
"input_words": 12,
"output_words": 11,
"mode": "standard",
"tone": "casual",
"language": "en",
"best_of_used": 1,
"is_custom_tone": false,
"words_charged": 12,
"words_remaining": 124988
}Authentication
All authenticated endpoints require a Bearer token in the Authorization header.
Authorization: Bearer htai_live_...Key management
- •Generation: Create API keys from your dashboard at any time. Each key starts with
htai_live_. - •Security: Keys are shown only once at creation. We store a SHA-256 hash — even we can’t recover the original. Store it securely.
- •Rotation: When you rotate a key, the old key enters a grace period (configurable) before revocation, so you can update your integrations without downtime.
- •Limits: Growth plans get 5 keys, Scale gets 15.
Endpoints
https://api.humanizethisai.com/v1/humanizeHumanize AI-generated text with a specific mode and tone. This is the primary endpoint.
Request Body
{
"text": "string (required) — The AI-generated text to humanize",
"mode": "standard | academic | enhanced | ultra | aggressive",
"tone": "casual | formal | professional | academic | creative",
"readability": "high-school | college | graduate | doctorate",
"freeze_words": ["BrandName", "TechnicalTerm"],
"best_of": 1,
"language": "en",
"stream": false
}| Field | Type | Required | Description |
|---|---|---|---|
| text | string | Yes | The AI-generated text to humanize |
| mode | string | No | Default: standard. One of: standard, academic, enhanced, ultra, aggressive |
| tone | string | No | Default: casual. One of: casual, formal, professional, academic, creative |
| readability | string | No | Writing level of the output. One of: high-school, college, graduate, doctorate. Default: college |
| freeze_words | string[] | No | Words/phrases to preserve unchanged during humanization |
| best_of | integer | No | Fan-out 1-5. Runs N generations, keeps the best. Multiplies word cost by N. Default: 1 |
| language | string | No | Output language (ISO 639-1): en, es, fr, de, it, pt, ru, zh, ja, ko, tr, ar. Default: en |
| stream | boolean | No | Enable SSE streaming. Default: false |
Billing & best_of
You are charged words_charged = input_words × multiplier. The multiplier is best_of (1–5, default 1): higher values run more parallel generations and keep the best result, at a proportionally higher word cost. Two modes set their own floor: mode: "ultra" always runs a 3-call self-audit chain, so it forces a 3× multiplier and ignores best_of;mode: "aggressive" defaults to a 3× multiplier when best_of is omitted (an explicit best_of overrides it). The multiplier applies to input_words only — output length never affects the charge. best_of above 3 requires the Business plan.
Response (200 OK)
{
"object": "humanization",
"id": "8f2a1c6e-3b4d-4f0a-9c12-7e5d8a1b2c3d",
"humanized_text": "Your humanized output...",
"input_words": 150,
"output_words": 148,
"mode": "standard",
"tone": "casual",
"language": "en",
"best_of_used": 1,
"is_custom_tone": false,
"words_charged": 150,
"words_remaining": 124850
}Streaming Response (SSE events)
event: meta
data: {"id":"8f2a1c6e-3b4d-4f0a-9c12-7e5d8a1b2c3d","mode":"standard","tone":"casual","language":"en","input_words":12}
event: chunk
data: {"text":"AI has completely "}
event: chunk
data: {"text":"changed how we "}
event: chunk
data: {"text":"deal with tech."}
event: done
data: {"object":"humanization","id":"8f2a1c6e-3b4d-4f0a-9c12-7e5d8a1b2c3d","input_words":12,"output_words":11,"words_charged":12,"words_remaining":124988,"credits_low":false,"language":"en","best_of_used":1,"is_custom_tone":false,"latency_ms":1342}
# If generation fails mid-stream, a single error event is emitted instead of done:
event: error
data: {"code":"AI_GENERATION_FAILED","message":"Failed to generate humanized text. You were not charged.","refunded":true}meta — Request metadata: id (the canonical request id, equal to the X-Request-Id header), mode, tone, language, input_words.
chunk — Partial humanized text fragment: { text }. Repeats until the output is complete.
done — Terminal success event with object, id, word counts, words_charged/words_remaining, best_of_used, is_custom_tone, and latency_ms.
error — Terminal failure event: { code, message, refunded }. refunded: true means you were not charged. Emitted instead of done.
https://api.humanizethisai.com/v1/detectAll PlansRun AI detection scoring on text. Returns AI probability, human probability, and detailed signals.
Request Body
{
"text": "string (required) — The text to run AI detection on"
}Response (200 OK)
{
"object": "detection",
"id": "c4d5e6f7-8a9b-4c0d-1e2f-3a4b5c6d7e8f",
"ai_score": 72,
"human_score": 28,
"confidence": "high",
"verdict": "likely_ai",
"label": "Likely AI",
"signals": [
{ "signal": "Low lexical variance", "severity": "high", "detail": "Repetitive phrasing across sentences" }
],
"sentences": [],
"summary": "Text shows strong markers of AI generation.",
"input_words": 150,
"words_charged": 150,
"words_remaining": 124700
}https://api.humanizethisai.com/v1/usageReturns your current plan details, usage stats, and key information.
Response (200 OK)
{
"plan": {
"key": "growth",
"name": "Growth",
"words_per_month": 1000000,
"max_words_per_request": 15000,
"requests_per_minute": 60,
"allowed_modes": ["standard", "academic", "enhanced", "ultra", "aggressive"],
"streaming_enabled": true,
"detection_enabled": true
},
"usage": {
"words_used": 42150,
"words_remaining": 957850,
"words_limit": 1000000,
"topup_words_remaining": 0,
"requests_this_period": 1203,
"period_end": "2026-05-01T00:00:00Z"
},
"stats": {
"summary": {
"total_requests": 1203,
"total_words_charged": 42150,
"total_input_words": 41000,
"total_output_words": 40200,
"avg_latency_ms": 1380,
"error_count": 4,
"success_rate": 99.67
},
"daily": [
{ "date": "2026-04-07", "requests": 47, "words_charged": 1650, "errors": 0 }
]
},
"key": {
"id": "0b9c8d7e-6f5a-4b3c-2d1e-0f9a8b7c6d5e",
"name": "Production Key",
"scopes": ["humanize", "detect", "tones"]
}
}https://api.humanizethisai.com/v1/healthHealth check endpoint. No authentication required.
Response (200 OK)
{
"status": "healthy",
"timestamp": "2026-04-07T14:30:00Z",
"version": "1.0.0"
}Custom Tonestones scopeCreate and manage reusable custom tones, then pass a tone’s UUID as the tone field on /v1/humanize. Every endpoint requires an API key with the tones (or *) scope. Write operations (POST/PUT/DELETE) are capped at 10 requests/minute. These calls never consume words — words_charged is always 0.
| Method | Path | Description |
|---|---|---|
| POST | /v1/tones | Create a custom tone |
| GET | /v1/tones | List your custom tones |
| GET | /v1/tones/:id | Fetch one tone by UUID |
| PUT | /v1/tones/:id | Update a tone (any subset of fields) |
| DELETE | /v1/tones/:id | Delete a tone |
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | 1-50 characters. Display name for the tone. |
| instructions | string | Yes | 1-500 characters. How the model should rewrite the text. |
| description | string | No | Up to 500 characters. Optional human note. |
| example | string | No | Up to 500 characters. Optional sample of the target voice. |
Create — Request
curl -X POST https://api.humanizethisai.com/v1/tones \
-H "Authorization: Bearer htai_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Newsletter voice",
"instructions": "Warm, concise, second-person. Short sentences.",
"description": "Used for our weekly digest",
"example": "Hey there — here is what you missed this week."
}'Create — Response (200 OK)
{
"object": "tone",
"id": "0b9c8d7e-6f5a-4b3c-2d1e-0f9a8b7c6d5e",
"tone": {
"id": "9d7c1b2a-4e5f-4a6b-8c9d-0e1f2a3b4c5d",
"name": "Newsletter voice",
"instructions": "Warm, concise, second-person. Short sentences.",
"description": "Used for our weekly digest",
"example": "Hey there — here is what you missed this week.",
"created_at": "2026-04-07T14:30:00Z",
"updated_at": "2026-04-07T14:30:00Z"
},
"words_charged": 0,
"words_remaining": 957850
}List — Response (200 OK)
{
"object": "list",
"id": "0b9c8d7e-6f5a-4b3c-2d1e-0f9a8b7c6d5e",
"tones": [
{
"id": "9d7c1b2a-4e5f-4a6b-8c9d-0e1f2a3b4c5d",
"name": "Newsletter voice",
"instructions": "Warm, concise, second-person. Short sentences.",
"description": "Used for our weekly digest",
"example": "Hey there — here is what you missed this week.",
"created_at": "2026-04-07T14:30:00Z",
"updated_at": "2026-04-07T14:30:00Z"
}
],
"words_charged": 0,
"words_remaining": 957850
}Delete — Response (200 OK)
{
"object": "tone",
"id": "0b9c8d7e-6f5a-4b3c-2d1e-0f9a8b7c6d5e",
"deleted": true,
"words_charged": 0,
"words_remaining": 957850
}Idempotency
/v1/humanize and /v1/detect accept an optional Idempotency-Key request header. Send the same key to safely retry a request — on a flaky network or a timeout — without being charged twice. The key also becomes the response id and the X-Request-Id header.
X-Idempotent-Replay: true and a replayed: true field. Replays are always returned as JSON, even if the original request used stream: true.409 IDEMPOTENCY_KEY_CONFLICT. Only reuse a key to retry the identical request.1-128 characters of A-Z a-z 0-9 _ - : . returns 400 INVALID_IDEMPOTENCY_KEY. It is never silently replaced.# Retry the exact same request safely — reuse the key.
curl -X POST https://api.humanizethisai.com/v1/humanize \
-H "Authorization: Bearer htai_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-4815-humanize-01" \
-d '{ "text": "Text to humanize", "mode": "standard", "tone": "casual" }'
# Reusing the key with the SAME payload replays the stored result:
HTTP/1.1 200 OK
X-Idempotent-Replay: true
X-Request-Id: order-4815-humanize-01Error Codes
Every error is an RFC 7807 application/problem+json document. Match on the code field (a stable UPPER_SNAKE string) or the full type URL — never parse the human-readabledetail. request_id equals the X-Request-Id response header. Some codes add structured extension members — INSUFFICIENT_WORDS carries words_required and words_remaining.
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
{
"type": "https://docs.humanizethis.ai/errors/insufficient-words",
"title": "Insufficient word balance",
"status": 402,
"detail": "Insufficient word balance. Need 600, have 50. This request uses mode="ultra", which multiplies word cost by 3. Purchase top-ups or upgrade your plan.",
"instance": "/v1/humanize",
"code": "INSUFFICIENT_WORDS",
"request_id": "8f2a1c6e-3b4d-4f0a-9c12-7e5d8a1b2c3d",
"words_required": 600,
"words_remaining": 50
}| Code | HTTP | Description |
|---|---|---|
| MISSING_API_KEY | 401 | No Authorization header provided |
| INVALID_API_KEY_FORMAT | 401 | Key doesn't start with htai_live_ |
| INVALID_KEY | 401 | Key not found or has been revoked |
| KEY_EXPIRED | 401 | Key has expired (rotated) |
| NO_ACTIVE_SUBSCRIPTION | 403 | No active API plan on the account |
| SCOPE_DENIED | 403 | Key doesn't have the required scope for this operation |
| MODE_NOT_AVAILABLE | 403 | Requested mode not included in current plan |
| ENDPOINT_NOT_AVAILABLE | 403 | Endpoint not included in current plan |
| STREAMING_NOT_AVAILABLE | 403 | SSE streaming not included in current plan |
| DETECTION_NOT_AVAILABLE | 403 | AI detection not included in current plan |
| IP_NOT_ALLOWED | 403 | Request IP not in key's allowlist |
| RATE_LIMITED | 429 | Rate limit exceeded — slow down and retry |
| MISSING_TEXT | 400 | No text field in request body |
| INVALID_TEXT | 400 | Text failed validation (empty or invalid characters) |
| INVALID_JSON | 400 | Request body is not valid JSON |
| TEXT_TOO_LONG | 400 | Text exceeds plan's maximum words per request |
| INVALID_MODE | 400 | Unknown humanization mode |
| INVALID_TONE | 400 | Unknown tone preset |
| INVALID_BEST_OF | 400 | best_of is not an integer between 1 and 5 |
| BEST_OF_NOT_AVAILABLE | 403 | best_of above 3 requires the Business plan |
| LEGACY_PROMPT_REMOVED | 400 | Legacy "prompt" field is no longer supported — use "text" |
| INVALID_IDEMPOTENCY_KEY | 400 | Idempotency-Key header is malformed (must be 1-128 chars of A-Z a-z 0-9 _ - : .) |
| IDEMPOTENCY_KEY_CONFLICT | 409 | Idempotency-Key was already used for a different request payload |
| INSUFFICIENT_WORDS | 402 | Not enough word balance — carries words_required and words_remaining |
| TONE_NOT_FOUND | 404 | Referenced custom tone does not exist |
| AI_GENERATION_FAILED | 500 | AI processing failed — not charged |
| DETECTION_FAILED | 500 | Detection processing failed — not charged |
Rate Limits
Every API response includes rate limit headers so you can build adaptive throttling into your client.
| Plan | Requests / min | Concurrent | Keys |
|---|---|---|---|
| Growth | 60 | 10 | 5 |
| Scale | 200 | 30 | 15 |
Response headers
X-RateLimit-LimitYour plan's maximum requests per minute.X-RateLimit-RemainingRequests remaining in the current 60-second window.X-RateLimit-ResetSeconds until the current window resets (a delta, not a Unix timestamp). 0 while you are within the limit.Retry-AfterSeconds to wait before retrying. Present only on 429 responses.# Example rate-limited response
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 30
Retry-After: 30
{
"type": "https://docs.humanizethis.ai/errors/rate-limited",
"title": "Rate limit exceeded",
"status": 429,
"detail": "Rate limit exceeded. Slow down.",
"instance": "/v1/humanize",
"code": "RATE_LIMITED",
"request_id": "8f2a1c6e-3b4d-4f0a-9c12-7e5d8a1b2c3d"
}Code Examples
Complete, runnable examples with authentication and error handling.
curl -X POST https://api.humanizethisai.com/v1/humanize \
-H "Authorization: Bearer htai_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"text": "AI-generated text to humanize",
"mode": "standard",
"tone": "casual",
"freeze_words": ["HumanizeThisAI", "GPTZero"],
"best_of": 1,
"language": "en",
"stream": false
}'