# Monte um formulário de pedido de orçamento sem upload de arquivos

> Um formulário de pedido de orçamento que recebe briefings como links compartilhados em vez de uploads, coloca um prazo em cada pedido e mantém leads cheios de links fora do spam.

Publicado em 2026-10-25 · https://ikiform.com/pt-br/guides/lead-capture/quote-request

Peça o briefing como link para uma pasta compartilhada num campo `url`, porque o Ikiform recusa upload de arquivos com `422 files_not_supported`. Mantenha serviço e orçamento como escolhas fixas para que todo pedido chegue no mesmo formato, e prometa um prazo de resposta na mensagem de sucesso. Depois mande cada pedido para a equipe com o prazo anexado, para que a promessa seja cumprida.

## O que muda num pedido de orçamento

Um pedido de orçamento vem com material: um briefing, uma planta, uma planilha de peças, o design do ano passado. A resposta de costume é um input de arquivo. Isso não funciona aqui, e vale a pena saber por que antes de projetar em torno disso.

Upload de arquivos ainda não é suportado. Um envio com arquivo recebe `422 files_not_supported`. O envio inteiro é recusado, não só o arquivo, então um visitante que anexa um PDF perde tudo o que digitou, a menos que o seu formulário mostre o erro e mantenha o que ele digitou. Um link compartilhado evita o problema e tem vantagens próprias: o cliente pode adicionar arquivos depois de enviar, não há limite de tamanho e nada grande fica na sua caixa de entrada.

Diagrama: Um input de arquivo comparado com um campo de link num formulário de pedido de orçamento

1. Com um input de arquivo, o visitante anexa brief.pdf e o navegador envia um post multipart.
2. O Ikiform recusa o envio inteiro com 422 files_not_supported.
3. Nada é armazenado, então nenhum e-mail ou webhook é enviado.
4. Com um campo de link, o visitante cola um link para uma pasta compartilhada.
5. O Ikiform confere se é uma URL https válida e armazena o pedido.
6. O link chega no e-mail de notificação e no chat, onde qualquer pessoa da equipe pode abri-lo.

Mesmo pedido, dois resultados. Peça um link de pasta e os arquivos nunca passam pelo formulário.

## Os campos

