# Buat formulir permintaan penawaran tanpa unggah file

> Formulir minta penawaran yang mengumpulkan brief sebagai tautan bersama alih-alih unggahan, memberi tenggat pada setiap permintaan, dan menjauhkan lead yang penuh tautan dari spam.

Terbit 2026-10-25 · https://ikiform.com/id/guides/lead-capture/quote-request

Minta brief sebagai tautan ke folder bersama di field `url`, karena Ikiform menolak unggah file dengan `422 files_not_supported`. Jadikan layanan dan anggaran pilihan tetap agar setiap permintaan tiba dalam bentuk yang sama, dan janjikan waktu penyelesaian di pesan sukses. Lalu kirim setiap permintaan ke tim beserta tenggatnya, agar janji itu ditepati.

## Apa yang berbeda dari permintaan penawaran

Permintaan penawaran datang bersama materi: brief, denah, spreadsheet komponen, desain tahun lalu. Jawaban yang biasa adalah input file. Itu tidak bekerja di sini, dan ada baiknya tahu alasannya sebelum Anda mendesain di sekitarnya.

Unggah file belum didukung. Kiriman berisi file mendapat `422 files_not_supported`. Seluruh kiriman ditolak, bukan hanya file-nya, jadi pengunjung yang melampirkan PDF kehilangan semua yang mereka ketik kecuali formulir Anda menampilkan error dan menyimpan input mereka. Tautan bersama menghindari masalah ini dan punya kelebihan sendiri: klien bisa menambah file setelah mengirim, tidak ada batas ukuran, dan tidak ada file besar yang menumpuk di inbox Anda.

Diagram: Input file dibandingkan dengan field tautan di formulir permintaan penawaran

1. Dengan input file, pengunjung melampirkan brief.pdf dan browser mengirim kiriman multipart.
2. Ikiform menolak seluruh kiriman dengan 422 files_not_supported.
3. Tidak ada yang disimpan, jadi tidak ada email atau webhook yang dikirim.
4. Dengan field tautan, pengunjung menempel tautan ke folder bersama.
5. Ikiform memeriksa bahwa itu URL https yang valid dan menyimpan permintaannya.
6. Tautan tiba di email notifikasi dan di chat, tempat siapa pun di tim bisa membukanya.

Permintaan yang sama, dua hasil. Minta tautan folder dan file-file itu tidak pernah melewati formulir.

## Field-nya

