Documentation

Intégrez en quelques minutes.

Votre site ne touche jamais au SMTP. Il détient deux valeurs et appelle deux endpoints — le service se charge de l'envoi, du filtrage anti-spam et de la réponse automatique à votre image.

1Le contrat à deux valeurs

Créez un formulaire dans votre tableau de bord et copiez son ID. Donnez à votre site exactement deux valeurs :

FORM_API_URL

L'origine du service — là où partent les défis et les soumissions.

FORM_ID

L'UUID d'un formulaire. Chaque site (ou chaque formulaire) a le sien.

2L'assistant à copier-coller

Fonctionne avec Astro, Next.js, Nuxt, Vue, Svelte, ou un simple <script type="module">.

form-service.js
// form-service.js — drop into any project (framework-agnostic)
const API_URL = import.meta.env.PUBLIC_FORM_API_URL; // or process.env / hardcode
const FORM_ID = import.meta.env.PUBLIC_FORM_ID;      // UUID from your dashboard

async function sha256Hex(text) {
  const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
  return [...new Uint8Array(buf)].map(b => b.toString(16).padStart(2, "0")).join("");
}

export async function submitForm(fields, { lang = "en" } = {}) {
  // 1. Get a proof-of-work challenge
  const c = await (await fetch(`${API_URL}/api/challenge`)).json();

  // 2. Solve it (costs a bot CPU, costs your user ~a blink)
  let nonce = 0;
  const prefix = "0".repeat(c.difficulty);
  while (!(await sha256Hex(`${c.challenge}:${nonce}`)).startsWith(prefix)) nonce++;

  // 3. Submit the fields
  const res = await fetch(`${API_URL}/api/submit/${FORM_ID}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      ...fields,
      _lang: lang,
      _gotcha: "",              // honeypot — leave empty
      pow_challenge: c.challenge,
      pow_timestamp: c.timestamp,
      pow_nonce: String(nonce),
    }),
  });
  if (!res.ok) throw new Error((await res.json()).error ?? "Submission failed");
  return res.json();
}

3Utilisez-le

your-form-handler.js
import { submitForm } from "./form-service";

await submitForm({
  name: "Ada Lovelace",
  email: "ada@example.com",     // used for the branded auto-reply
  message: "I'd like a quote.",
});
  • email field — s'il est présent, l'expéditeur reçoit votre réponse automatique à votre image.
  • _lang — "en" ou "fr" — sélectionne la langue de la réponse automatique.
  • _gotcha — champ honeypot caché. Les humains le laissent vide ; les bots le remplissent et sont écartés en silence.
  • files — envoyez des données en base64 — elles sont téléversées vers le stockage et arrivent sous forme de liens de téléchargement.

4Laissez votre IA le faire

Vous utilisez Claude, Cursor ou Copilot ? Nous publions un fichier d'installation lisible par machine à /llm-install.md — collez ce prompt et votre IA réalise toute l'intégration, correctement, du premier coup :

prompt.txt — collez dans votre assistant IA
Read https://inlett.vercel.app/llm-install.md
and integrate Inlet into this project exactly as it instructs.
My values: FORM_API_URL=https://inlett.vercel.app FORM_ID=<paste yours>

Utilisateurs de Claude Code : déposez notre fichier skill .claude/skills/inlet/SKILL.md et Claude câble seul les formulaires, honeypots et webhooks dans n'importe quel projet.

5Webhooks (optionnel)

Ajoutez une URL de webhook à un formulaire et chaque lead stocké est envoyé (POST) à votre endpoint sous forme de submission.created, signé façon Stripe dans l'en-tête X-Inlet-Signature — vérifiez-le et rejetez les rejeux en cinq lignes :

verify-webhook.js
// Verify Inlet's webhook signature (Node) — read the RAW body first.
import crypto from "node:crypto";

export function verifyInletWebhook(rawBody, sigHeader, secret, toleranceSec = 300) {
  const p = Object.fromEntries(sigHeader.split(",").map(s => s.split("=")));
  const expected = crypto.createHmac("sha256", secret).update(`${p.t}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(p.t)) < toleranceSec;
  return fresh && crypto.timingSafeEqual(Buffer.from(p.v1), Buffer.from(expected));
}

La livraison est asynchrone avec une nouvelle tentative — un endpoint hors service ne peut jamais bloquer ni perdre un lead. Les endpoints doivent être en https.

Ce qui se passe côté serveur

Quatre barrières anti-spam. Honeypot, vérification par preuve de travail, filtre NLP par mots-clés, blocage VPN/cloud par DNS inversé. Les tentatives bloquées sont journalisées, jamais délivrées.

Deux e-mails. Le propriétaire reçoit la notification du lead ; l'expéditeur reçoit une réponse automatique à l'image de votre client — logo, couleurs, nom d'expéditeur. La bascule SMTP de secours fait qu'un identifiant défaillant ne perd jamais un lead.

Prêt à arrêter de câbler l'e-mail dans chaque site ?