# Créer un formulaire de demande de projet pour une agence ou un freelance

> Un formulaire de démarrage de projet pour studios et freelances, qui trie les demandes en chaudes, tièdes et hors cible selon le budget et le calendrier, avant que quiconque ne lise le brief.

Publié le 2026-10-25 · https://ikiform.com/fr/guides/lead-capture/project-inquiry

Demandez les services sous forme de cases à cocher, le budget et la date de début en choix fixes, et une description assez longue pour juger de l'adéquation. Envoyez chaque demande par webhook à un petit relais qui la trie en file chaude, tiède ou hors cible selon le budget et le calendrier. Répondez ensuite à la file chaude le jour même, et déclinez poliment la file hors cible dans la journée, car ces deux réponses construisent votre réputation.

## Ce qui change avec une demande de projet

Une demande de devis demande le prix d'un travail connu. Une demande de projet pose une question plus large : sommes-nous faits pour travailler ensemble ? Le visiteur est souvent encore en train de définir le projet, et vous décidez s'il vaut un appel de découverte. Pour un studio ou un freelance, ce qui manque, ce ne sont pas les leads, ce sont les heures d'associés passées à lire des briefs qui n'auraient jamais abouti.

Ce formulaire recueille donc assez de structure pour trier avant de lire. Trois réponses suffisent : ce dont ils ont besoin, à peu près ce qu'ils peuvent dépenser, et quand. Tout ce dont vous voudriez discuter tient dans une longue description, lue en entier seulement quand les réponses structurées disent que ça en vaut la peine.

Schéma : Comment un relais trie les demandes de projet en files

1. La demande arrive sous forme de webhook signé avec les services, le budget et la date de début.
2. Le relais vérifie la signature et note le budget et le calendrier.
3. Il vérifie le score.
4. Un budget de 30 000 $ ou plus avec un démarrage sous trois mois va dans la file chaude.
5. Un budget plus faible ou un démarrage plus tardif va dans la file tiède.
6. Moins de 10 000 $ pour autre chose qu'un site web va dans la file hors cible, pour un refus rapide et aimable.

Les files sont des canaux de chat. Personne n'est rejeté automatiquement : une personne répond toujours à chaque file, dans un ordre différent.

## Les champs

