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
- Rate Limits: Detalles de concurrencia y RPM
- Request Outcomes: Explicación de los siete valores de resultado
- Common Issues: Síntomas, causas y soluciones