NueForm

Manejo de errores

Comprende el formato de respuesta de error de la API de NueForm, los códigos de error y cómo manejar errores de forma elegante en tu aplicación.

La API de NueForm utiliza códigos de estado HTTP convencionales y devuelve respuestas de error JSON estructuradas. Esta guía cubre el formato de respuesta, todos los códigos de error posibles y patrones para manejar errores en tu código.

Formatos de respuesta

Respuestas exitosas

Las llamadas exitosas a la API devuelven un objeto JSON con un campo data. Los endpoints de lista también incluyen un campo meta con información de paginación.

json
{
  "data": {
    "id": "clx1abc2d3e4f5g6h7i8j9k0",
    "title": "Customer Feedback",
    "status": "published",
    "created_at": "2026-01-15T09:30:00.000Z"
  }
}

Con metadatos de paginación:

json
{
  "data": [
    {
      "id": "clx1abc2d3e4f5g6h7i8j9k0",
      "title": "Customer Feedback"
    },
    {
      "id": "clx2def3g4h5i6j7k8l9m0n1",
      "title": "Employee Survey"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 150,
    "total_pages": 8
  }
}

Respuestas de error

Las respuestas de error devuelven un objeto JSON con un campo error que contiene el code de error, un message legible para humanos y el código de status HTTP.

json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "The requested form could not be found.",
    "status": 404
  }
}

Códigos de error

La siguiente tabla lista todos los códigos de error devueltos por la API:

CódigoEstado HTTPDescripción
BAD_REQUEST400La solicitud está mal formada, faltan campos requeridos o contiene valores inválidos.
UNAUTHORIZED401La autenticación falló. La clave de API falta, está mal formada, revocada o expirada.
FORBIDDEN403El usuario autenticado no tiene permiso para realizar esta acción.
NOT_FOUND404El recurso solicitado no existe o no es accesible para el usuario autenticado.
CONFLICT409La solicitud entra en conflicto con el estado actual del recurso (por ejemplo, una entrada duplicada o un formulario que todavía no se puede publicar).
RATE_LIMITED429Demasiadas solicitudes. Consulta Límites de velocidad para más detalles.
INTERNAL_ERROR500Ocurrió un error inesperado en el servidor.

Ejemplos de respuestas de error

400 Bad Request

Se devuelve cuando el cuerpo de la solicitud es inválido o faltan campos requeridos.

json
{
  "error": {
    "code": "BAD_REQUEST",
    "message": "Field 'title' is required.",
    "status": 400
  }
}

401 Unauthorized

Se devuelve cuando la autenticación falla por cualquier motivo.

json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired API key.",
    "status": 401
  }
}

403 Forbidden

Se devuelve cuando el usuario está autenticado pero carece de permisos. Las causas comunes incluyen acceder a recursos de otro usuario o usar una función no disponible en el plan actual.

json
{
  "error": {
    "code": "FORBIDDEN",
    "message": "API access is not available on your current plan.",
    "status": 403
  }
}

404 Not Found

Se devuelve cuando el recurso solicitado no existe.

json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "The requested form could not be found.",
    "status": 404
  }
}

409 Conflict

Se devuelve cuando la solicitud crearía un duplicado o entra en conflicto con datos existentes.

json
{
  "error": {
    "code": "CONFLICT",
    "message": "A form with this slug already exists.",
    "status": 409
  }
}

409 Conflict — publicación bloqueada

Lo devuelve POST /api/v1/forms/:id/publish (y PUT /api/v1/forms/:id con published: true) cuando el formulario todavía no puede publicarse. No se publica nada. reason indica el motivo y question_ids enumera las preguntas que hay que corregir. Cuando upgrade_required es true, hay que mejorar el plan del propietario del formulario.

json
{
  "error": {
    "code": "CONFLICT",
    "message": "E-signature contracts need a Pro plan to go live. Upgrade to publish this form, or remove the contract question.",
    "status": 409,
    "reason": "contract_requires_pro",
    "question_ids": ["66a1b2c3d4e5f6a7b8c9d001"],
    "upgrade_required": true
  }
}
reasonQué corregir
contract_requires_pro, data_node_requires_pro, booking_requires_pro, payment_connect_requires_pro, webhook_requires_proEl plan del propietario del formulario (el del propietario del equipo en los formularios de equipo) no incluye esta función. Mejora el plan o quita la función: elimina la pregunta, vacía webhook_url o cambia la pregunta de pago a la opción estándar.
booking_*Una pregunta de reserva todavía no puede aceptar reservas: conecta o vuelve a conectar su calendario, o añade su horario, su zona horaria, sus opciones de duración o el número para las llamadas de confirmación.
email_node_*A un paso de email le falta el destinatario, el nombre del remitente, el asunto o el cuerpo, o envía a {respondent.email} en un formulario que no requiere iniciar sesión.
fuse_*Una pregunta Fuse no tiene formulario Fuse, su formulario Fuse no existe o no está publicado, o su sesión fijada se archivó.
composite_*Un compuesto que usa el formulario no está publicado, se eliminó o está vacío; composite_ids los enumera.