Pour un formulaire plus léger avec un seul sujet, partez du [modèle de formulaire de contact](https://ikiform.com/forms/contact-form). Celui-ci ajoute les trois questions de tri. Cochez plusieurs services dans l'aperçu pour les voir stockés sous forme de liste.

Formulaire : Project inquiry

- **Nom** (`name`, text, obligatoire)
- **E-mail** (`email`, email, obligatoire)
- **Votre site actuel** (`website`, url)
- **De quoi avez-vous besoin ?** (`services`, multi_select, obligatoire)
- **Budget** (`budget`, select, obligatoire)
- **Quand doit-il démarrer ?** (`start`, radio, obligatoire)
- **Parlez-nous du projet** (`description`, textarea, obligatoire)

`services` est un `multi_select`, stocké sous forme de tableau comme `["brand", "website"]`. `website` est un champ `url` : `example.com` est donc stocké sous la forme `https://example.com/`.

| Champ | Pourquoi cette forme |
| --- | --- |
| `services` | Des cases à cocher, car les vrais projets combinent plusieurs services. Arrive sous forme de tableau dans le webhook |
| `budget` | Obligatoire ici, contrairement à un formulaire de devis. Vos tranches doivent commencer là où commence votre engagement minimum |
| `start` | **En exploration pour l'instant** est une réponse honnête, et utile : elle va dans la file tiède |
| `description` | Au moins 40 caractères, au plus 4 000. Assez long pour juger de l'adéquation, assez court pour que les gens le terminent |

## Le formulaire

Les cases à cocher partagent un même `name`. Le navigateur envoie `services=brand&services=website`, et Ikiform rassemble les répétitions dans une seule liste. Terminer le nom par `[]` fonctionne aussi, si votre outillage l'attend.

`start-a-project.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">Email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />
  <label for="website">Your current website</label>
  <input id="website" name="website" inputmode="url" placeholder="example.com" />

  <fieldset>
    <legend>What do you need?</legend>
    <label><input type="checkbox" name="services" value="brand" /> Brand identity</label>
    <label><input type="checkbox" name="services" value="website" /> Website</label>
    <label><input type="checkbox" name="services" value="app" /> Web or mobile app</label>
    <label><input type="checkbox" name="services" value="seo" /> Search and content</label>
  </fieldset>

  <label for="budget">Budget</label>
  <select id="budget" name="budget" required>
    <option value="under_10k">Under $10,000</option>
    <option value="10k_30k">$10,000 to $30,000</option>
    <option value="30k_75k">$30,000 to $75,000</option>
    <option value="over_75k">Over $75,000</option>
  </select>

  <fieldset>
    <legend>When should it start?</legend>
    <label><input type="radio" name="start" value="this_month" required /> This month</label>
    <label><input type="radio" name="start" value="next_quarter" /> In the next three months</label>
    <label><input type="radio" name="start" value="exploring" /> Exploring for now</label>
  </fieldset>

  <label for="description">Tell us about the project</label>
  <textarea id="description" name="description" rows="6" minlength="40" maxlength="4000" required></textarea>

  <input type="hidden" name="_redirect" value="https://studio.example/inquiry/thanks" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send inquiry</button>
</form>
```

## Trier les demandes par webhook

Ce serveur Express reçoit chaque demande, la vérifie, choisit une file et publie un court résumé dans le canal Slack de cette file. Il lit le corps brut avec `express.raw`, car la signature couvre les octets exacts envoyés par Ikiform, et passe les `req.headers` de Node tels quels à `verifyWebhook`.

`server.ts`:

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

const BUDGET: Record<string, number> = { under_10k: 0, "10k_30k": 1, "30k_75k": 2, over_75k: 3 };
const START: Record<string, number> = { this_month: 2, next_quarter: 1, exploring: 0 };
const CHANNEL = {
  hot: process.env.SLACK_HOT_LEADS!,
  warm: process.env.SLACK_LEADS!,
  "no-fit": process.env.SLACK_NO_FIT!,
};

function lane(fields: Record<string, unknown>): keyof typeof CHANNEL {
  const budget = BUDGET[String(fields.budget)] ?? 0;
  const start = START[String(fields.start)] ?? 0;
  const services = Array.isArray(fields.services) ? fields.services : [];
  if (budget === 0 && !services.includes("website")) return "no-fit";
  if (budget >= 2 && start >= 1) return "hot";
  return "warm";
}

const app = express();

app.post("/webhooks/inquiries", express.raw({ type: "application/json" }), async (req, res) => {
  let event;
  try {
    event = await verifyWebhook({
      payload: req.body.toString("utf8"),
      headers: req.headers,
      secret: process.env.IKIFORM_WEBHOOK_SECRET!,
    });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return res.status(400).send(error.reason);
    throw error;
  }
  if (event.type !== "submission.created") return res.sendStatus(204);

  const fields = event.data.fields;
  const which = lane(fields);
  const summary = String(fields.description ?? "").slice(0, 280);
  const response = await fetch(CHANNEL[which], {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      text: `[${which}] ${fields.name}: ${(fields.services as string[]).join(", ")}, ${fields.budget}, ${fields.start}\n> ${summary}\nmailto:${fields.email}`,
    }),
  });
  res.sendStatus(response.ok ? 204 : 502);
});

