One draft, one run.
A run is asynchronous. Creating it reserves money and queues the work. You read the rewrite from the run when it finishes.
/v1/runs
Creates a run and returns 202 Accepted. Limited to 6 requests per minute per key. A 429 includes a Retry-After header.
{
"text": "Your draft, in plain text or Markdown.",
"quality": "standard",
"options": {
"persona": "freelance journalist filing a feature",
"tone": "warm and plain-spoken",
"formality": 2,
"typos_enabled": true,
"typos_per_100_words": 1.0,
"common_words_enabled": true,
"min_zipf": 4.0
}
}
| Field | |
|---|---|
text | Required. Longer than 5,000 characters returns 400 text_too_long. Text with no prose words returns 400. |
quality | low, standard, or high. An unknown name is 400. |
options | Optional. See below. Omit it to let each run pick a voice. |
{
"id": "run_01J9ABCDEF",
"status": "queued",
"quality": "standard",
"word_count": 11,
"prose_word_count": 11,
"estimated_cost_usd": "0.050000",
"held_usd": "0.050000",
"is_estimate": true,
"events_url": "/api/v1/runs/run_01J9ABCDEF/events"
}
held_usd is reserved until the run settles. estimated_cost_usd is not the price. The amount you pay is billing.charged_usd on the finished run. If the available balance cannot cover the hold, the response is 402 and nothing is queued.
Options
Leave a voice field out and that run samples one. Two runs of the same text will not necessarily sound the same. GET /v1/presets returns the lists the sampler draws from.
| Field | |
|---|---|
persona | Who is writing. A concrete description works better than a label like “professional”. |
tone | How it should sound. |
formality | Integer from 1 (conversational) to 5 (formal). |
typos_enabled | Defaults to true. Short drafts often get none, because a single slip in a short paragraph reads as a mistake. |
typos_per_100_words | Rate used when typos are on. The default in the app is 1.0. |
common_words_enabled | Prefer everyday wording. Defaults to true. |
min_zipf | How common a replacement word should be. The app default is 4.0. |
random_plan | When true, voice options in the same object are ignored and the whole plan is sampled. |
Statuses
| Status | |
|---|---|
queued | Accepted, not started. |
running | In progress. The hold is still reserved. |
succeeded | Rewrite is in output_text. |
rejected | Finished, and our checks did not pass. You are still charged for the work. Read scores.reasons. |
failed | The run stopped on an error. You are charged for work already done. |
canceled | You canceled it. Unused hold is released. Work already done is charged. |
/v1/runs/{id}
The run, including both texts. A run that belongs to someone else is 404.
{
"id": "run_01J9ABCDEF",
"status": "succeeded",
"quality": "standard",
"prose_word_count": 11,
"input_text": "Artificial intelligence has fundamentally transformed the landscape of modern software development.",
"output_text": "Artificial intelligence has changed modern software development.",
"text_deleted_at": null,
"scores": {
"validation_passed": true,
"reasons": []
},
"billing": {
"charged_usd": "0.050000",
"estimated_cost_usd": "0.050000",
"held_usd": "0.050000",
"charge_exceeded_hold": false
},
"created_at": "2026-10-05T18:00:00+00:00",
"finished_at": "2026-10-05T18:00:40+00:00"
}
charge_exceeded_hold is true when the final charge was higher than the amount reserved up front. scores.validation_passed is the check result. A few extra fields may be present; you do not need them to read the rewrite or the charge.
/v1/runs
Your runs, newest first. limit defaults to 50 and caps at 100. List items omit input_text and output_text and include input_preview, the first 160 characters of the draft.
{ "data": [ /* run objects */ ], "next_cursor": null }
/v1/runs/{id}/cancel
Cancels a queued or running run and returns the run. Canceling a finished run returns it unchanged.
/v1/runs/{id}
Erases the draft and the rewrite. The billing record stays, so the charge still appears in the ledger. Cancel an in-progress run first; otherwise the response is 409 run_in_progress.
{ "id": "run_01J9ABCDEF", "text_deleted": true, "deleted_at": "2026-10-05T19:00:00+00:00" }
/v1/runs?confirm=true
Erases the text of every finished run. Without confirm=true the response is 400 confirmation_required. Runs that are still queued or running are skipped.
{ "deleted": 12, "skipped_in_progress": 0 }