[Template permintaan penawaran](https://ikiform.com/forms/quote-request) punya set field lengkap dengan telepon, perusahaan, dan jadwal. Versi di bawah memangkasnya dan menambahkan field tautan. Coba tautan `http:`, atau tautan `drive.google.com` tanpa skema, untuk melihat bagaimana field `url` menjawab.

Formulir: Quote request

- **Nama** (`name`, text, wajib)
- **Email kantor** (`email`, email, wajib)
- **Apa yang Anda butuhkan?** (`service`, select, wajib)
- **Budget** (`budget`, select)
- **Tautan ke file Anda** (`files_url`, url)
- **Apa saja yang perlu dicakup penawaran?** (`details`, textarea, wajib)

`files_url` adalah field `url` dengan `https_only`, jadi `drive.google.com/...` tanpa skema disimpan sebagai `https://drive.google.com/...` dan tautan `http:` ditolak.

| Field | Mengapa bentuknya begini |
| --- | --- |
| `files_url` | Satu tautan ke folder, bukan satu field per file. Klien mengendalikan isinya dan bisa menambahkannya nanti |
| `service` | Menentukan siapa yang menghitung harganya. Nilainya tetap stabil untuk routing meskipun Anda mengganti labelnya |
| `budget` | Opsional, dengan pilihan **Not sure yet** (belum yakin) yang tidak mengirim apa pun. Field anggaran yang wajib kehilangan lead |
| `details` | Wajib, minimal 20 karakter. Penawaran butuh cakupan, dan dari sinilah cakupan itu berasal |

## Formulirnya

HTML biasa. `type="url"` memunculkan keyboard yang tepat di ponsel, dan teks bantuan menjelaskan cara membagikan folder, yang menghemat satu kali bolak-balik saat tautan pertama ternyata privat.

`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>
```

> Hapus `<input type="file">` apa pun yang terbawa dari formulir lama. Yang kosong dilewati. Jika ada file yang dipilih, kiriman multipart atau `FormData` gagal seluruhnya, dan formulir urlencoded biasa hanya mengirim nama file. Bagaimanapun, file-nya tidak pernah sampai.

## Tautan dan skor spam

Formulir penawaran adalah satu-satunya tempat lead asli sengaja mengirim tautan, dan tautan adalah sinyal spam. Tiga tautan atau lebih di semua field menambah 2 pada skor. Field `url` disimpan sebagai tautan `https://` lengkap, jadi ikut dihitung.

| Permintaan berisi | Skor | Hasil |
| --- | --- | --- |
| Tautan folder | 0 | Diterima |
| Tautan folder dan dua tautan lain di `details` | +2 | Diterima |
| Tiga tautan yang sama, dikirim lagi dalam 24 jam dengan field yang sama | +2 dan +3 | Spam, di skor 5 |

Baris ketiga adalah orang sungguhan yang mengira submit pertama gagal. Itulah sebabnya formulir sebaiknya punya satu field tautan, bukan tiga, dan status suksesnya harus tidak mungkin salah dibaca. Periksa filter **Spam** setiap minggu; menandai permintaan sebagai bukan spam akan mengirim email dan webhook-nya saat itu.

## Beri tenggat pada setiap permintaan

Pesan sukses menjanjikan penawaran dalam dua hari kerja. Cloudflare Worker ini mengubah janji itu menjadi tanggal yang bisa dilihat tim. Worker memverifikasi webhook, menghitung tenggat dari `created_at`, dan mengirim permintaan ke channel penawaran bersama tautan file-nya:

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

- Hari kerja melewati Sabtu dan Minggu dalam UTC. Tambahkan hari libur Anda jika penawaran Anda memperhitungkannya.
- `files_url` yang tidak ada menghasilkan pengingat untuk meminta file di balasan pertama, alih-alih baris kosong.
- Menjawab `502` saat Slack gagal membuat Ikiform mencoba ulang pengiriman yang sama, jadi permintaan tidak hilang.

Tambahkan URL Worker di **Webhooks**, salin secret `whsec_` ke `IKIFORM_WEBHOOK_SECRET`, dan simpan URL Slack sebagai secret. [Panduan Slack](https://ikiform.com/blog/form-submissions-to-slack.md) membahas cara membuat incoming webhook.

## Pastikan berfungsi

1. Kirim dengan tautan folder Google Drive atau Dropbox. Buka tautan dari email notifikasi di jendela privat untuk memastikan bisa dilihat.
2. Kirim dengan tautan `http:`. Kiriman ditolak dengan `422` dan pesannya menyebut `files_url`.
3. Cari `type="file"` di template Anda dan hapus setiap kecocokan dari formulir penawaran yang mengirim ke Ikiform.
4. Periksa channel penawaran. Pesannya menampilkan tenggat dua hari kerja ke depan dan tautan file-nya.
5. Tekan **Reply** di email notifikasi. Balasannya menuju alamat di formulir.

## Hal yang sering menjebak

- **Tautan privat.** Kegagalan paling umum adalah tautan yang hanya bisa dibuka pemiliknya. Jelaskan cara membagikannya di teks bantuan, dan minta akses di balasan pertama alih-alih menunggunya.
- **Klien punya file tapi tidak punya folder.** Minta mereka membalas email pertama Anda dengan lampiran. Reply-to menaruh file mereka di utas email biasa bersama tim Anda.
- **Cakupan panjang.** Email notifikasi menampilkan nilai hingga 500 karakter. Teks `details` lengkap ada di dashboard dan webhook.
- **Tidak ada email konfirmasi.** Ikiform tidak mengirim email ke orang yang mengisi formulir. Pesan di halaman adalah konfirmasinya, jadi buat waktu penyelesaiannya konkret.

## Pertanyaan

### Bisakah formulir menerima upload file?

Belum. Kiriman yang berisi file ditolak dengan 422 files_not_supported. Minta link ke file sebagai gantinya, seperti URL shared drive.

### Bagaimana cara mengumpulkan gambar teknis, brief, atau foto dengan formulir penawaran?

Minta satu tautan ke folder bersama di field url, dan sebutkan di teks bantuan bahwa folder harus bisa dilihat siapa pun yang punya tautan. Klien bisa menambahkan file ke folder setelah mengirim permintaan.

### Mengapa permintaan penawaran dengan beberapa tautan masuk ke spam?

Tiga tautan atau lebih menambah 2 pada skor spam, dan field yang sama dikirim lagi dalam 24 jam menambah 3, yang mencapai ambang batas 5. Pertahankan satu field tautan, dan tandai permintaan sebagai bukan spam untuk mengirim email dan webhook-nya.

### Bisakah field anggaran dibuat opsional?

Bisa. Biarkan required mati dan tambahkan opsi pertama dengan nilai kosong, seperti Not sure yet. Pilihan kosong tidak mengirim apa pun, dan Ikiform menyimpan permintaan tanpa anggaran.

## Panduan lainnya

- [Formulir lead capture](https://ikiform.com/id/guides/lead-capture.md): Formulir lead capture di situs Anda sendiri yang mengirimi Anda email dengan reply-to, memberi tahu chat tim, dan mengisi CRM, agar Anda menjawab selagi lead masih ada.
- [Formulir inquiry proyek](https://ikiform.com/id/guides/lead-capture/project-inquiry.md): Formulir mulai proyek untuk studio dan freelancer yang memilah inquiry menjadi hot, warm, dan tidak cocok berdasarkan anggaran dan waktu sebelum ada yang membaca brief-nya.
- [Formulir permintaan demo](https://ikiform.com/id/guides/lead-capture/demo-request.md): Formulir pesan demo yang menyimpan lead, lalu mengarahkan pengunjung ke Cal.com atau Calendly dengan nama dan email yang sudah terisi.
- [Lead ke HubSpot atau Pipedrive](https://ikiform.com/id/guides/lead-capture/leads-to-crm.md): Petakan setiap webhook Ikiform bertanda tangan ke contact upsert HubSpot atau panggilan person dan lead Pipedrive, tanpa kontak duplikat saat pengiriman dicoba ulang.
- [Formulir permintaan konsultasi](https://ikiform.com/id/guides/lead-capture/consultation-request.md): Formulir permintaan konsultasi untuk akuntan, pengacara, coach, dan klinik yang menanyakan cara dan waktu menghubungi, dan menyimpan detail sensitif untuk panggilannya.
- [Formulir lead Next.js](https://ikiform.com/id/guides/lead-capture/nextjs.md): Formulir lead App Router Next.js yang memvalidasi dengan Zod di server action, menyimpan UTM first-touch di cookie, dan mengirim lead yang lolos kualifikasi ke kalender Anda.
