Problemas comunes

Soluciones a los problemas más comunes al usar la API de FourA.

Contenido vacío o incompleto

Síntoma: La API devuelve un estado 200 pero el campo data está vacío o no tiene el contenido esperado.

Causa: La página de destino usa JavaScript para renderizar el contenido después de la carga inicial de la página.

Solución: Cambia del endpoint único al endpoint del navegador. Usa checkText para verificar que el contenido se ha cargado:

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"
  }'

Nota: el endpoint del navegador devuelve el contenido en el campo body (no en data).

Páginas 403 Forbidden o CAPTCHA

Síntoma: La API devuelve un HTML que contiene un desafío CAPTCHA o una página de acceso denegado.

Causa: El sitio de destino detectó la request como automatizada y la bloqueó.

Solución: Usa el endpoint del proxy para la rotación automática de 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 el problema persiste, aumenta maxTries para darle más intentos a la rotación de proxy.

Errores de timeout

Síntoma: Las requests fallan con un error de timeout.

Causa: La página de destino tarda en cargar más que el timeout configurado.

Solución: Aumenta timeout_ms (el valor por defecto es 15s para single, 30s para browser y 45s para 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
  }'

Para las request del navegador, verifica también que tu valor checkText realmente aparezca en la página. Un error tipográfico siempre causará un timeout.

429 Too Many Requests (Límite de RPM)

Síntoma: La API devuelve un estado 429 con un mensaje "rate limit exceeded".

Causa: Has superado tu límite de request por minuto (RPM). Esto es diferente a los límites de concurrencia (ver 503 a continuación).

Solución: Usa el campo retryAfter de la response para esperar la cantidad de tiempo adecuada antes de reintentar:

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"}
)

Revisa tu uso actual en el Dashboard para ver tus rate limits.

503 Service Unavailable

Síntoma: La API devuelve el estado 503.

Causa: Esto ocurre en dos casos:

  1. Límite de concurrencia alcanzado. Tienes demasiadas requests ejecutándose simultáneamente. Esto es diferente al 429, que limita las requests por minuto. Con el 503, no has superado tu RPM, pero has alcanzado el máximo de requests que pueden ejecutarse al mismo tiempo.
  2. Servicio deshabilitado temporalmente. Hay una ventana de mantenimiento en curso.

Ambos casos incluyen un campo retryAfter en la response.

Solución: Espera retryAfter segundos, luego vuelve a intentar:

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 alcanzas regularmente los límites de concurrencia 503, reduce el número de requests paralelos en tu flujo de scraping, o verifica el límite de concurrencia de tu plan en el Panel de control.

504 Upstream Timeout

Síntoma: La API devuelve 504 con {"error": "Upstream timeout"}.

Causa: El trabajo no terminó dentro del presupuesto de tiempo que declaraste para el request. Un objetivo lento, la resolución de un desafío en frío o una página muy grande pueden causarlo. No es un problema con tu clave, tus parámetros o tu proxy.

Solución: Dale más tiempo a la llamada, o vuelve a intentarlo. FourA espera tu timeout_ms más un pequeño margen, por lo que aumentarlo realmente extiende la espera:

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

Para /api/auto/ en un objetivo protegido, una primera llamada en frío puede tardar decenas de segundos. Su timeout_ms cubre toda la escalera y acepta hasta 180000.

502 Upstream no disponible

Síntoma: La API devuelve 502 con {"error": "Upstream unavailable"}, o 503 con {"error": "Backend service unavailable"}.

Causa: FourA alcanzó su propio motor pero no pudo usar la respuesta, generalmente porque una instancia se estaba reiniciando.

Solución: Reintenta con un breve tiempo de espera. Ambos se clasifican como service_error, y solo success se factura, por lo que un reintento no te cuesta nada extra. Si dura más de un minuto o dos, revisa la página de estado.

401 Errores de autenticación

Síntoma: Cada request devuelve 401 Unauthorized.

Lista de verificación:

  1. Verifica que el header sea X-API-Key: YOUR_API_KEY (no Authorization: Bearer ni Api-Key)
  2. Comprueba si hay espacios en blanco adicionales o saltos de línea en tu API key
  3. Crea una nueva clave desde el Dashboard si la actual pudiera estar comprometida