O [modelo de pedido de orçamento](https://ikiform.com/forms/quote-request) tem o conjunto completo de campos, com telefone, empresa e prazo. A versão abaixo enxuga esse conjunto e adiciona o campo de link. Teste um link `http:`, ou um link `drive.google.com` sem protocolo, para ver como o campo `url` responde.

Formulário: Quote request

- **Nome** (`name`, text, obrigatório)
- **E-mail de trabalho** (`email`, email, obrigatório)
- **Do que você precisa?** (`service`, select, obrigatório)
- **Orçamento** (`budget`, select)
- **Link para os seus arquivos** (`files_url`, url)
- **O que o orçamento deve cobrir?** (`details`, textarea, obrigatório)

`files_url` é um campo `url` com `https_only`, então um `drive.google.com/...` sem protocolo é armazenado como `https://drive.google.com/...` e um link `http:` é recusado.

| Campo | Por que ele tem esse formato |
| --- | --- |
| `files_url` | Um link para uma pasta, não um campo por arquivo. O cliente controla o que tem dentro e pode adicionar mais depois |
| `service` | Decide quem faz o orçamento. Os valores ficam estáveis para o roteamento mesmo que você renomeie os rótulos |
| `budget` | Opcional, com uma opção **Ainda não sei** que não envia nada. Um campo de orçamento obrigatório perde leads |
| `details` | Obrigatório, com pelo menos 20 caracteres. Um orçamento precisa de escopo, e é daqui que ele vem |

## O formulário

HTML simples. `type="url"` abre o teclado certo nos celulares, e o texto de ajuda diz como compartilhar a pasta, o que economiza uma troca de mensagens quando o primeiro link acaba sendo 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>
```

> Remova qualquer `<input type="file">` herdado de um formulário antigo. Um input vazio é ignorado. Com um arquivo escolhido, um envio multipart ou com `FormData` falha por inteiro, e um formulário urlencoded simples envia só o nome do arquivo. De qualquer jeito, o arquivo nunca chega.

## Links e a pontuação de spam

Um formulário de orçamento é o único lugar em que leads reais mandam links de propósito, e links são um sinal de spam. Três ou mais links somando todos os campos acrescentam 2 à pontuação. Um campo `url` é armazenado como um link `https://` completo, então ele conta.

| O pedido contém | Pontuação | Resultado |
| --- | --- | --- |
| O link da pasta | 0 | Recebido |
| O link da pasta e mais dois links em `details` | +2 | Recebido |
| Os mesmos três links, enviados de novo em até 24 horas com os mesmos campos | +2 e +3 | Spam, com 5 |

A terceira linha é uma pessoa real que achou que o primeiro envio tinha falhado. É por isso que o formulário deve ter um campo de link, não três, e que o estado de sucesso precisa ser inconfundível. Confira o filtro **Spam** toda semana; marcar um pedido como não spam dispara o e-mail e o webhook dele nesse momento.

## Coloque um prazo em cada pedido

A mensagem de sucesso promete um orçamento em até dois dias úteis. Este Cloudflare Worker transforma essa promessa numa data que a equipe consegue ver. Ele verifica o webhook, calcula o prazo a partir de `created_at` e publica o pedido num canal de orçamentos com o link dos arquivos:

`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 });
  },
};
```

- Os dias úteis pulam sábado e domingo em UTC. Adicione seus feriados se você faz orçamentos levando-os em conta.
- Um `files_url` ausente gera um lembrete para pedir os arquivos na primeira resposta, em vez de uma linha vazia.
- Responder `502` quando o Slack falha faz o Ikiform tentar de novo a mesma entrega, para que nenhum pedido se perca.

Adicione a URL do Worker em **Webhooks**, copie o segredo `whsec_` para `IKIFORM_WEBHOOK_SECRET` e guarde a URL do Slack como segredo. O [guia do Slack](https://ikiform.com/blog/form-submissions-to-slack.md) explica como criar o incoming webhook.

## Confira se funciona

1. Envie com um link de pasta do Google Drive ou do Dropbox. Abra o link do e-mail de notificação numa janela anônima para confirmar que ele pode ser visualizado.
2. Envie com um link `http:`. O envio é recusado com `422` e a mensagem cita `files_url`.
3. Procure `type="file"` nos seus templates e remova cada ocorrência dos formulários de orçamento que enviam ao Ikiform.
4. Confira o canal de orçamentos. A mensagem mostra o prazo dois dias úteis à frente e o link dos arquivos.
5. Clique em **Reply** no e-mail de notificação. Ele escreve para o endereço informado no formulário.

## Pegadinhas

- **Links privados.** A falha mais comum é um link que só o dono consegue abrir. Diga no texto de ajuda como compartilhá-lo, e peça acesso na primeira resposta em vez de esperar.
- **Clientes com arquivos e sem pasta.** Peça que respondam ao seu primeiro e-mail com anexos. O reply-to coloca os arquivos deles numa conversa de e-mail normal com a sua equipe.
- **Escopos longos.** Os e-mails de notificação mostram valores de até 500 caracteres. O texto completo de `details` fica no painel e no webhook.
- **Nenhum e-mail de confirmação.** O Ikiform não envia e-mail para quem preenche o formulário. A mensagem na página é a confirmação, então deixe o prazo de resposta concreto.

## Perguntas

### O formulário aceita upload de arquivos?

Ainda não. Um envio que contém um arquivo é recusado com 422 files_not_supported. Peça um link para o arquivo, como a URL de um drive compartilhado.

### Como recebo desenhos, briefings ou fotos com um formulário de orçamento?

Peça um link para uma pasta compartilhada num campo url, e diga no texto de ajuda que a pasta precisa poder ser vista por qualquer pessoa com o link. O cliente pode adicionar arquivos à pasta depois de enviar o pedido.

### Por que um pedido de orçamento com vários links foi parar no spam?

Três ou mais links acrescentam 2 à pontuação de spam, e os mesmos campos enviados de novo em até 24 horas acrescentam 3, o que atinge o limite de 5. Mantenha um único campo de link, e marque o pedido como não spam para disparar o e-mail e o webhook dele.

### Posso deixar o campo de orçamento opcional?

Sim. Deixe required desligado e adicione uma primeira opção com valor vazio, como Ainda não sei. Uma escolha vazia não envia nada, e o Ikiform armazena o pedido sem orçamento.

## Mais guias

- [Formulário de captação de leads](https://ikiform.com/pt-br/guides/lead-capture.md): Um formulário de leads no seu próprio site que envia e-mail com reply-to, avisa o chat da equipe e alimenta seu CRM, para você responder enquanto o lead ainda está lá.
- [Formulário de consulta de projeto](https://ikiform.com/pt-br/guides/lead-capture/project-inquiry.md): Um formulário de "comece um projeto" para estúdios e freelancers que separa as consultas em quentes, mornas e sem fit por orçamento e prazo antes de alguém ler o briefing.
- [Formulário de pedido de demonstração](https://ikiform.com/pt-br/guides/lead-capture/demo-request.md): Um formulário de agendar demonstração que armazena o lead e depois manda o visitante para o Cal.com ou o Calendly com nome e e-mail já preenchidos.
- [Leads no HubSpot ou no Pipedrive](https://ikiform.com/pt-br/guides/lead-capture/leads-to-crm.md): Mapeie cada webhook assinado do Ikiform para o upsert de contatos do HubSpot ou para as chamadas de pessoa e lead do Pipedrive, sem contatos duplicados quando uma entrega é repetida.
- [Formulário de pedido de consulta](https://ikiform.com/pt-br/guides/lead-capture/consultation-request.md): Um formulário de pedido de consulta para contadores, advogados, coaches e clínicas que pergunta como e quando ligar, e deixa os detalhes sensíveis para a conversa.
- [Formulário de leads em Next.js](https://ikiform.com/pt-br/guides/lead-capture/nextjs.md): Um formulário de leads no App Router do Next.js que valida com Zod numa server action, guarda as UTMs do primeiro toque num cookie e manda leads qualificados para a sua agenda.
