# Crea un formulario de solicitud de presupuesto sin subida de archivos

> Un formulario de solicitud de presupuesto que recoge los briefs como enlaces compartidos en lugar de archivos, pone fecha límite a cada solicitud y evita que los leads con muchos enlaces acaben en spam.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/lead-capture/quote-request

Pide el brief como enlace a una carpeta compartida en un campo `url`, porque Ikiform rechaza la subida de archivos con `422 files_not_supported`. Mantén el servicio y el presupuesto como opciones fijas para que todas las solicitudes lleguen con la misma forma, y promete un plazo de respuesta en el mensaje de éxito. Después envía cada solicitud al equipo con su fecha límite, para que la promesa se cumpla.

## Qué tiene de distinto una solicitud de presupuesto

Una solicitud de presupuesto viene con material: un brief, un plano, una hoja de cálculo de piezas, el diseño del año pasado. La respuesta habitual es un input de archivo. Aquí eso no funciona, y vale la pena saber por qué antes de diseñar en torno a ello.

La subida de archivos todavía no está disponible. Un envío con un archivo recibe `422 files_not_supported`. Se rechaza todo el envío, no solo el archivo, así que un visitante que adjunta un PDF pierde todo lo que escribió a menos que tu formulario muestre el error y conserve sus datos. Un enlace compartido evita el problema y tiene ventajas propias: el cliente puede añadir archivos después de enviar, no hay límite de tamaño y no se acumula nada pesado en tu bandeja de entrada.

Diagrama: Un input de archivo comparado con un campo de enlace en un formulario de solicitud de presupuesto

1. Con un input de archivo, el visitante adjunta brief.pdf y el navegador envía un post multipart.
2. Ikiform rechaza todo el envío con 422 files_not_supported.
3. No se guarda nada, así que no sale ningún email ni webhook.
4. Con un campo de enlace, el visitante pega un enlace a una carpeta compartida.
5. Ikiform comprueba que es una URL https válida y guarda la solicitud.
6. El enlace llega en el email de notificación y en el chat, donde cualquiera del equipo puede abrirlo.

La misma solicitud, dos resultados. Pide un enlace a una carpeta y los archivos nunca pasan por el formulario.

## Los campos

