Intégration
Chaque formulaire possède une URL unique de soumission de la forme https://airmess.fr/api/submit/{token}. Deux façons de l'utiliser : un formulaire HTML classique, sans aucun JavaScript (recommandé), ou un appel fetch.
Formulaire HTML classique (recommandé)
Le plus simple et le plus robuste : collez l'URL dans l'attribut action d'un <form method="post">. Rien à installer, cela fonctionne même si le JavaScript est désactivé. L'onglet Intégration de chaque formulaire génère ce code à partir de vos champs.
<form action="https://airmess.fr/api/submit/{token}" method="post">
<label>Nom
<input type="text" name="nom" required>
</label>
<label>Email
<input type="email" name="email" required>
</label>
<label>Message
<textarea name="message" required></textarea>
</label>
<!-- Anti-spam : champ piège invisible, ne pas le supprimer -->
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">
<button type="submit">Envoyer</button>
</form> Après l'envoi, le navigateur est redirigé vers l'URL de votre choix : renseignez « URL de redirection après envoi » (onglet Intégration, https:// obligatoire), par exemple une page « Merci » de votre site. Sans URL, AirMess affiche une page de confirmation simple. En cas d'erreur (champ manquant, trop de requêtes…), une page explicite est affichée à la place, sans redirection.
L'URL de redirection est enregistrée dans la configuration du formulaire et n'est jamais lue dans la requête : un champ _redirect envoyé par un visiteur est ignoré.
Le champ _gotcha est un piège à robots : masqué, un visiteur ne le remplit jamais. S'il est rempli, la soumission est écartée sans envoyer d'email, mais reste visible dans le tableau de bord avec le statut REJECTED. Le robot, lui, reçoit une réponse de succès et ne cherche pas à contourner le piège. Ce champ est actif pour tous les formulaires, avec ou sans CAPTCHA.
Appel JavaScript (fetch)
Utile pour garder l'utilisateur sur la page (message de succès en ligne, application monopage). Envoyez un corps JSON (Content-Type: application/json) ; la réponse est aussi en JSON et aucune redirection n'est effectuée. Un envoi FormData est également accepté : seuls les champs texte sont lus, les fichiers sont ignorés.
fetch('https://airmess.fr/api/submit/{token}', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
nom: 'Alice',
email: 'alice@exemple.fr',
message: 'Bonjour !'
})
})
.then(r => r.json())
.then(data => console.log(data.message))
.catch(err => console.error(err)); En cas de succès, la réponse est 200 { "message": "Email envoyé avec succès." }.
Formulaire hébergé
Vous n'avez pas de site pour y intégrer l'URL de soumission ? AirMess peut générer une page de formulaire prête à l'emploi, hébergée directement sur https://airmess.fr. Activez l'option depuis l'onglet Intégration de la configuration du formulaire : une URL de la forme https://airmess.fr/form/{token} est alors générée.
Cette page n'est pas personnalisable, à l'exception de trois éléments, tous facultatifs :
| Élément | Détail |
|---|---|
| Titre | Affiché en haut de la page. Le nom du formulaire est utilisé si aucun titre n'est renseigné. |
| Texte d'introduction | Affiché sous le titre, avant les champs du formulaire. |
| Image | Affichée au-dessus du titre. Formats acceptés : PNG, JPEG, WebP, GIF — 2 Mio maximum. Dimensions recommandées : 400 × 96 px (une image plus grande est réduite à l'affichage, sans être déformée). |
Les champs affichés et leur ordre suivent la configuration du formulaire (voir Champs ci-dessous) ; le type de chaque champ détermine le clavier proposé sur mobile et la validation native du navigateur (adresse email, numéro de téléphone…).
La page s'adapte automatiquement au thème clair ou sombre du système d'exploitation ou du navigateur du visiteur — il n'y a pas de bascule manuelle à configurer.
Si le formulaire est désactivé ou l'option désactivée, l'URL répond 404, comme pour un token de soumission inconnu.
Champs
Lors de la création du formulaire, vous définissez une liste de champs attendus. Chaque champ a une clé (name) qui doit correspondre exactement à la clé envoyée dans le corps JSON.
| Propriété | Description |
|---|---|
name | Clé attendue dans le corps JSON (ex : email, message) |
label | Libellé affiché dans l'email reçu |
required | Si coché, la soumission retourne 400 si le champ est absent ou vide |
type | Texte, Email, Téléphone ou Zone de texte. N'affecte que le rendu du formulaire hébergé (clavier mobile, validation native) — sans effet si vous intégrez votre propre HTML. |
Les clés supplémentaires présentes dans le JSON mais non déclarées comme champs sont quand même incluses dans l'email.
Destinataires
Chaque adresse email destinataire doit être vérifiée avant de pouvoir recevoir des soumissions : un email de confirmation contenant un lien de vérification lui est envoyé automatiquement dès qu'elle est ajoutée à un formulaire. La vérification est portée par votre compte : une adresse déjà vérifiée sur un autre de vos formulaires n'a pas besoin d'être revérifiée.

Un formulaire sans aucune adresse destinataire vérifiée est traité comme inactif : son URL de soumission répond 404, même si le formulaire est marqué actif dans l'interface. Si certaines adresses sont vérifiées et d'autres non, les soumissions ne partent que vers les adresses vérifiées.
Un formulaire compte 10 destinataires au maximum. Les emails de vérification ne partent qu'une fois l'adresse de votre compte confirmée (lien reçu à l'inscription), et comptent dans un quota de 30 emails par jour et par compte, partagé avec les invitations d'organisation.
Le lien de vérification expire au bout de 24 heures. Vous pouvez renvoyer l'email de vérification depuis la page du formulaire ; un délai minimum de 60 secondes est imposé entre deux renvois pour la même adresse.
Pour un formulaire appartenant à une organisation, la vérification reste rattachée au compte propriétaire du formulaire, et non à celui du membre qui le modifie : une adresse vérifiée par le propriétaire l'est pour toute l'organisation.
Organisations
Par défaut, vos formulaires sont personnels : vous seul y avez accès. Une organisation permet à plusieurs comptes de gérer les mêmes formulaires. Tous les membres d'une organisation ont exactement les mêmes droits sur ses formulaires : consulter, modifier, activer, désactiver, supprimer et voir l'historique d'envois.
Espaces de travail
Le sélecteur d'espace en haut de page bascule entre votre espace Personnel et chacune de vos organisations. La liste des formulaires n'affiche que ceux de l'espace sélectionné. Un formulaire créé alors qu'une organisation est active lui est directement rattaché.
Vous pouvez appartenir à plusieurs organisations en même temps ; vos formulaires personnels restent privés dans tous les cas.

Rôles
| Rôle | Droits |
|---|---|
| Administrateur | Le créateur de l'organisation. Seul à pouvoir inviter et retirer des membres, transférer l'administration et supprimer l'organisation. Dispose aussi des droits de membre sur les formulaires. |
| Membre | Gère les formulaires de l'organisation au même titre que l'administrateur, mais ne gère ni les membres ni l'organisation elle-même. Peut la quitter à tout moment. |

Inviter un membre
L'administrateur saisit une adresse email depuis la page de l'organisation. La personne reçoit un lien d'invitation valable 7 jours. Elle n'a pas besoin d'avoir déjà un compte : si elle n'en a pas, le lien la mène à l'inscription avec son adresse pré-remplie, et elle rejoint l'organisation dès son compte créé.
Une invitation ne peut être acceptée que par l'adresse à laquelle elle a été envoyée, et une seule fois.

Transférer un formulaire
Depuis la page d'un formulaire personnel, la section Organisation permet de le transférer à une organisation dont vous êtes membre. Son URL de soumission et ses statistiques sont conservées : les intégrations déjà en place continuent de fonctionner.

Ce transfert est définitif : un formulaire rattaché à une organisation ne peut plus en être détaché, et l'accès passe alors exclusivement par l'appartenance à cette organisation. Si vous la quittez, vous perdez l'accès au formulaire même si vous l'aviez créé.
Quitter ou supprimer une organisation
Un membre peut partir quand il le souhaite. L'administrateur, lui, doit d'abord transférer l'administration à un autre membre : une organisation ne reste jamais sans administrateur. Cette règle s'applique aussi à la suppression de votre compte.
Une organisation ne peut être supprimée que lorsqu'elle ne contient plus aucun formulaire — transférez-les ou supprimez-les d'abord. Cette contrainte évite de couper par mégarde des URLs de soumission utilisées en production.
Templates email
Par défaut, les emails sont générés à partir d'un template HTML intégré qui affiche les champs soumis sous forme de tableau label / valeur. Vous pouvez remplacer ce template par le vôtre dans la configuration du formulaire.
Les templates utilisent une syntaxe de placeholders simple (substitution de texte, sans langage d'expression exécutable) :
| Placeholder | Description |
|---|---|
{{data.nomDuChamp}} | Valeur brute d'un champ par sa clé (ex : {{data.email}}). La valeur est échappée HTML automatiquement. |
{{#fields}}...{{/fields}} | Bloc répété pour chaque champ déclaré sur le formulaire. À l'intérieur, {{label}} et {{value}} donnent le libellé et la valeur du champ courant. |
Exemple de template minimal :
<!DOCTYPE html>
<html>
<body>
<p>Nouveau message de {{data.nom}}</p>
<table>
{{#fields}}
<tr>
<th>{{label}}</th>
<td>{{value}}</td>
</tr>
{{/fields}}
</table>
</body>
</html>Deux templates indépendants peuvent être définis : un pour l'email envoyé aux destinataires, un pour l'email de confirmation envoyé à l'expéditeur. Si l'un ou l'autre est laissé vide, le template par défaut correspondant est utilisé.
Placeholders dans le sujet
Le sujet de l'email — celui envoyé aux destinataires comme celui de la confirmation expéditeur — accepte les mêmes placeholders {{data.nomDuChamp}} : un sujet Nouveau message de {{data.nom}} arrive avec la valeur soumise à la place du placeholder. Le bloc {{#fields}}...{{/fields}}, lui, n'a pas de sens dans un sujet et y est ignoré.
Deux différences avec le corps du message : la valeur n'est pas échappée en HTML (un sujet n'est pas du HTML), et le sujet final est ramené à 200 caractères, les retours à la ligne étant remplacés par des espaces. Un champ absent ou vide donne un placeholder vide — pour un sujet toujours renseigné, appuyez-vous sur un champ requis.
Confirmation expéditeur
Vous pouvez activer l'envoi automatique d'un email de confirmation à la personne qui a soumis le formulaire. Pour cela, configurez dans votre formulaire :
- Confirmation expéditeur activée — active la fonctionnalité
- Champ email expéditeur — la clé (
name) du champ qui contient l'adresse email de l'expéditeur (ex :email) - Sujet et template HTML optionnels pour personnaliser l'email

Par défaut, cet email est un simple accusé de réception : il ne recopie pas les réponses du visiteur. L'adresse qui le reçoit est saisie dans le formulaire, par n'importe qui ; recopier les réponses permettrait d'envoyer un texte de son choix à une adresse quelconque depuis votre formulaire. Un template personnalisé peut les inclure ({{data.nomDuChamp}}), en connaissance de cause.
Si le champ désigné est absent ou vide lors de la soumission, la confirmation est simplement ignorée — la soumission reste un succès.
Une erreur SMTP sur la confirmation n'affecte pas le statut de la soumission : l'email aux destinataires est considéré comme la finalité principale.
| Cas | Résultat |
|---|---|
| Confirmation désactivée | Aucun email de confirmation envoyé |
| Champ email absent ou vide | Confirmation ignorée silencieusement, soumission SUCCESS |
| Champ email présent et valide | Email de confirmation envoyé à l'expéditeur |
Si le champ email n'est pas marqué requis, la confirmation ne sera pas envoyée lorsque l'expéditeur ne le remplit pas.
Origines autorisées
Par défaut, toute origine peut soumettre un formulaire. Si vous configurez une whitelist, AirMess vérifie l'en-tête HTTP Origin de chaque requête.
Cette restriction empêche un autre site d'intégrer votre formulaire dans les pages qu'il sert à ses visiteurs. Elle ne constitue pas une authentification : un script hors navigateur choisit librement son en-tête Origin. Contre les envois automatisés, activez plutôt un CAPTCHA.
| Cas | Résultat |
|---|---|
| Whitelist vide | Toutes les origines sont acceptées |
| Origin dans la whitelist | 200 — soumission acceptée |
| Origin absente ou non autorisée | 403 { "error": "Origine non autorisée." } |
Les navigateurs envoient automatiquement l'en-tête Origin pour tout fetch cross-origin. Les requêtes sans Origin (ex : scripts serveur, curl) sont bloquées dès qu'une whitelist est configurée.
Format attendu : URL complète avec protocole et domaine, sans slash final.
✓ https://monsite.fr
✓ https://www.monsite.fr
✗ monsite.fr (pas de protocole)
✗ https://monsite.fr/ (slash final)Ce filtre n'est pas un contrôle d'accès. L'en-tête Origin n'est envoyé que par les navigateurs et peut être falsifié trivialement par un script (curl, un appel serveur à serveur, etc.). La whitelist bloque l'intégration accidentelle ou abusive de votre formulaire depuis un autre site web dans un navigateur ; elle ne protège pas contre un attaquant déterminé qui appelle directement l'API. Combinez-la avec un CAPTCHA si vous devez limiter qui peut réellement soumettre le formulaire.
CAPTCHA
AirMess supporte hCaptcha et reCAPTCHA v2. La vérification est effectuée côté serveur : vous fournissez votre clé secrète dans la configuration du formulaire, et AirMess contacte l'API du fournisseur à chaque soumission.
La clé secrète est chiffrée au stockage et n'est plus jamais réaffichée : une fois enregistrée, le champ reste vide. Laissez-le vide pour conserver la clé actuelle, saisissez une nouvelle valeur pour la remplacer.
Côté client, intégrez le widget CAPTCHA dans votre page HTML. Dans un formulaire HTML classique, le widget ajoute lui-même son token au formulaire (champs h-captcha-response ou g-recaptcha-response) : rien d'autre à faire. Pour un envoi par fetch, transmettez le token généré par le widget dans le corps JSON sous la clé captcha-token.
{
"nom": "Alice",
"email": "alice@exemple.fr",
"captcha-token": "TOKEN_GÉNÉRÉ_PAR_LE_WIDGET"
}hCaptcha
<!-- Dans votre <head> -->
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
<!-- Dans votre formulaire -->
<div class="h-captcha" data-sitekey="VOTRE_SITE_KEY"></div>Récupérez la clé publique (site key) et la clé secrète sur hcaptcha.com.
reCAPTCHA v2
<!-- Dans votre <head> -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<!-- Dans votre formulaire -->
<div class="g-recaptcha" data-sitekey="VOTRE_SITE_KEY"></div>Récupérez vos clés sur google.com/recaptcha.
| Cas | Résultat |
|---|---|
| CAPTCHA désactivé | Aucune vérification effectuée |
| Token CAPTCHA absent | 400 { "error": "Token CAPTCHA manquant." } |
| Token invalide ou expiré | 403 { "error": "Vérification CAPTCHA échouée." } |
| Token valide | La soumission continue normalement |
Rate limiting
Deux limites s'appliquent à chaque soumission :
- 5 soumissions par minute et par adresse IP, compteur partagé entre tous les formulaires ;
- 60 soumissions par heure et par formulaire, toutes adresses IP confondues : un réseau de robots restant chacun sous la limite par IP ne peut pas inonder vos destinataires.
En cas de dépassement, la réponse est 429 { "error": "Trop de requêtes. Veuillez réessayer dans quelques instants." }, avec un en-tête Retry-After indiquant en secondes le délai avant la prochaine tentative possible.
L'adresse IP retenue est celle que voit le proxy frontal d'AirMess : un en-tête X-Forwarded-For ajouté par le client lui-même n'est pas pris en compte.
Limites et conservation
AirMess est gratuit. Aucun quota mensuel n'est appliqué à ce jour ; les limites ci-dessous servent à protéger le service contre les abus. Toute évolution de ces limites ou de la gratuité sera annoncée avant son entrée en vigueur.
| Limite | Valeur |
|---|---|
| Débit de soumission | 5 par minute et par adresse IP, tous formulaires confondus, et 60 par heure et par formulaire (voir Rate limiting) |
| Destinataires | 10 adresses maximum par formulaire |
| Emails de vérification et d'invitation | 30 par jour et par compte, une fois l'adresse du compte confirmée |
| Taille d'une requête | 256 Kio maximum |
| Conservation des soumissions | 12 mois, puis suppression automatique du contenu et de l'historique d'envoi |
| Export | Les soumissions et les statistiques d'un formulaire s'exportent en CSV depuis sa page de suivi, à tout moment |
Pensez à exporter les soumissions que vous souhaitez garder plus longtemps que 12 mois.
Délivrabilité des emails
Les emails de notification partent d'un domaine authentifié par SPF, DKIM et DMARC : ils ne sont pas envoyés depuis l'adresse de vos visiteurs, ce qui les ferait rejeter comme usurpation.
Le champ Reply-To est renseigné automatiquement avec l'adresse du visiteur, tirée du premier champ de type Email dont la valeur est valide : « Répondre » dans votre messagerie écrit directement à la personne qui a rempli le formulaire.
Si vous configurez votre propre serveur SMTP (onglet SMTP du formulaire), la délivrabilité dépend alors de votre domaine : publiez-y des enregistrements SPF, DKIM et DMARC, et utilisez une adresse d'expéditeur de ce domaine.
Un email absent de votre boîte de réception ? Vérifiez d'abord vos courriers indésirables, puis l'historique du formulaire : une soumission SUCCESS signifie que le message a bien été remis au serveur d'envoi. Une soumission marquée FAILED indique l'erreur remontée par votre serveur SMTP si vous en avez configuré un ; avec le serveur d'AirMess, le motif affiché reste générique, le détail étant réservé à l'équipe d'exploitation.
Codes de retour
| Code | Signification |
|---|---|
200 | Email envoyé avec succès |
202 | Soumission acceptée, envoi toujours en cours après quelques secondes (relais SMTP lent) — se termine en arrière-plan, la soumission reste consultable dans le tableau de bord une fois résolue |
303 | Formulaire HTML classique : redirection vers l'URL configurée après un envoi réussi |
400 | Champ requis manquant ou token CAPTCHA absent — le corps contient la liste des champs manquants |
403 | Origine non autorisée ou vérification CAPTCHA échouée |
404 | Token de formulaire inconnu, formulaire désactivé, ou aucun destinataire vérifié |
413 | Corps de requête supérieur à 256 Kio |
415 | Type de contenu non pris en charge : utilisez un formulaire HTML classique (application/x-www-form-urlencoded), un FormData (multipart/form-data) ou du JSON (application/json) |
429 | Rate limit dépassé pour cette IP ou pour ce formulaire — l'en-tête Retry-After indique le délai d'attente |
500 | Erreur d'envoi SMTP — la soumission est enregistrée avec le statut FAILED |