POST that Wibble sends to a URL you control when a humanization job reaches a terminal state. Instead of polling GET /humanize/{id}, you give Wibble a URL up front and it notifies you once the job succeeds or fails. The request body contains the terminal job result plus a type field that names the event.
Webhooks are a convenience, not a guarantee. Network failures and downtime happen, so keep polling available as a fallback. See Jobs for the lifecycle and the polling flow.
Enable webhooks
Pass awebhook_url when you submit a job. Wibble sends a signed POST to that URL when the job finishes.
webhook_url must:
- Use
https. - Be publicly reachable from the internet.
- Contain no embedded credentials (no
user:pass@in the URL). - Not resolve to a private or loopback address.
- Be 2048 characters or fewer.
400 validation_error. See Errors for the response shape.
Events
There are two events. Both deliver the same payload shape: job identifiers, billing fields,status_url, timestamps, and either output or error, with a type field added. Webhooks do not include polling-only progress fields such as current_stage or detected_language.
| Event | Sent when | Notable fields |
|---|---|---|
humanize.job.succeeded | The job completes and status is succeeded. | output holds the humanized text. |
humanize.job.failed | The job ends and status is failed. Reserved words are refunded before the event is sent. | error holds the code and message. words_charged is 0. |
humanize.job.succeeded payload:
humanize.job.succeeded
Job succeeded
The payload Wibble sends when a job succeeds.
Job failed
The payload Wibble sends when a job fails.
Delivery headers
Every delivery carries four headers.| Header | Meaning |
|---|---|
X-Wibble-Delivery | Unique delivery ID (UUID). Stable across retries of the same event, so you can deduplicate. |
X-Wibble-Event | The event type, matching the payload type field (humanize.job.succeeded or humanize.job.failed). |
X-Wibble-Signature | HMAC-SHA256 signature of the request, of the form sha256=<hex>. |
X-Wibble-Timestamp | Unix timestamp in seconds at which the request was signed. Recomputed on each retry. |
Verify the signature
Anyone who learns yourwebhook_url could POST to it. Verify the signature before you trust a delivery.
Wibble signs each request with the API key’s webhook signing secret. The secret is shown once when the key is created and has the format whsec_.... Store it where your webhook handler can read it.
To verify a delivery, recompute the signature and compare it to the header:
- Read the raw request body as it arrived, before any JSON parsing. Parsing and re-serializing changes the bytes and breaks the signature.
- Build the signed string
"{X-Wibble-Timestamp}.{raw body}"using the timestamp from theX-Wibble-Timestampheader on this request. - Compute the HMAC-SHA256 of that string with your
whsec_...secret and hex-encode it. - Compare your value to the hex after
sha256=inX-Wibble-Signatureusing a constant-time comparison.
Protect against replays
A valid request that is captured and resent later still carries a valid signature. UseX-Wibble-Timestamp to bound how old a delivery you accept.
After the signature checks out, compare the timestamp to the current time and reject deliveries outside a tolerance window, such as five minutes. Account for retries: a genuine delivery may arrive a few seconds after the first attempt, each with its own fresh timestamp.
Node.js
Delivery semantics
| Behavior | Detail |
|---|---|
| Attempts | Up to 3 per event. |
| Backoff | Exponential between attempts. |
| Timeout | 5,000 ms per attempt. |
| Acknowledgment | Any 2xx response. Non-2xx (or a timeout) is retried until the attempt limit is reached. |
| Delivery ID | X-Wibble-Delivery is stable across retries of the same event. The timestamp and signature change per attempt. |
GET /humanize/{id} to recover the result.
Best practices
Verify before you trust
Verify before you trust
Confirm the signature on every delivery before reading the payload or doing any work. Reject requests that fail verification or fall outside your timestamp tolerance.
Respond fast
Respond fast
Return a
2xx quickly, within the 5,000 ms timeout. Acknowledge first, then do slower work (database writes, downstream calls) asynchronously. Holding the connection open risks a timeout and an unnecessary retry.Handle deliveries idempotently
Handle deliveries idempotently
The same event can arrive more than once. Treat
X-Wibble-Delivery (or the job id plus type) as a key and ignore deliveries you have already processed.Keep polling as a fallback
Keep polling as a fallback
If a webhook never arrives, fall back to polling
GET /humanize/{id}. Webhooks reduce polling; they do not replace your ability to read a job’s final state.Next steps
Jobs
The job object, statuses, and polling versus webhooks.
Quickstart
Go from an API key to your first humanized result.