Problèmes courants

Solutions aux problèmes les plus courants lors de l'utilisation de l'API FourA.

Contenu vide ou incomplet

Symptôme : L'API renvoie un statut 200, mais le champ data est vide ou le contenu attendu est manquant.

Cause : La page cible utilise JavaScript pour afficher le contenu après le chargement initial de la page.

Solution : Passez du endpoint unique au endpoint du navigateur. Utilisez checkText pour vérifier le contenu chargé :

curl -X POST https://eu.api.foura.ai/api/browser/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/products",
    "timeout_ms": 15000,
    "checkText": "product-list"
  }'

Remarque : le endpoint du navigateur retourne le contenu dans le champ body (et non data).

403 Forbidden ou pages CAPTCHA

Symptôme : L'API retourne du HTML contenant un défi CAPTCHA ou une page d'accès refusé.

Cause : Le site cible a détecté la request comme automatisée et l'a bloquée.

Solution : Utilisez le endpoint proxy pour une rotation automatique des adresses IP :

curl -X POST https://eu.api.foura.ai/api/proxy/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "maxTries": 5,
    "request": {
      "method": "GET",
      "url": "https://example.com/prices",
      "unblocker": true
    }
  }'

Si le problème persiste, augmentez maxTries pour donner plus de tentatives à la rotation de proxy.

Erreurs de timeout

Symptôme : Les requêtes échouent avec une erreur de timeout.

Cause : La page cible met plus de temps à se charger que le timeout configuré.

Solution : Augmentez timeout_ms (la valeur par défaut est de 15s pour simple, 30s pour navigateur, 45s pour proxy) :

curl -X POST https://eu.api.foura.ai/api/browser/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://slow-site.com",
    "timeout_ms": 60000
  }'

Pour les requêtes de navigateur, vérifiez également que votre valeur checkText apparaît bien sur la page. Une faute de frappe provoquera toujours un délai d'attente.

429 Too Many Requests (Limite RPM)

Symptôme : L'API renvoie le statut 429 avec un message "rate limit exceeded".

Cause : Vous avez dépassé votre limite de requêtes par minute (RPM). Cela est différent des limites de simultanéité (voir 503 ci-dessous).

Solution : Utilisez le champ retryAfter de la réponse pour attendre le temps nécessaire avant de réessayer :

import time
import requests

def make_request(endpoint_url, payload, retries=3):
    for i in range(retries):
        resp = requests.post(
            endpoint_url,
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json=payload
        )
        if resp.status_code == 429:
            body = resp.json()
            wait = body.get("retryAfter", 2 ** i)
            time.sleep(wait)
            continue
        return resp
    raise Exception("Rate limit not resolved after retries")

# Example: single request
make_request(
    "https://eu.api.foura.ai/api/single/",
    {"method": "GET", "url": "https://example.com"}
)

Vérifiez votre utilisation actuelle dans le Tableau de bord pour voir vos rate limits.

503 Service Unavailable

Symptôme : L'API retourne le statut 503.

Cause : Cela se produit dans deux cas :

  1. Limite de concurrence atteinte. Vous avez trop de requests simultanées en cours d'exécution. Cela est différent du statut 429, qui limite les requests par minute. Avec le statut 503, vous n'avez pas dépassé votre RPM, mais vous avez atteint le nombre maximum de requests pouvant s'exécuter en même temps.
  2. Service temporairement désactivé. Une fenêtre de maintenance est en cours.

Les deux cas incluent un champ retryAfter dans la response.

Solution : Attendez retryAfter secondes, puis réessayez :

import time
import requests

def make_request_with_retry(endpoint_url, payload, retries=3):
    for i in range(retries):
        resp = requests.post(
            endpoint_url,
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json=payload
        )
        if resp.status_code in (429, 503):
            body = resp.json()
            wait = body.get("retryAfter", 2 ** i)
            time.sleep(wait)
            continue
        return resp
    raise Exception("Request not resolved after retries")

Si vous atteignez régulièrement les limites de concurrence 503, réduisez le nombre de requêtes parallèles dans votre pipeline de scraping, ou vérifiez la limite de concurrence de votre forfait dans le tableau de bord.

504 Upstream Timeout

Symptôme : L'API renvoie 504 avec {"error": "Upstream timeout"}.

Cause : Le travail ne s'est pas terminé dans le budget de temps que vous avez déclaré pour la request. Une cible lente, la résolution d'un challenge à froid ou une très grande page peuvent en être la cause. Ce n'est pas un problème avec votre clé, vos paramètres ou votre proxy.

Solution : Donnez plus de temps à l'appel ou réessayez. FourA attend votre timeout_ms plus une petite marge, donc l'augmenter allonge véritablement l'attente :

{
  "url": "https://slow-site.com/report",
  "timeout_ms": 90000
}

Pour un /api/auto/ sur une cible protégée, un premier appel à froid peut prendre des dizaines de secondes. Son timeout_ms couvre toute l'échelle et accepte jusqu'à 180000.

502 Upstream indisponible

Symptôme : L'API renvoie 502 avec {"error": "Upstream unavailable"}, ou 503 avec {"error": "Backend service unavailable"}.

Cause : FourA a atteint son propre moteur mais n'a pas pu utiliser la réponse, généralement parce qu'une instance redémarrait.

Solution : Réessayez avec un court délai d'attente. Les deux sont classés comme service_error, et seul success est facturé, donc une nouvelle tentative ne vous coûte rien de plus. Si cela dure plus d'une minute ou deux, vérifiez la page d'état.

401 Erreurs d'authentification

Symptôme : Chaque requête renvoie 401 Unauthorized.