La [plantilla de solicitud de presupuesto](https://ikiform.com/forms/quote-request) tiene el conjunto completo de campos con teléfono, empresa y plazos. La versión de abajo la recorta y añade el campo de enlace. Prueba un enlace `http:`, o un enlace `drive.google.com` sin protocolo, para ver cómo responde el campo `url`.

Formulario: Quote request

- **Nombre** (`name`, text, obligatorio)
- **Email del trabajo** (`email`, email, obligatorio)
- **¿Qué necesitas?** (`service`, select, obligatorio)
- **Presupuesto** (`budget`, select)
- **Enlace a tus archivos** (`files_url`, url)
- **¿Qué debe cubrir el presupuesto?** (`details`, textarea, obligatorio)

`files_url` es un campo `url` con `https_only`, así que un `drive.google.com/...` sin protocolo se guarda como `https://drive.google.com/...` y un enlace `http:` se rechaza.

| Campo | Por qué tiene esta forma |
| --- | --- |
| `files_url` | Un enlace a una carpeta, no un campo por archivo. El cliente controla lo que hay dentro y puede añadir más después |
| `service` | Decide quién hace el presupuesto. Los valores se mantienen estables para el enrutado aunque cambies las etiquetas |
| `budget` | Opcional, con una opción **Not sure yet** que no envía nada. Un campo de presupuesto obligatorio hace perder leads |
| `details` | Obligatorio, de al menos 20 caracteres. Un presupuesto necesita un alcance, y aquí es de donde sale |

## El formulario

HTML sin más. `type="url"` muestra el teclado adecuado en el móvil, y el texto de ayuda explica cómo compartir la carpeta, lo que ahorra un ida y vuelta cuando el primer enlace resulta ser privado.

`quote.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required />

  <label for="email">Work email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="service">What do you need?</label>
  <select id="service" name="service" required>
    <option value="design">Design</option>
    <option value="development">Development</option>
    <option value="both">Design and development</option>
  </select>

  <label for="budget">Budget</label>
  <select id="budget" name="budget">
    <option value="">Not sure yet</option>
    <option value="under_5k">Under $5,000</option>
    <option value="5k_20k">$5,000 to $20,000</option>
    <option value="over_20k">Over $20,000</option>
  </select>

  <label for="files_url">Link to your files</label>
  <input id="files_url" name="files_url" type="url" inputmode="url" placeholder="https://drive.google.com/..." aria-describedby="files-help" />
  <p id="files-help">A shared folder with the brief, mockups or specs. Set it so anyone with the link can view.</p>

  <label for="details">What should the quote cover?</label>
  <textarea id="details" name="details" rows="5" minlength="20" required></textarea>

  <input type="hidden" name="_redirect" value="https://example.com/quote/thanks" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Request a quote</button>
</form>
```

> Quita cualquier `<input type="file">` heredado de un formulario antiguo. Uno vacío se ignora. Con un archivo elegido, un envío multipart o con `FormData` falla entero, y un formulario urlencoded normal envía solo el nombre del archivo. En ambos casos, el archivo nunca llega.

## Los enlaces y la puntuación de spam

Un formulario de presupuesto es el único sitio donde los leads reales envían enlaces a propósito, y los enlaces son una señal de spam. Tres o más enlaces entre todos los campos suman 2 a la puntuación. Un campo `url` se guarda como un enlace `https://` completo, así que cuenta.

| La solicitud contiene | Puntuación | Resultado |
| --- | --- | --- |
| El enlace a la carpeta | 0 | Recibido |
| El enlace a la carpeta y dos enlaces más en `details` | +2 | Recibido |
| Los mismos tres enlaces, enviados otra vez en 24 horas con los mismos campos | +2 y +3 | Spam, con 5 |

La tercera fila es una persona real que pensó que el primer envío había fallado. Por eso el formulario debe tener un campo de enlace, no tres, y por eso el estado de éxito tiene que ser inconfundible. Revisa el filtro **Spam** cada semana; al marcar una solicitud como no spam se envían en ese momento su email y su webhook.

## Pon una fecha límite a cada solicitud

El mensaje de éxito promete un presupuesto en dos días laborables. Este Cloudflare Worker convierte esa promesa en una fecha que el equipo puede ver. Verifica el webhook, calcula la fecha límite a partir de `created_at` y publica la solicitud en un canal de presupuestos con el enlace a los archivos:

`src/index.ts`:

```ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";

function addWorkingDays(from: Date, days: number) {
  const date = new Date(from);
  while (days > 0) {
    date.setUTCDate(date.getUTCDate() + 1);
    const day = date.getUTCDay();
    if (day !== 0 && day !== 6) days -= 1;
  }
  return date.toISOString().slice(0, 10);
}

export default {
  async fetch(request: Request, env: { IKIFORM_WEBHOOK_SECRET: string; SLACK_QUOTES_WEBHOOK: string }) {
    const payload = await request.text();
    let event;
    try {
      event = await verifyWebhook({ payload, headers: request.headers, secret: env.IKIFORM_WEBHOOK_SECRET });
    } catch (error) {
      if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
      throw error;
    }
    if (event.type !== "submission.created") return new Response(null, { status: 204 });

    const quote = event.data.fields;
    const due = addWorkingDays(new Date(event.data.created_at), 2);
    const lines = [
      `Quote due *${due}*: ${quote.service} for ${quote.name} (${quote.budget ?? "budget not given"})`,
      quote.files_url ? `Files: ${quote.files_url}` : "No files linked. Ask for them in the first reply.",
      `Reply: mailto:${quote.email}`,
    ];

    const response = await fetch(env.SLACK_QUOTES_WEBHOOK, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ text: lines.join("\n") }),
    });
    if (!response.ok) return new Response(`Slack answered ${response.status}`, { status: 502 });
    return new Response(null, { status: 204 });
  },
};
```

- Los días laborables se saltan el sábado y el domingo en UTC. Añade tus festivos si los tienes en cuenta al presupuestar.
- Si falta `files_url`, aparece un recordatorio para pedir los archivos en la primera respuesta, en lugar de una línea vacía.
- Responder `502` cuando Slack falla hace que Ikiform reintente la misma entrega, así que no se pierde ninguna solicitud.

Añade la URL del Worker en **Webhooks**, copia el secreto `whsec_` en `IKIFORM_WEBHOOK_SECRET` y guarda la URL de Slack como secreto. La [guía de Slack](https://ikiform.com/blog/form-submissions-to-slack.md) explica cómo crear el incoming webhook.

## Comprueba que funciona

1. Envía el formulario con un enlace a una carpeta de Google Drive o Dropbox. Abre el enlace del email de notificación en una ventana privada para confirmar que se puede ver.
2. Envía el formulario con un enlace `http:`. El envío se rechaza con `422` y el mensaje nombra `files_url`.
3. Busca `type="file"` en tus plantillas y quita todas las coincidencias de los formularios de presupuesto que envían a Ikiform.
4. Revisa el canal de presupuestos. El mensaje muestra la fecha límite a dos días laborables y el enlace a los archivos.
5. Pulsa **Reply** en el email de notificación. Escribe a la dirección del formulario.

## Errores comunes

- **Enlaces privados.** El fallo más común es un enlace que solo puede abrir su dueño. Explica en el texto de ayuda cómo compartirlo, y pide acceso en la primera respuesta en lugar de esperar.
- **Clientes con archivos y sin carpeta.** Diles que respondan a tu primer email con adjuntos. El reply-to pone sus archivos en un hilo de email normal con tu equipo.
- **Alcances largos.** Los emails de notificación muestran valores de hasta 500 caracteres. El texto completo de `details` está en el panel y en el webhook.
- **Sin email de confirmación.** Ikiform no envía email a la persona que rellena el formulario. El mensaje en la página es la confirmación, así que concreta el plazo de respuesta.

## Preguntas

### ¿Puede el formulario aceptar subida de archivos?

Todavía no. Un envío que contiene un archivo se rechaza con 422 files_not_supported. Pide en su lugar un enlace al archivo, como la URL de una carpeta compartida.

### ¿Cómo recojo planos, briefings o fotos con un formulario de presupuesto?

Pide un enlace a una carpeta compartida en un campo url, y di en el texto de ayuda que la carpeta debe poder verla cualquiera con el enlace. El cliente puede añadir archivos a la carpeta después de enviar la solicitud.

### ¿Por qué una solicitud de presupuesto con varios enlaces acabó en spam?

Tres o más enlaces suman 2 a la puntuación de spam, y los mismos campos enviados otra vez en 24 horas suman 3, lo que alcanza el umbral de 5. Deja un solo campo de enlace, y marca la solicitud como no spam para enviar su email y su webhook.

### ¿Puedo hacer opcional el campo de presupuesto?

Sí. Deja required desactivado y añade una primera opción con valor vacío, como Not sure yet. Una opción vacía no envía nada, e Ikiform guarda la solicitud sin presupuesto.

## Más guías

- [Formulario de captación de leads](https://ikiform.com/es/guides/lead-capture.md): Un formulario de captación de leads en tu propio sitio que te avisa por email con reply-to, avisa al chat del equipo y alimenta tu CRM, para responder mientras el lead sigue ahí.
- [Formulario de consulta de proyecto](https://ikiform.com/es/guides/lead-capture/project-inquiry.md): Un formulario de inicio de proyecto para estudios y freelances que clasifica las consultas en calientes, templadas y sin encaje por presupuesto y plazos antes de que nadie lea el briefing.
- [Formulario de solicitud de demo](https://ikiform.com/es/guides/lead-capture/demo-request.md): Un formulario para reservar una demo que guarda el lead y luego envía al visitante a Cal.com o Calendly con su nombre y email ya rellenados.
- [Leads a HubSpot o Pipedrive](https://ikiform.com/es/guides/lead-capture/leads-to-crm.md): Convierte cada webhook firmado de Ikiform en el upsert de contactos de HubSpot o en las llamadas de personas y leads de Pipedrive, sin contactos duplicados cuando se reintenta una entrega.
- [Formulario de solicitud de consulta](https://ikiform.com/es/guides/lead-capture/consultation-request.md): Un formulario de solicitud de consulta para gestorías, abogados, coaches y clínicas que pregunta cómo y cuándo llamar, y deja los detalles sensibles para la llamada.
- [Formulario de leads en Next.js](https://ikiform.com/es/guides/lead-capture/nextjs.md): Un formulario de leads en el App Router de Next.js que valida con Zod en una server action, guarda los UTMs del primer contacto en una cookie y envía los leads cualificados a tu calendario.