app.listen(3000);
```

- Adaptez `lane()` à votre façon de vendre. Les seuils ci-dessus sont un exemple, pas un conseil.
- Le résumé correspond aux 280 premiers caractères de la description. Le texte complet est dans le tableau de bord et dans `event.data.fields`.
- Un `502` quand Slack échoue fait réessayer Ikiform pour la même livraison pendant environ 3 jours : une demande n'est donc pas perdue à cause d'une panne du chat.

Ajoutez l'URL `https:` publique du serveur sous **Webhooks**. Si vous préférez ne pas faire tourner de serveur, le même aiguillage fonctionne comme une étape de routeur dans [Zapier](https://ikiform.com/blog/form-submissions-to-zapier.md), [Make](https://ikiform.com/blog/form-submissions-to-make.md) ou [n8n](https://ikiform.com/blog/form-submissions-to-n8n.md).

## Quand vos propres services ressemblent à du spam

Le score de spam inclut des phrases de démarchage connues, comme `seo services`, `backlinks` et `rank your website`, qui ajoutent chacune 2. Si vous vendez du référencement, un vrai client peut écrire exactement ça. Les liens s'additionnent aussi : `website` est stocké comme un lien, et trois liens ou plus ajoutent 2.

| Une vraie demande qui contient | Score | Résultat |
| --- | --- | --- |
| « We need SEO services » et un site web | +2 | Reçue |
| La même chose, plus deux liens de concurrents dans la description | +2 et +2 | Reçue, à un signal du seuil |
| Tout ce qui précède, envoyé deux fois en 24 heures | +2, +2 et +3 | Spam, au-delà de 5 |

Une option référencement et contenu dans `services` permet aux clients de dire ce dont ils ont besoin sans taper la phrase. Vérifiez quand même le filtre **Spam** chaque semaine ; une demande de 50 000 $ perdue coûte plus cher que la lecture de dix spams.

## Vérifiez que tout fonctionne

1. Envoyez avec deux services cochés. La soumission stocke `services` sous forme de liste de deux éléments.
2. Envoyez avec **Plus de 75 000 $** et **Ce mois-ci**. Le résumé arrive dans le canal chaud.
3. Envoyez avec **Moins de 10 000 $** et seulement **Identité de marque**. Il arrive dans le canal hors cible.
4. Collez une description de 3 000 caractères. L'e-mail de notification coupe la valeur à 500 caractères ; le tableau de bord l'affiche en entier.
5. Arrêtez votre serveur et envoyez. La livraison affiche des tentatives échouées sous **Webhooks**, puis réussit quand vous le relancez et choisissez **Retry**.

## Pièges

- **Aucune case cochée.** Un groupe de cases vide n'envoie rien, donc le `required` HTML ne peut pas l'imposer. Ikiform refuse l'envoi avec `Choose at least one option` ; affichez cette erreur sur la page avec la version `fetch` du [guide de capture de leads](https://ikiform.com/fr/guides/lead-capture.md#form).
- **Renommer les options.** Changez librement les libellés. Ne changez les valeurs qu'en même temps que le relais, sinon les demandes tombent dans la mauvaise file.
- **Les longs briefs dans l'e-mail.** Les e-mails de notification affichent jusqu'à 20 champs et 500 caractères par valeur. La description y est coupée. Les membres de l'espace de travail reçoivent dans l'e-mail un lien vers la soumission complète.
- **Le refus.** Ikiform n'envoie rien à la personne qui a rempli le formulaire : un lead hors cible n'entend donc rien si personne ne répond. Un refus de deux lignes avec une recommandation garde la porte ouverte.

## Questions

### Que doit demander un formulaire de demande de projet ?

Les coordonnées, les services nécessaires, une tranche de budget, une date de début et une description du projet. Les trois questions à choix fixe permettent de trier les demandes avant que quiconque ne lise la description.

### Comment sont stockées les réponses à des cases à cocher ?

Les cases à cocher qui partagent un même nom sont rassemblées dans une seule liste. Avec un champ multi_select défini, Ikiform n'accepte que les valeurs listées et les stocke sous forme de tableau, et c'est ce que transporte le webhook.

### Faut-il exiger un budget dans un formulaire de demande ?

Pour une demande de projet, généralement oui : c'est le meilleur signal d'adéquation, et des tranches qui commencent à votre engagement minimum rendent la question naturelle. Pour une demande de devis, où c'est vous qui fixez le prix, rendez-le facultatif.

### Pourquoi une vraie demande concernant le SEO a-t-elle fini en spam ?

Des phrases comme seo services comptent comme signal de spam, et les liens augmentent le score. Avec une répétition identique dans les 24 heures, cela atteint le seuil de 5. Marquez la demande comme non-spam pour déclencher son e-mail et son webhook, et proposez le référencement en case à cocher pour que les clients n'aient pas à taper la phrase.

## Autres guides

- [Formulaire de capture de leads](https://ikiform.com/fr/guides/lead-capture.md): Un formulaire de capture de leads sur votre propre site, qui vous écrit avec le lead en adresse de réponse, alerte le chat de l'équipe et alimente votre CRM, pour répondre tant que le lead est encore là.
- [Formulaire de demande de devis](https://ikiform.com/fr/guides/lead-capture/quote-request.md): Un formulaire de demande de devis qui reçoit les briefs sous forme de liens partagés plutôt qu'en pièces jointes, fixe une échéance à chaque demande et garde les leads riches en liens hors du spam.
- [Leads vers HubSpot ou Pipedrive](https://ikiform.com/fr/guides/lead-capture/leads-to-crm.md): Convertissez chaque webhook Ikiform signé en upsert de contact HubSpot ou en appels person et lead de Pipedrive, sans contacts en double quand une livraison est réessayée.
- [Formulaire de demande de consultation](https://ikiform.com/fr/guides/lead-capture/consultation-request.md): Un formulaire de demande de consultation pour comptables, avocats, coachs et cabinets, qui demande comment et quand appeler, et garde les détails sensibles pour l'appel.
- [Formulaire de demande de démo](https://ikiform.com/fr/guides/lead-capture/demo-request.md): Un formulaire de réservation de démo qui stocke le lead, puis envoie le visiteur vers Cal.com ou Calendly avec son nom et son e-mail déjà remplis.
- [Formulaire de leads Next.js](https://ikiform.com/fr/guides/lead-capture/nextjs.md): Un formulaire de leads Next.js App Router qui valide avec Zod dans une server action, garde les UTM du premier contact dans un cookie et envoie les leads qualifiés vers votre agenda.