400 El objetivo se resuelve a una IP privada o reservada

Síntoma: La API devuelve 400 con Target <ip> resolves to a private/reserved IP antes de que la request salga de FourA.

Causa: Tu url se resuelve a un rango de IP privado, de loopback o reservado (RFC 5735, RFC 6598 o bloques reservados de IPv6). FourA rechaza estos objetivos para que su red no pueda usarse para alcanzar hosts internos.

Solución: Obtén una URL pública. Si estás haciendo pruebas, usa un objetivo público como https://example.com o https://httpbin.org/get. Si tu objetivo previsto es un servicio que tú ejecutas, exponlo primero en un hostname público.

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

no_eligible_proxy al usar exitCountries

Síntoma: Una llamada /api/proxy/ con exitCountries devuelve HTTP 200 con una envoltura de error JSON:

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

Causa: El pool de proxy actual no tiene una salida funcional cuyo país visible para el objetivo coincida con tu lista de permitidos. FourA nunca recurre a un país no solicitado cuando configuras exitCountries.

Solución: Conserva el alcance solicitado y vuelve a intentarlo más tarde. El pool se actualiza aproximadamente cada diez minutos, por lo que un país que no tiene coincidencia ahora a menudo obtiene una en el transcurso de una hora.

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")

Solo amplía la lista de países si el requisito de país de tu flujo de trabajo realmente cambió. Los respaldos silenciosos a otros países pueden romper la lógica que depende de la geolocalización más adelante.

El cuerpo de la respuesta regresa como texto ilegible

Síntoma: La respuesta data (o body) contiene caracteres ilegibles o corruptos cuando el objetivo usa un juego de caracteres que no es UTF-8.

Causa: Por defecto, FourA decodifica automáticamente los cuerpos de respuesta a UTF-8 basándose en el header Content-Type del objetivo o en una etiqueta HTML <meta charset>. Si el objetivo miente sobre su juego de caracteres, obtienes texto ilegible.

Solución: Para payloads binarios (imágenes, protobuf, audio crudo), configura returnBuffer: true en la request. El cuerpo regresa como un buffer en base64 sin aplicar ninguna transcodificación de juego de caracteres.

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

Para los objetivos de texto que declaran incorrectamente su charset, decodifica los bytes sin procesar tú mismo: obtén con returnBuffer: true, decodifica en base64 y luego aplica el charset correcto.

HTML inesperado en lugar de JSON

Síntoma: Esperabas JSON del sitio objetivo pero recibiste HTML.

Causa: La página objetivo puede servir contenido diferente según los headers.

Solución: Agrega un header Accept y habilita unblocker para obtener headers de navegador realistas:

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
  }'

También puedes establecer tryJsonData en true para que FourA analice automáticamente las respuestas JSON.

El cuerpo es una página de desafío, no el contenido

Síntoma: La llamada tuvo éxito, status es 200, pero data (o body) es una comprobación de bot en lugar de la página que querías.

Causa: El objetivo ejecutó una comprobación de bot que FourA encontró pero no pudo superar. La respuesta lo indica: Single y Proxy devuelven defense con solved: false, y Browser devuelve defenseSolved: false con el proveedor en defenses.present.

Solución: Verifica defense.vendor primero y luego escala. Prueba un perfil de navegador diferente en Single, cambia a Proxy para obtener una salida diferente o usa Browser para que se ejecute JavaScript. Referencia completa de campos y lista de proveedores: Defensas anti-bot.

Añade una subcadena validate.data.accept que solo contenga la página real. Sin ella, una página de desafío devuelta con HTTP 200 cuenta como éxito y te enteras del error más adelante en el proceso en lugar de en la llamada.

¿Sigues teniendo problemas?

Si ninguna de las soluciones anteriores funciona:

  1. Revisa la página de estado por si hay incidentes en curso
  2. Revisa tus métricas de request en el Dashboard
  3. Contacta con soporte en support@foura.ai con los detalles de tu request (incluye el X-FourA-Request-Id de la respuesta fallida)

Próximos pasos

Actualizado: 12 de agosto de 2026