Skip to main content

POST /api/humanize

The rewrite engine. Every client — the web app, the extension, curl — calls this one endpoint. Anthropic keys stay on the server; you never hold one.

Drafts are not stored.

Auth

Either:

  • a session cookie, for same-origin browser calls, or
  • Authorization: Bearer hn_..., for everything else.

A Bearer header that is not a valid key returns 401. It does not fall through to the anonymous allowance.

Create keys at rewr.it/account while signed in. The secret is shown once. Up to 5 active keys. Quota follows the key's owner.

Request

{
"text": "It is important to note that we should leverage this.",
"register": "email",
"mode": "rewrite",
"templateId": null,
"voiceProfileId": null,
"fromNotes": false,
"previousRewrite": "",
"protectedSpans": [],
"modelTier": "standard"
}
FieldRequiredValues
textyesThe draft, or the notes when fromNotes is true
registeryesslack | email | skip_level | linkedin
modenorewrite (default) | expand | vary | closer
templateIdnoA custom template you own. Pro. Unresolvable ids fall back to register
voiceProfileIdnoA voice profile you own. Unresolvable ids fall back to the default voice
fromNotesnotext is bullet notes, not a draft. Implied by mode: "expand"
previousRewritefor vary / closerThe prior rewrite. Not a source of new facts
protectedSpansnoExact substrings to keep verbatim. Max 20, 4,000 characters
modelTiernostandard | fast | auto. Plan-gated
fromNotes on a retry

vary and closer describe what to do with the previous output and say nothing about the input. Retrying an expansion must carry fromNotes: true, or the server reads your notes as a draft.

Response

Content-Type: text/event-stream.

data: {"type":"delta","text":"We should "}
data: {"type":"delta","text":"look at this properly."}
data: {"type":"usage","plan":"pro","modelTier":"standard","inputTokens":12,"outputTokens":40,"requests":3,"fundingSource":"wallet","creditsUsed":2,"creditBalance":10998}
data: {"type":"done"}

Concatenate every delta.text. A trailing NOTES: block, if present, is the model's commentary — split it off before showing the rewrite.

An error inside a stream that has already started arrives as an event:

data: {"type":"error","message":"Rewrite failed. Try again."}

An error before the stream starts is a JSON body with an HTTP status. See Errors.

Do not log the draft

The endpoint does not, and neither should your client. That is most of the privacy promise, and it is the one part of it that lives in your code rather than in ours.

CORS

Browser and extension callers send an Origin. Allowed:

  • NEXT_PUBLIC_APP_URL
  • chrome-extension://<id> for each id in HUMANIZER_EXTENSION_IDS
  • anything in HUMANIZER_CORS_ORIGINS
  • on loopback (localhost, 127.0.0.1, ::1), any chrome-extension://<id>, so an unpacked build works against next dev without configuring env

OPTIONS is implemented on /api/humanize and /api/usage. Production requires ids in HUMANIZER_EXTENSION_IDS.

curl

curl -N https://rewr.it/api/humanize \
-H "Authorization: Bearer hn_..." \
-H "Content-Type: application/json" \
-d '{"text":"It is important to note that we should leverage this.","register":"email"}'

-N matters. Without it curl buffers and the stream looks like it hangs.