Si creas un formulario con published: true y su publicación se bloquea, el formulario se crea igualmente como borrador: la respuesta es 201 Created con un objeto publish_error (reason, message, question_ids, upgrade_required), así que reintentar nunca crea un duplicado. Cuando PUT /api/v1/forms/:id devuelve este error, tus cambios se guardaron (saved_as_draft: true) y solo falló la publicación.

429 Rate Limited

Se devuelve cuando se ha excedido el límite de velocidad. Incluye un encabezado Retry-After.

json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Please try again later.",
    "status": 429
  }
}

500 Internal Error

Se devuelve cuando ocurre un error inesperado del servidor. Si persiste, contacta con soporte.

json
{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An internal error occurred.",
    "status": 500
  }
}

Manejo de errores en código

JavaScript

Construye un cliente de API reutilizable que verifique errores y lance excepciones tipadas:

javascript
class NueFormApiError extends Error {
  constructor(code, message, status) {
    super(message);
    this.name = "NueFormApiError";
    this.code = code;
    this.status = status;
  }
}

async function nueformRequest(path, options = {}) {
  const response = await fetch(`https://app.nueform.io/api/v1${path}`, {
    ...options,
    headers: {
      "Authorization": `Bearer ${process.env.NUEFORM_API_KEY}`,
      "Content-Type": "application/json",
      ...options.headers,
    },
  });

  const body = await response.json();

  if (!response.ok) {
    const { code, message, status } = body.error;
    throw new NueFormApiError(code, message, status);
  }

  return body;
}

// Uso
async function getForm(formId) {
  try {
    const { data } = await nueformRequest(`/forms/${formId}`);
    return data;
  } catch (error) {
    if (error instanceof NueFormApiError) {
      switch (error.code) {
        case "NOT_FOUND":
          console.error(`Form ${formId} does not exist.`);
          return null;
        case "UNAUTHORIZED":
          console.error("Check your API key configuration.");
          break;
        case "RATE_LIMITED":
          console.warn("Rate limited. Implement backoff and retry.");
          break;
        default:
          console.error(`API error [${error.code}]: ${error.message}`);
      }
    }
    throw error;
  }
}

Python

python
import os
import requests

class NueFormApiError(Exception):
    def __init__(self, code, message, status):
        super().__init__(message)
        self.code = code
        self.status = status

class NueFormClient:
    def __init__(self, api_key=None):
        self.api_key = api_key or os.environ["NUEFORM_API_KEY"]
        self.base_url = "https://app.nueform.io/api/v1"

    def request(self, method, path, **kwargs):
        url = f"{self.base_url}{path}"
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
        }

        response = requests.request(method, url, headers=headers, **kwargs)
        body = response.json()

        if not response.ok:
            error = body["error"]
            raise NueFormApiError(
                error["code"], error["message"], error["status"]
            )

        return body

# Uso
client = NueFormClient()

try:
    result = client.request("GET", f"/forms/{form_id}")
    form = result["data"]
    print(f"Form: {form['title']}")

except NueFormApiError as e:
    if e.code == "NOT_FOUND":
        print(f"Form {form_id} does not exist.")
    elif e.code == "UNAUTHORIZED":
        print("Check your API key configuration.")
    elif e.code == "RATE_LIMITED":
        print("Rate limited. Implement backoff and retry.")
    else:
        print(f"API error [{e.code}]: {e}")

Mejores prácticas

Siempre verifica el campo error

Nunca asumas que una respuesta es exitosa basándote únicamente en la presencia de un cuerpo. Siempre verifica el campo error o comprueba el código de estado HTTP antes de procesar la respuesta.

Usa códigos de error específicos para el flujo de control

Compara con error.code (por ejemplo, NOT_FOUND, RATE_LIMITED) en lugar del código de estado HTTP. Los códigos de error son estables, descriptivos y más fáciles de razonar en la lógica de la aplicación.

Registra los detalles del error

Incluye la respuesta de error completa en tus registros para depuración. El code, message y status juntos proporcionan suficiente contexto para diagnosticar la mayoría de los problemas sin reproducir la solicitud.

Maneja errores 5xx con reintentos

Los errores del servidor (500 Internal Error) son típicamente transitorios. Implementa lógica de reintento con retroceso exponencial para estas respuestas. Limita los reintentos a 2--3 intentos antes de fallar.

No expongas mensajes de error a los usuarios finales

Los mensajes de error de la API están diseñados para desarrolladores, no para usuarios finales. Mapea los errores de la API a mensajes amigables para el usuario en tu aplicación.

Si recibes respuestas 500 Internal Error persistentes, contacta con soporte proporcionando los detalles de la solicitud y las marcas de tiempo. Los errores del servidor se registran en nuestro sistema y se investigan.

Ultima actualizacion: 8 de octubre de 2026