Secciones de la documentación
Errores
Cada rechazo lleva errorKind junto a detail, y los campos con los que actuar. Base su lógica en el estado y en errorKind; la redacción de detail está escrita para personas y puede cambiar.
La biblioteca de Python lanza una excepción tipada para cada estado, elegida solo por el estado, nunca por el mensaje. Un 5xx se reintenta con espera progresiva antes de lanzar la excepción.
Códigos de estado
| Estado | Excepción de Python | Cuándo |
|---|---|---|
| 200 | ninguna | Éxito: el resultado está en el cuerpo. |
| 202 | ninguna | Aceptado: se puso en cola un trabajo de simulación; consúltelo para obtener el resultado. |
| 400 Bad Request | ValidationError | La solicitud no puede responderse tal como se envió: una entrada que no es un número finito, una resolución que no puede plantearse, un cuerpo de trabajo fuera de su contrato o un lote vacío o por encima de su límite. No se cuenta nada. |
| 401 Unauthorized | AuthError | No se envió ninguna clave (el cuerpo lleva keyUrl), o la clave no la emitimos nosotros o fue revocada. Nunca se refiere a la cuota. |
| 402 Payment Required | QuotaError | La cuota mensual de la cuenta está agotada, en todas las rutas contabilizadas. No se contó nada. Retry-After da los segundos hasta resetAt. |
| 403 Forbidden | AuthError | El trabajo pertenece a otra persona, o el plan de la cuenta no incluye el endpoint por lotes o el modo de resolución pedido. |
| 404 Not Found | NotFound | No existe ese slug de calculadora, tipo de trabajo o trabajo. No se cuenta nada. |
| 409 Conflict | APIError | Una aprobación de dispositivo con el límite de claves alcanzado, o para un código ya decidido (una llamada desde un navegador con sesión iniciada). |
| 422 Unprocessable Content | ValidationError | El cuerpo no se puede leer: falta un campo obligatorio, o un valor es de un tipo incorrecto (una entrada enviada como texto). Se responde antes de que se ejecute la ruta. |
| 429 Too Many Requests | RateLimitError | Demasiadas solicitudes en un minuto para la credencial, o demasiados trabajos en cola o en ejecución a la vez. Retry-After indica cuándo volver a intentarlo. |
| 500 Internal Server Error | APIError | El resultado se calculó pero no se pudo devolver, o falló una resolución. No se cobró nada. |
| 503 Service Unavailable | APIError | No se pudo comprobar la clave ni el contador de la cuota, o no se pudo poner en cola un trabajo. No se puso nada en cola ni se cobró nada; inténtelo de nuevo. |
Se lanzan otras dos excepciones sin estado: JobFailed, cuando un trabajo termina en failed (lleva el errorKind del trabajo como .kind), y LoginError, cuando rftools login no entrega ninguna clave.
Cuerpos de rechazo
Estos son los cuerpos que envía la API, con las cifras de este mes tomadas de la tabla de planes.
{
"detail": "An API key is required. Get a free key at https://rftools.io/dashboard/?newKey=1.",
"errorKind": "invalid_request",
"keyUrl": "https://rftools.io/dashboard/?newKey=1"
}{
"detail": "This API key is not valid. It may have been revoked.",
"errorKind": "invalid_request"
}Mal formada, desconocida o revocada. Un 401 nunca significa que la cuota esté agotada.
{
"detail": "This account's 100 API calls for September are used. They reset on 2026-10-01. The API plan includes 10,000 a month.",
"errorKind": "rate_limited",
"reason": "allowance",
"limit": 100,
"used": 100,
"upgradeUrl": "https://rftools.io/pricing/",
"overageUrl": null,
"resetAt": "2026-10-01T00:00:00+00:00"
}Con Retry-After en segundos hasta resetAt. El mismo cuerpo en todas las rutas contabilizadas, incluidas las calculadoras. overageUrl se indica cuando el plan puede activar el pago por uso; reason es overage_cap cuando también ese tope está agotado. No se contó nada.
{
"detail": "More than 30 requests in 60 seconds from this address. An API key allows 120.",
"errorKind": "rate_limited",
"limit": 30,
"windowSeconds": 60,
"upgradeUrl": "https://rftools.io/pricing/"
}Con Retry-After. El límite depende de la credencial que lleva la solicitud.
{
"detail": "This account already holds 1 API key, the most the Free plan allows. Revoke a key to free its place, or upgrade to Pro for 3 API keys.",
"errorKind": "not_available",
"keyLimit": 1,
"manageUrl": "https://rftools.io/dashboard/#api-usage",
"upgradeUrl": "https://rftools.io/pricing/"
}POST /apikeys responde 400; la aprobación de dispositivo responde 409 con reason: key_limit.
Tipos de error
errorKind es un conjunto cerrado, en una solicitud rechazada y en un trabajo de simulación que falló después de ser aceptado. Base su lógica en él, no en la redacción del mensaje.
| errorKind | Significado |
|---|---|
| invalid_request | Falta un parámetro, es de un tipo incorrecto, está fuera de rango, no es una de las opciones declaradas o no es un parámetro de este tipo de trabajo. El cuerpo del 400 enumera cada parámetro erróneo. |
| too_large | La solicitud está dentro del contrato pero supera lo que puede ejecutar el entorno de este plan. Reduzca el tamaño del problema. |
| not_available | La solicitud pide un modo o una función que este plan no incluye. El mensaje nombra lo que sí incluye el plan. |
| rate_limited | Se agotó un límite de trabajos simultáneos o una cuota mensual. Lleva Retry-After y, si la cuota es mensual, resetAt. |
| timeout | El trabajo superó el tiempo máximo de su tipo. No se cobra nada por él. |
| interrupted | La ejecución se detuvo antes de terminar: se sustituyó un worker o se detuvo una tarea. No se cobra nada por ella. |
| result_expired | El trabajo terminó, pero su resultado ya no está guardado. El estado sigue siendo completed y no lleva resultUrl. |
| transient | El servicio no pudo aceptar ni comprobar la solicitud en ese momento. No se puso nada en cola ni se cobró nada; inténtelo de nuevo. |
| fault | El servicio falló durante el cálculo. El mensaje indica en qué paso; no se cobra nada por ello. |