Errores de la API

Cómo manejar los errores de la API de FourA.

Formato de respuesta de error

La API devuelve objetos JSON planos para todos los errores. No hay un objeto error anidado ni códigos de error.

{
  "error": "Invalid API key"
}

Algunos errores incluyen campos adicionales como status, service, retryAfter, current o limits en el nivel superior:

{
  "error": "Rate limit exceeded",
  "status": 429,
  "service": "single",
  "retryAfter": 5,
  "current": { "concurrency": 12, "rpm": 3000 },
  "limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}

Seguimiento de un request

Cada response de la API (éxito o error) incluye un header X-Foura-Request-Id con un UUID para esa llamada. Regístrelo en su sistema. Si necesita preguntar a soporte qué sucedió con un request específico, ese ID nos permite encontrarlo.

curl -i -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://example.com"}'
# HTTP/1.1 200 OK
# X-Foura-Request-Id: 9f1c4e6c-7b2a-4d3e-8a1f-2c9d8e4a3b15
# Content-Type: application/json
# ...

Tipos de error

400: Bad Request

El cuerpo del request no contiene los campos requeridos, contiene valores no válidos o especifica un destino que la API se niega a obtener.

{
  "error": "Invalid request body format"
}

El mismo error 400 también cubre la protección contra SSRF. Si su url se resuelve en un rango de IP privado, de loopback o reservado de otro modo (RFC 5735, RFC 6598, bloques reservados de IPv6), el request se rechaza antes de salir de la red de FourA:

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

Solución: Verifique que su request incluya todos los campos requeridos, que las URL utilicen http:// o https:// y que el host se resuelva en una dirección pública.

401: Unauthorized

Su API key no se encuentra o no es válida.

Falta la key:

{
  "error": "Missing API key. Include X-API-Key header."
}

Key no válida:

{
  "error": "Invalid API key"
}

Solución: Verifique que su header X-API-Key contenga una key válida. Genere una nueva key desde el Dashboard si es necesario.

429: Rate Limited

Ha enviado demasiados requests en un período corto.

{
  "error": "Rate limit exceeded",
  "status": 429,
  "service": "single",
  "retryAfter": 5,
  "current": { "concurrency": 12, "rpm": 3000 },
  "limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}

Solución: Espere la cantidad de segundos indicada en retryAfter antes de enviar más requests. Consulte Rate Limits para obtener más detalles.

500: Server Error

Algo salió mal de nuestro lado.

Solución: Reintente el request después de un breve retraso. Si el error persiste, consulte la página de estado o póngase en contacto con soporte técnico con el X-Foura-Request-Id del response fallido.

503: Servicio deshabilitado o al límite de capacidad

Un error 503 significa que el servicio no está disponible temporalmente por mantenimiento o que ha alcanzado el límite de concurrencia. Ambos responses incluyen un campo retryAfter. El formato de concurrencia también incluye current y limits.

{
  "error": "Service disabled",
  "status": 503,
  "retryAfter": 60
}

Solución: Espere los segundos indicados en retryAfter y luego vuelva a intentarlo. La página de estado muestra las ventanas de mantenimiento activas.

Fallos en el lado del destino dentro de un 200 OK

No todos los fallos se muestran como un estado HTTP que no sea 2xx. Cuando el sitio de destino devuelve un HTTP 200 con un payload de error, FourA aún le entrega el cuerpo pero clasifica el request como application_error. Cuando el destino devuelve un estado que no es 2xx y que sus reglas de validate no aceptan, el resultado es application_fail y el cuerpo se entrega sin cambios.

Ambos casos son facturables como si el request hubiera funcionado a nivel de red. La referencia de Outcomes cubre la taxonomía completa.

Codificación de responses

FourA decodifica automáticamente los cuerpos de los responses a UTF-8. Si el destino sirve windows-1251, gbk, shift_jis, iso-8859-* o cualquier otro juego de caracteres declarado en el header Content-Type o en una etiqueta HTML <meta charset>, recibirá una cadena UTF-8 limpia en el campo data (single, proxy) o body (browser).

Para payloads binarios (imágenes, protobuf, audio sin procesar), establezca returnBuffer: true en el request. El cuerpo se devuelve como un buffer base64 sin que se aplique ninguna transcodificación de juego de caracteres.

Estrategia de reintento

Una política de reintento práctica:

import time
import requests

def make_request(url, payload, api_key, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(
            url,
            headers={"X-API-Key": api_key, "Content-Type": "application/json"},
            json=payload,
        )
        if resp.status_code == 200:
            return resp.json()

        body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
        retry_after = body.get("retryAfter", 2 ** attempt)
        request_id = resp.headers.get("X-Foura-Request-Id", "?")

        if resp.status_code in (429, 503):
            time.sleep(retry_after)
            continue
        if resp.status_code >= 500:
            time.sleep(2 ** attempt)
            continue

        # 400/401/404 won't fix themselves
        raise RuntimeError(f"{resp.status_code} (request {request_id}): {body.get('error')}")

    raise RuntimeError(f"Exhausted {max_retries} retries")

Relacionado

Actualizado: 18 de junio de 2026