# Fouten, robots.txt-weigeringen en retries

> WebReaderAPI-foutcodes: weigering door robots.txt of de site, time-outs en creditfouten, welke je opnieuw probeert en waarom niets wordt gefactureerd.

- URL: https://webreaderapi.com/nl/docs/errors/
- Laatst bijgewerkt: 2026-10-22
- Uitgever: WebReaderAPI (https://webreaderapi.com)

Elke fout heeft een HTTP-status, een stabiele `code` en een leesbare `message`. Geen enkele gebruikt een credit. Sommige zijn een retry waard; de weigeringen die van een site komen zijn definitief, en we werken ze nooit omzeilend rond.

**Kort antwoord — Wat betekenen WebReaderAPI-foutcodes, en welke moet ik opnieuw proberen?**

**WebReaderAPI**-fouten komen in drie groepen, en geen enkele wordt ooit gefactureerd. Problemen met het request (`invalid_url`, `invalid_api_key`, `insufficient_credits`) vragen een oplossing aan jouw kant. Beslissingen van de site (`blocked_by_robots`, `blocked_by_site_policy`, `target_refused`) zijn definitief. Tijdelijke fouten (`fetch_failed`, `fetch_timeout`, `concurrency_limit`) kun je opnieuw proberen met backoff. Credits beginnen bij US$ 0,07/1K pagina's, betaald met crypto zonder KYC.

## Welke foutcodes kan de API retourneren?

De body is altijd `{"error": {"code", "message"}}`, plus `target_status` wanneer de weigering van de site kwam.

| HTTP | `code` | Oorzaak | Opnieuw proberen? |
| --- | --- | --- | --- |
| 400 | `invalid_url` | Geen http of https, te lang, of een privé-, lokaal of cloud-metadata-adres | Nee: herstel de URL |
| 400 | `invalid_parameter` | Een parameter heeft een waarde buiten de lijst of het bereik | Nee: herstel de request |
| 401 | `invalid_api_key` | API-sleutel ontbreekt, is onjuist of ingetrokken | Nee: controleer de API-sleutel |
| 402 | `insufficient_credits` | Je saldo heeft geen credits meer | Na aankoop van een pack |
| 403 | `blocked_by_robots` | De robots.txt van de site staat de pagina niet toe voor WebReaderAPI of voor alle robots | Nee: definitief |
| 403 | `blocked_by_site_policy` | De site verklaart `Content-Signal: ai-input=no` | Nee: definitief |
| 422 | `unsupported_content` | Een type dat we niet lezen (video, archief) of een te groot bestand | Nee |
| 429 | `concurrency_limit` | Te veel van je requests draaien tegelijkertijd | Ja, met backoff |
| 502 | `target_refused` | De site weigerde: 403, 429, een challenge-pagina of een loginmuur; de status staat in `target_status` | Nee: definitief |
| 502 | `fetch_failed` | DNS-, TLS- of verbindingsfout, of de site antwoordde 404 of 410 | Eén of twee keer, met backoff |
| 504 | `fetch_timeout` | De site antwoordde niet binnen `timeout` | Ja, met backoff of een langere timeout |

## Waarom zijn robots.txt en weigeringen van de site definitief?

Omdat ze de beslissing van de site-eigenaar zijn, en WebReaderAPI is gebouwd om die te volgen. We respecteren robots.txt: onze crawler identificeert zich als WebReaderAPI, volgt de regels die voor hem of voor alle robots zijn geschreven, en leest geen pagina die een site niet toestaat. Geweigerde pagina's worden niet in rekening gebracht. Als een site Content-Signal: ai-input=no in zijn robots.txt aangeeft, lezen we de pagina's niet voor je.

Wanneer een site een request op een andere manier afwijst, met een 403, een 429, een challenge-pagina of een loginformulier, krijg je `target_refused` en de eigen status van de site in `target_status`. Als een site ons verzoek weigert, geven we het antwoord terug: we lossen nooit CAPTCHA's op, loggen niet in op accounts en proberen nooit een blokkade of paywall te omzeilen. Dezelfde URL een minuut later opnieuw proberen geeft meestal hetzelfde antwoord, dus behandel deze codes als een resultaat, niet als een fout: log ze en ga verder.

## Hoe controleer ik waarom een pagina is geweigerd?

Open de `/robots.txt` van de site en zoek naar een groep die `WebReaderAPI` noemt, of de groep `*` die voor alle robots geldt. Een `Disallow`-regel die overeenkomt met het pad verklaart een `blocked_by_robots`. Een regel zoals `Content-Signal: ai-input=no` verklaart een `blocked_by_site_policy`.

We bewaren een kopie van elke robots.txt maximaal 24 uur. Als een site net een sectie heeft opengesteld voor robots, kan de wijziging tot een dag duren voordat die van kracht is. Site-eigenaren kunnen lezen hoe onze crawler zich gedraagt en hoe je die toestaat of blokkeert, op [onze crawler-pagina](https://webreaderapi.com/nl/bot/).

## Hoe moet ik tijdelijke fouten opnieuw proberen?

Probeer alleen `concurrency_limit`, `fetch_timeout` en, één of twee keer, `fetch_failed` opnieuw. Wacht voor elke nieuwe poging en verdubbel de wachttijd elke keer, met een beetje willekeurige jitter zodat parallelle workers niet tegelijk opnieuw proberen. Stop na 4 of 5 pogingen.

Voor `concurrency_limit` is de betere oplossing minder requests tegelijk te sturen: Elk account heeft een limiet voor het aantal pagina's dat het tegelijk leest; je dashboard toont die, en support kan hem verhogen. Voor `fetch_timeout` verhoog je `timeout` tot 60 seconden voordat je een langzame site opnieuw probeert. Opnieuw proberen kost niets, want een mislukte poging wordt nooit gefactureerd.

*Python: probeer alleen de fouten opnieuw die kunnen veranderen*

```python
import os
import random
import time

import requests

API = "https://webreaderapi.com/api/v1/read"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}
RETRY = {"concurrency_limit", "fetch_timeout", "fetch_failed"}
FINAL = {"blocked_by_robots", "blocked_by_site_policy", "target_refused", "unsupported_content"}


def read_page(url, attempts=5, **options):
    wait = 1.0
    for attempt in range(1, attempts + 1):
        resp = requests.get(API, headers=HEADERS, params={"url": url, **options}, timeout=75)
        if resp.status_code == 200:
            return resp.json()
        error = resp.json().get("error", {})
        code = error.get("code", "unknown")
        if code in FINAL:
            return {"url": url, "skipped": code, "target_status": error.get("target_status")}
        if code not in RETRY or attempt == attempts or (code == "fetch_failed" and attempt >= 3):
            raise RuntimeError(f"{code}: {error.get('message')}")
        time.sleep(wait + random.uniform(0, wait / 2))
        wait = min(wait * 2, 30)
    raise RuntimeError("unreachable")


if __name__ == "__main__":
    print(read_page("https://example.com/blog/first-post", max_chars=20000).get("title"))

```

*Node.js: dezelfde regel met exponentiële backoff*

```javascript
const RETRY = new Set(['concurrency_limit', 'fetch_timeout', 'fetch_failed']);
const FINAL = new Set(['blocked_by_robots', 'blocked_by_site_policy', 'target_refused', 'unsupported_content']);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function readPage(url, options = {}, attempts = 5) {
  let wait = 1000;
  for (let attempt = 1; attempt <= attempts; attempt++) {
    const params = new URLSearchParams({ url, ...options });
    const res = await fetch(`https://webreaderapi.com/api/v1/read?${params}`, {
      headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
    });
    const body = await res.json();
    if (res.ok) return body;
    const code = body.error?.code ?? 'unknown';
    if (FINAL.has(code)) return { url, skipped: code, target_status: body.error.target_status };
    if (!RETRY.has(code) || attempt === attempts) throw new Error(`${code}: ${body.error?.message}`);
    await sleep(wait + Math.random() * (wait / 2));
    wait = Math.min(wait * 2, 30000);
  }
}