Liste de vérification :

  1. Vérifiez que le header est X-API-Key: YOUR_API_KEY (et non Authorization: Bearer ou Api-Key)
  2. Vérifiez la présence d'espaces ou de sauts de ligne supplémentaires dans votre clé API
  3. Créez une nouvelle clé depuis le Tableau de bord si la clé actuelle pourrait être compromise

400 La cible se résout en une IP privée/réservée

Symptôme : L'API renvoie 400 avec Target <ip> resolves to a private/reserved IP avant que la requête ne quitte FourA.

Cause : Votre url se résout en une plage d'IP privée, de boucle locale (loopback) ou réservée (RFC 5735, RFC 6598 ou blocs réservés IPv6). FourA refuse ces cibles afin que son réseau ne puisse pas être utilisé pour atteindre des hôtes internes.

Solution : Récupérez une URL publique. Si vous effectuez des tests, utilisez une cible publique comme https://example.com ou https://httpbin.org/get. Si votre cible prévue est un service que vous exécutez, exposez-la d'abord sur un nom d'hôte public.

{ "error": "Target <ip> resolves to a private/reserved IP" }

no_eligible_proxy lors de l'utilisation de exitCountries

Symptôme : Un appel /api/proxy/ avec exitCountries renvoie HTTP 200 avec une enveloppe d'erreur JSON :

{
  "error": "No eligible proxy found for exit countries: CZ, GB",
  "code": "no_eligible_proxy",
  "details": { "exitCountries": ["CZ", "GB"] },
  "total": 0.084
}

Cause : Le pool de proxy actuel n'a aucune sortie fonctionnelle dont le pays visible par la cible correspond à votre liste d'autorisation. FourA ne se rabat jamais sur un pays non demandé lorsque vous définissez exitCountries.

Solution : Conservez la portée demandée et réessayez plus tard. Le pool est actualisé environ toutes les dix minutes, de sorte qu'un pays qui n'a aucune correspondance maintenant en obtient souvent une dans l'heure.

import time, requests

def fetch_scoped(url, countries, max_attempts=6, wait_sec=600):
    for _ in range(max_attempts):
        r = requests.post("https://eu.api.foura.ai/api/proxy/",
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json={"maxTries": 5, "exitCountries": countries,
                  "request": {"method": "GET", "url": url}}).json()
        if r.get("code") == "no_eligible_proxy":
            time.sleep(wait_sec)
            continue
        return r
    raise RuntimeError(f"no eligible exit in {countries} after {max_attempts} attempts")

N'élargissez la liste des pays que si les exigences géographiques de votre workflow ont réellement changé. Les replis silencieux vers d'autres pays peuvent casser la logique dépendante de la géolocalisation en aval.

Le corps de la réponse revient sous forme de texte illisible

Symptôme : La réponse data (ou body) contient du mojibake ou des caractères illisibles lorsque la cible utilise un charset non UTF-8.

Cause : Par défaut, FourA décode automatiquement les corps de réponse en UTF-8 en fonction du header Content-Type de la cible ou d'une balise HTML <meta charset>. Si la cible ment sur son charset, vous obtenez un texte illisible.

Solution : Pour les payloads binaires (images, protobuf, audio brut), définissez returnBuffer: true sur la request. Le corps revient sous la forme d'un tampon base64 sans aucun transcodage de charset appliqué.

{
  "method": "GET",
  "url": "https://example.com/image.png",
  "returnBuffer": true
}

Pour les cibles textuelles qui déclarent mal leur charset, décodez les octets bruts vous-même : récupérez avec returnBuffer: true, décodez en base64, puis appliquez le bon charset.

HTML inattendu au lieu de JSON

Symptôme : Vous attendiez du JSON du site cible mais avez reçu du HTML.

Cause : La page cible peut servir un contenu différent en fonction des headers.

Solution : Ajoutez un header Accept et activez unblocker pour des headers de navigateur réalistes :

curl -X POST https://eu.api.foura.ai/api/single/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "GET",
    "url": "https://api.example.com/data",
    "headers": [["Accept", "application/json"]],
    "unblocker": true
  }'

Vous pouvez également définir tryJsonData sur true pour que FourA analyse automatiquement les réponses JSON.

Le corps est une page de défi, pas du contenu

Symptôme : L'appel a réussi, status est 200, mais data (ou body) est une vérification de bot au lieu de la page que vous vouliez.

Cause : La cible a exécuté une vérification de bot que FourA a rencontrée mais n'a pas pu résoudre. La réponse l'indique : Single et Proxy renvoient defense avec solved: false, et Browser renvoie defenseSolved: false avec le fournisseur dans defenses.present.

Solution : Vérifiez defense.vendor d'abord, puis passez au niveau supérieur. Essayez un autre profil de navigateur sur Single, passez à Proxy pour une sortie différente, ou utilisez Browser pour que le JavaScript s'exécute. Référence complète des champs et liste des fournisseurs : Défenses anti-bot.

Ajoutez une sous-chaîne validate.data.accept que seule la vraie page contient. Sans cela, une page de défi renvoyée avec HTTP 200 compte comme un succès, et vous le découvrez en aval au lieu de lors de l'appel.

Toujours bloqué ?

Si aucune des solutions ci-dessus ne fonctionne :

  1. Consultez la page d'état pour tout incident en cours
  2. Examinez les métriques de vos requêtes dans le Tableau de bord
  3. Contactez l'assistance à support@foura.ai avec les détails de votre requête (incluez le X-FourA-Request-Id de la réponse ayant échoué)

Prochaines étapes

Mis à jour : 12 août 2026