Démarrage rapide
Antisy vérifie qu’un envoi de formulaire vient d’un navigateur et non d’un programme. Vous posez une balise dans la page, le script met un jeton dans le formulaire à l’envoi, et votre serveur le fait vérifier par un appel.
État du service
Cette documentation décrit la version 1 de l’API. L’accès se fait pour l’instant sur liste d’attente, et l’hébergement en Suisse n’est pas encore en service : api.antisy.com répondra à la mise en service. Contenu relu contre le code de l’API le 4 octobre 2026.
Le principe
- Le navigateur charge le script d’Antisy, servi par
api.antisy.com. Il ne montre rien au visiteur. - À l’envoi d’un formulaire
POSTvers votre site, le script retient l’envoi le temps d’obtenir un jeton, le met dans un champ caché,antisy-token, puis reprend l’envoi. Vous n’écrivez pas de JavaScript pour ce cas. - Votre serveur reçoit le formulaire avec le jeton. Il l’envoie à
POST /v1/siteverify, avec votre secret. - La réponse dit
allowoudeny: le visiteur passe, ou non. Vous décidez de la suite.
Le navigateur ne parle jamais à /v1/siteverify : c’est une route pour votre serveur, qui n’envoie aucun en-tête CORS. Le secret ne va jamais dans une page.
Ce qu’il vous faut
- Un site déclaré dans le tableau de bord, avec les noms d’hôte de vos pages (voir noms d’hôte).
- Sa clé de site (32 caractères) : elle va dans la page, ce n’est pas un secret.
- Un secret de vérification (64 caractères) : il reste sur votre serveur, dans une variable d’environnement. Il est montré une seule fois, à sa création (page sur les clés).
- Des pages servies en HTTPS.
Un exemple complet
1. La page
La balise dans le <head> et un formulaire ordinaire : ni champ caché ni script de votre côté. Remplacez VOTRE_CLE_DE_SITE.
<script src="https://api.antisy.com/v1/i/l.js"
data-site="VOTRE_CLE_DE_SITE" defer></script>
<form method="post" action="/contact">
<input name="name" autocomplete="name">
<input name="email" type="email" autocomplete="email">
<textarea name="message"></textarea>
<button>Envoyer</button>
</form>À l’envoi, le script d’Antisy retient l’envoi le temps d’obtenir le jeton (6 secondes au plus), crée le champ antisy-token, le remplit et relance l’envoi. Si le script est bloqué ou ne répond pas, le formulaire part quand même, sans le champ antisy-token : votre serveur le lit avec une valeur vide par défaut, comme l’exemple Node ci-dessous. La page sur le script dit ce qui se passe alors. Cet exemple couvre les formulaires POST vers votre propre site. Pour un envoi par fetch, un formulaire vers un sous-domaine ou une cible dans une autre fenêtre, voir quels formulaires sont couverts.
2. Le serveur, avec curl
Le secret et le jeton sont dans le corps de la requête, jamais dans un en-tête ; le secret passe par l’entrée standard, pas en argument. Le jeton est contrôlé avant l’appel. Délai de 3 secondes ; si Antisy ne répond pas, l’envoi passe.
#!/bin/sh
# ANTISY_SECRET : votre secret de vérification, dans l'environnement, jamais en dur.
# ANTISY_TOKEN : le champ antisy-token reçu avec le formulaire.
# Sortie 0 : accepté. Sortie 2 : refusé, ou envoi non vérifié.
LC_ALL=C
# 1. Un jeton présent doit avoir la forme d'un jeton : 1 à 2048 caractères ASCII imprimables.
# Sinon on n'appelle pas Antisy et on ne laisse pas passer.
if [ -n "$ANTISY_TOKEN" ]; then
case "$ANTISY_TOKEN" in
*[!\ -~]*) echo "Jeton mal formé, envoi non vérifié" >&2; exit 2 ;;
esac
if [ "$(( $(printf '%s' "$ANTISY_TOKEN" | wc -c) ))" -gt 2048 ]; then
echo "Jeton trop long, envoi non vérifié" >&2; exit 2
fi
fi
# 2. L'appel. Le secret passe par l'entrée standard : il n'apparaît pas dans la liste des processus.
body=$(printf 'secret=%s' "$ANTISY_SECRET" | curl -sS --max-time 3 -w '\n%{http_code}' \
https://api.antisy.com/v1/siteverify \
-d @- \
--data-urlencode response="$ANTISY_TOKEN")
curl_status=$?
http_code=$(printf '%s' "$body" | tail -n1)
# 3. On laisse passer seulement quand Antisy ne répond pas : panne réseau, délai dépassé, 5xx.
# Le 429 aussi, par défaut : voir la page sur la vérification avant de garder ce choix.
if [ "$curl_status" -ne 0 ] || [ "$http_code" -ge 500 ] || [ "$http_code" = 429 ]; then
echo "Antisy ne répond pas (curl $curl_status, HTTP $http_code), envoi laissé passer" >&2
exit 0
fi
# Tout autre statut d'erreur est un défaut de votre appel : à corriger, et jamais un laissez-passer.
if [ "$http_code" -ge 400 ]; then
echo "Requête refusée par Antisy (HTTP $http_code), envoi non vérifié" >&2
exit 2
fi
# 4. Réponse JSON compacte : grep suffit ici, utilisez un vrai lecteur JSON dans votre code.
if printf '%s' "$body" | grep -q '"success":true'; then
exit 0 # visiteur accepté
else
exit 2 # deny : refus générique, sans dire pourquoi
fi3. Le serveur, avec Node
La même chose avec fetch, sans dépendance. La fonction rend allow ou deny ; la page sur la vérification explique chaque cas, dont le 429, dont le traitement par défaut est un choix qui vous appartient.
// antisy.mjs : Node 22 ou plus, sans dépendance.
// Rend "allow" ou "deny".
// Antisy ne répond pas (réseau, délai, 5xx) : "allow". Tout le reste d'incertain : "deny".
// Le 429 est une décision qui vous appartient. "allow" par défaut, comme pour une panne ;
// pour un formulaire sensible, mettez "deny" (voir la page sur la vérification).
const ON_RATE_LIMIT = "allow";
export async function antisyVerdict(token) {
// 1. Un jeton présent doit avoir la forme d'un jeton : 1 à 2048 caractères ASCII imprimables.
// Sinon, on n'appelle pas Antisy et on ne laisse pas passer.
// Un champ vide ou absent (script bloqué) part comme une chaîne vide : Antisy le lit comme un jeton absent.
if (token && !/^[\x20-\x7e]{1,2048}$/.test(token)) {
console.warn("Jeton mal formé, envoi non vérifié");
return "deny";
}
let response;
try {
response = await fetch("https://api.antisy.com/v1/siteverify", {
method: "POST",
// fetch suit les redirections par défaut : une 3xx rejouerait le corps, secret compris, ailleurs.
// Ici elle est une erreur de votre appel (refusée plus bas).
redirect: "manual",
// Un corps URLSearchParams part en application/x-www-form-urlencoded.
body: new URLSearchParams({
secret: process.env.ANTISY_SECRET, // votre secret, jamais dans la page
response: token ?? "", // le champ antisy-token, tel que reçu
}),
signal: AbortSignal.timeout(3000), // au-delà de 3 s, Antisy ne répond pas
});
} catch (error) {
console.warn("Antisy injoignable, envoi laissé passer :", error.name);
return "allow";
}
if (response.status >= 500) {
console.warn("Antisy a répondu " + response.status + ", envoi laissé passer");
return "allow";
}
if (response.status === 429) {
console.warn("Antisy a répondu 429, décision : " + ON_RATE_LIMIT);
return ON_RATE_LIMIT;
}
if (!response.ok) {
// 400, 401, 413, 415... : le défaut est dans votre appel. À corriger, jamais un laissez-passer.
console.error("Antisy a refusé la requête (" + response.status + "), envoi non vérifié");
return "deny";
}
const result = await response.json().catch(() => null);
if (typeof result?.success !== "boolean") {
console.error("Réponse d'Antisy illisible, envoi non vérifié");
return "deny";
}
// Un secret absent ou refusé n'est pas une erreur HTTP : la réponse est un refus, à 200.
const codes = result["error-codes"] ?? [];
if (codes.includes("missing-input-secret") || codes.includes("invalid-input-secret")) {
console.error("Antisy refuse le secret : " + codes.join(", "));
}
// success est la seule acceptation : il vaut true si et seulement si verdict vaut "allow".
return result.success ? "allow" : "deny";
}import { antisyVerdict } from "./antisy.mjs";
// Dans le gestionnaire de votre formulaire, après l'analyse du corps :
const verdict = await antisyVerdict(body["antisy-token"]);
if (verdict === "deny") return refuse(); // refus générique, sans dire pourquoi
return accept();PHP, Python et Go ont leurs exemples sur la page vérifier un jeton. Pour le parcours complet, de la création du site à la mise en production, suivez le guide pas à pas.
Que faire du verdict
allow: le visiteur est accepté. Enregistrez ou publiez le message.deny: le visiteur ne passe pas. Refusez, sans dire pourquoi.
Il n’y a que ces deux issues, et la réponse ne dit jamais pourquoi : ni raison, ni score, ni seuil, dans aucun mode. Chaque raison rendue apprendrait à celui qui contourne ce qui l’a arrêté. Le visiteur, lui, ne voit rien de tout cela.
Un jeton est valable 60 secondes et ne se vérifie qu’une fois. Une panne d’Antisy ne doit jamais bloquer vos visiteurs : les deux exemples ci-dessus laissent passer l’envoi, et le journalisent, seulement quand Antisy ne répond pas (réseau, délai, erreur 5xx). Une erreur causée par votre requête ne laisse jamais passer.
À quel point refuser
Chaque site a un mode de vérification, qui se règle dans l’onglet Paramètres du tableau de bord. Il ne change que le moment où un visiteur douteux ne passe pas ; il n’y a ni curseur ni valeur à saisir.
- Strict
- Refuse plus tôt, au risque de gêner quelques vrais visiteurs.
- Équilibré
- Le réglage par défaut : un compromis entre les deux autres.
- Permissif
- Ne refuse que les cas nets, au risque de laisser passer davantage de robots.
Dans tous les modes, certains cas ne passent jamais : la liste est sur la page sur la vérification.
Ce que ce parcours couvre
L’appel décrit ici convient aux formulaires à faible enjeu : contact, lettre d’information. Il ne lie pas le jeton à un compte ; il ne convient donc pas à une connexion ou à une inscription. Pour celles-ci, le SDK Node (Express, Fastify, Next.js) sera publié sur npm avec sa documentation ; il n’est pas encore publié.
Les pages connexion et inscription disent ce que cet autre appel vérifie et où il en est ; les questions fréquentes résument le reste.
La suite
- Guide pas à pasDe la création du site à un formulaire protégé : huit étapes, ce qu’on doit observer à chacune, et que faire si un vrai visiteur est refusé.
- Le script navigateurLa balise, les formulaires couverts, antisy.token(), la politique CSP, les noms d’hôte, les navigateurs, si le script est bloqué.
- Vérifier un jetonLa requête, la réponse, les durées, les codes d’erreur, quand l’API ne répond pas, les exemples PHP, Python et Go, l’issue réelle.
- Clés et environnements de testClé de site, secret, création et révocation, clés de test et leur garde-fou.
- Données collectées et vie privéeCe que le navigateur envoie, ce qu’Antisy conserve, et pendant combien de temps.