```

## Hoe zit het met fouten binnen een batch of crawl?

Een job stopt niet omdat één pagina mislukt. Die pagina verschijnt in `results` als `{url, error}` met dezelfde codes als hierboven, en kost niets. Een crawl die `blocked_by_robots` tegenkomt op een sectie leest gewoon de rest van de site.

Tel aan het einde van een job de foutcodes. Veel `target_refused` op één site betekent dat de site geen geautomatiseerde lezers accepteert; veel `fetch_timeout` betekent dat het traag is, en een langere `timeout` in de job-opties kan helpen.

## Fouten: veelgestelde vragen

### Wordt er iets in rekening gebracht voor een pagina die robots.txt blokkeert?

Nee. 1 credit = 1 pagina lezen zonder browser; 2 credits wanneer de pagina een browser nodig heeft om JavaScript te renderen. Een verzoek dat mislukt, of dat de robots.txt van een site weigert, wordt niet in rekening gebracht. Hetzelfde geldt voor elke andere fout op deze pagina.

### Kunnen jullie een pagina lezen die je crawler blokkeert als ik dat vraag?

Nee. We volgen de keuze van de site-eigenaar, en het beleid is hetzelfde voor elke klant. Als je de site bezit, voeg dan een regel voor `WebReaderAPI` toe in je robots.txt; de [crawler-pagina](https://webreaderapi.com/nl/bot/) laat zien hoe.

### Waarom krijg ik fetch_failed voor een pagina die bestaat?

De site was mogelijk down, traag met het accepteren van een TLS-verbinding of gaf 404 terug aan geautomatiseerde clients. Probeer het een of twee keer opnieuw met backoff. Als het blijft mislukken, controleer dan het adres in een browser.

### Wat moet mijn agent de gebruiker vertellen na een weigering?

Iets simpels, zoals dat de site geautomatiseerd lezen van die pagina niet toestaat. Laat het model dan andere bronnen gebruiken. De foutcode teruggeven als tool-resultaat is voor de meeste modellen genoeg.

---

WebReaderAPI: WebReaderAPI is een web reader-API voor AI-agents die elke openbare webpagina omzet in schone Markdown, betaald met crypto zonder ID te uploaden. Prepaid credits vanaf US$ 0,07/1K pagina's verlopen nooit, en robots.txt wordt gerespecteerd. Zonder KYC — geen ID, geen selfie, geen documenten. Betalen met crypto.
