Skip to main content
A job represents one humanization request. When you submit text to POST /humanize, Wibble reserves the required API words, creates a job, and returns it with status queued. The job moves through its lifecycle in the background, and you read the result once it finishes.

The async model

Humanization takes time. Rewriting text well is not instant, and the work runs on Wibble’s infrastructure rather than in the request that submitted it. Instead of holding the HTTP connection open until the rewrite is done, POST /humanize returns immediately with HTTP 202 and a job in status queued. Your request never blocks waiting for the engine. You learn the outcome in one of two ways:
  • Poll GET /humanize/{id} until the job reaches a terminal status.
  • Register a webhook by passing webhook_url on submit, and Wibble notifies you when the job finishes.
Polling returns the full job object. Webhooks deliver the terminal result in the same billing/result shape plus a type field, but omit transient polling fields such as current_stage and detected_language.

Statuses

A job is always in exactly one of four statuses. Two are terminal: once a job reaches succeeded or failed, it stays there and the status will not change.
StatusMeaningTerminal
queuedThe job is accepted and waiting to start.No
runningThe engine is humanizing the text.No
succeededThe job finished. The humanized text is in output.Yes
failedThe job did not finish. The reason is in error, and reserved words are refunded.Yes
When you poll or handle a webhook, branch on status. Treat any status other than succeeded and failed as “not done yet.”

current_stage is informational

While a job is running, current_stage carries a short, human-readable label describing what the engine is doing right now, such as detecting_language or refining_draft. It exists to give you something to show in a progress UI or a log line.
current_stage is not a stable enumerated contract. The set of stages can change, and labels can be added, renamed, or removed without notice. Do not branch your code on specific stage strings. Use status to decide what to do, and treat current_stage as display text only.

Polling vs webhooks

Both approaches deliver the same result state. Choose based on how your code is structured.

Polling

Best for scripts, short-lived processes, and anywhere you cannot accept an inbound HTTP request. You stay in control of timing and need no public endpoint.

Webhooks

Best for servers that can receive an HTTPS callback. You avoid repeated lookups and learn the result as soon as the job finishes.
When you poll, wait between requests. A poll interval of about 2.5 seconds balances responsiveness against your rate limit. GET requests are limited to 120 per minute per key, so polling faster than that risks 429 rate_limited responses without learning the result any sooner.
Poll a job
curl https://wibble.ai/api/v1/humanize/7b42f1d6-0a8c-4e8f-9a21-c6d9f47c2b10 \
  -H "Authorization: Bearer wib_live_..."
Webhooks and polling are not mutually exclusive. Treat a webhook as the fast path and keep polling available as a fallback in case a delivery is delayed or missed. See Webhooks for verification, delivery behavior, and retries.

The job object

Both POST /humanize and GET /humanize/{id} return the same polling job object. Webhook payloads contain the terminal job fields you need to process the result plus a type field, but do not include current_stage or detected_language.
id
string
The job identifier, for example 7b42f1d6-0a8c-4e8f-9a21-c6d9f47c2b10. Use it to retrieve the job.
status
string
One of queued, running, succeeded, or failed. succeeded and failed are terminal.
mode
string
Always humanize.
input_words
integer
The word count of the submitted text.
words_reserved
integer
API words held from your balance for this job at submission, equal to input_words.
words_charged
integer
The net words billed: reserved words minus any refund, floored at 0. A failed job is charged 0. See Words and billing.
status_url
string
The full URL to retrieve this job with GET /humanize/{id}.
current_stage
string
An informational, human-readable progress label. Not a stable enum. Display it if useful, but do not branch on it.
detected_language
string | null
The detected input language once detection has run, for example en. null before detection completes.
created_at
string
When the job was created, as an ISO 8601 timestamp.
completed_at
string | null
When the job reached a terminal status, as an ISO 8601 timestamp. null until the job finishes.
output
string
The humanized text. Present only when status is succeeded.
error
object
The failure reason, with code and message. Present only when status is failed. See Errors.
A succeeded job looks like this:
Succeeded job
{
  "id": "7b42f1d6-0a8c-4e8f-9a21-c6d9f47c2b10",
  "status": "succeeded",
  "mode": "humanize",
  "input_words": 9,
  "words_reserved": 9,
  "words_charged": 9,
  "status_url": "https://wibble.ai/api/v1/humanize/7b42f1d6-0a8c-4e8f-9a21-c6d9f47c2b10",
  "current_stage": "completed",
  "detected_language": "en",
  "created_at": "2026-06-14T12:00:00.000Z",
  "completed_at": "2026-06-14T12:00:42.000Z",
  "output": "Mitochondria are the cell's powerhouses."
}
output appears only on succeeded jobs, and error appears only on failed jobs. Read status first, then read the field that matches.

Expiry

A job that never reaches a terminal status on its own is failed after about one hour with the error code job_expired. The reserved words are refunded, so an expired job is charged 0, the same as any other failure.
Expired job
{
  "id": "7b42f1d6-0a8c-4e8f-9a21-c6d9f47c2b10",
  "status": "failed",
  "mode": "humanize",
  "input_words": 9,
  "words_reserved": 9,
  "words_charged": 0,
  "status_url": "https://wibble.ai/api/v1/humanize/7b42f1d6-0a8c-4e8f-9a21-c6d9f47c2b10",
  "current_stage": null,
  "detected_language": null,
  "created_at": "2026-06-14T12:00:00.000Z",
  "completed_at": "2026-06-14T13:00:00.000Z",
  "error": {
    "code": "job_expired",
    "message": "The job expired before completion."
  }
}
If you poll, this guarantees your loop terminates: a job you are tracking always reaches succeeded or failed.

Next steps

Retrieve a job

Reference for GET /humanize/{id}.

Webhooks

Get notified when a job finishes, and verify deliveries.

Words and billing

How words are reserved, charged, and refunded.

Errors

Error codes and how to handle them.