Skip to content

Errors

Every non-2xx response has the same shape:

{
"success": false,
"error": "nothing-extracted",
"note": "the page was fetched and nothing in it looked like a body. A JavaScript-only page may answer to depth:\"deep\".",
"retryable": "after-fix"
}
fieldforpromise
erroryour codea stable slug. Match on it exactly. It does not change when we reword the explanation.
noteyoua sentence. It will change. Never branch on it.
retryableyour codewhether coming back helps, and how

Read retryable, not the status code. HTTP numbers cannot say what a caller needs to know — 404 and 422 both mean “do not send this again”, 429 and 503 both mean “do, later”, and 400 means either depending on which 400 it is. The field says it outright.

retryablewhat to do
neverthe same request will not start working. Change something other than the request, or stop.
after-fixthe request itself is fixable. Correct it and send again.
after-waitwait, then send the same request. Retry-After carries the seconds.
backofftransient on our side. Exponential backoff with jitter.

⚠️ never does not mean “forever”. credits-exhausted clears on your monthly reset — but that is not a retry, so it is not after-wait, and the reset time is in the body rather than in a header you might sleep on.

statuserrorretryablemeans
422nothing-extractedafter-fixwe fetched the page and found nothing that reads as a body. depth:"deep" may reach a rendering the cheap path cannot.
400http-404, http-403, http-410neverthe site answered, and what it answered was that number
400http-429, http-500, http-503after-waitsame thing, but the site is throttling or down — the number is the site’s, not ours
424dns-failedafter-fixthe host name did not resolve, so nothing was fetched. Check the spelling — and note that a name which only exists on a private network will never resolve from here.
424unreachableafter-waitthe host resolved but the connection never completed (refused, timed out, or TLS did not come up). Nothing was fetched.

⚠️ dns-failed and unreachable are about the site you asked for; worker-unreachable is about our own hop and is not your doing. The three sit next to each other on purpose — the one you get names which connection failed.

⚠️ The status stays 400 for every http-… stop, and that is deliberate. The number you should act on is the site’s, which is in the name; what you should do is in retryable. A page that is gone and a page that is briefly down are the same 400 and different retryable — which is the whole reason that field exists.

🚨 A stop that says the page was fetched means it was. nothing-extracted is a statement about the page’s content, never about a page we could not reach. If you get it, the bytes arrived and nothing in them read as a body. | 400 | url-required | after-fix | no url in the body | | 400 | urls-required / urls-too-many | after-fix | batch input is empty, or over the 50-URL limit | | 400 | max-pages-invalid | after-fix | max_pages is outside 1–25 | | 400 | unsupported formats: … | after-fix | a format name we never had — check the spelling | | 410 | monitoring-withdrawn | never | changeTracking, sections and /v1/monitor* are frozen. There is no substitute name; asking for another one is refused too. |

statuserrorretryablemeans
401api-key-missingafter-fixsend Authorization: Bearer mrw_…
401api-key-invalidneverthe key is unknown or revoked
402credits-exhaustedneverout of credits this month. credits_reset_at says when they return.
403monitor-limit-reachedneveryour plan’s concurrent monitor slots are full
404api-key-not-found / subscription-not-foundnevernothing on record for that key or email
404monitor-not-foundnever⚠️ the monitor does not exist, or it is not yours. We answer the same way for both on purpose — otherwise this endpoint would tell strangers which monitor IDs are real.
409plan-not-yet-for-saleneverthe plan exists and is not being sold yet. Different from an unknown plan, which is a 400 — one means come back later, the other means check the spelling.
400plan-invalidafter-fixno such plan
429daily-rate-limitafter-waityour plan’s per-day request cap. Retry-After is the seconds until the UTC reset.
429signup-throttledafter-waittoo many signups from one network today
400email-requiredafter-fixthe billing endpoint needs email
400email-invalidafter-fixthe address did not parse
statuserrorretryablemeans
4xx/5xxworker-unreachablebackoffthe extraction worker did not answer. note carries whatever it did say.

A stop never comes back as a 200 with an empty body. That shape existed and was removed: a success carrying nothing is indistinguishable from a success carrying a page, right up until your parser finds no rows.

A stop is never billed. Credits are spent on reads that returned something. This is the reason nothing-extracted is a 422 and not a 200 — the billing rule keys on the response class, so the two cannot drift apart quietly.