Démarrage rapide des webhooks
Connecte GrowWriter à ton propre site web et fais livrer ton premier événement de test signé, sur une seule page, avec un seul fichier de code.
Dernière mise à jour le
Cette page t'amène de rien à Événement de test livré. Une stack, un fichier, zéro théorie. Quand le test passe, le guide te montre comment enregistrer les articles qui suivent, et la référence du payload liste tout ce qu'ils contiennent.
Cette page est pour la personne qui peut ajouter un fichier à ton site web et le déployer. Si ce n'est pas toi, envoie-lui ce lien ; ça lui prend un seul fichier. Le code est pour Next.js, la configuration derrière la plupart des sites Vercel et Netlify. Les autres stacks sont dans le guide ; les étapes de cette page restent les mêmes.
Connecte le webhook dans GrowWriter
Ouvre la page Publier, repère la carte Webhook dans le groupe Automatisation et clique sur Connecter.
Saisis l'adresse à laquelle le code répondra. Pour le fichier ci-dessous,
c'est le domaine de ton site suivi de /webhooks/growwriter, par exemple
https://www.example.com/webhooks/growwriter. Utilise l'adresse exacte que
ton site sert : s'il redirige example.com vers www.example.com, saisis
celle en www. Clique sur Créer la connexion.
La boîte de dialogue affiche maintenant ton Secret de signature, une
chaîne qui commence par whsec_. Clique sur Copier le secret. Il ne
s'affiche qu'une seule fois, garde donc la boîte de dialogue ouverte ou
colle-le en lieu sûr.
Ajoute le fichier récepteur
Crée ce fichier dans ton projet. Il lit chaque requête exactement telle qu'elle est arrivée, vérifie que GrowWriter l'a signée et répond à l'événement de test.
import { createHmac, timingSafeEqual } from 'node:crypto';
// Une requête signée plus vieille que ceci est rejetée, une requête
// capturée ne peut donc pas être rejouée plus tard.
const MAX_AGE_SECONDS = 5 * 60;
function isSignedByGrowWriter(rawBody: string, header: string, secret: string) {
// Le header ressemble à : t=1756718400,v1=5257a869e7...
const parts = Object.fromEntries(
header.split(',').map((part) => part.split('='))
);
const age = Math.abs(Date.now() / 1000 - Number(parts.t));
if (!(age < MAX_AGE_SECONDS)) {
return false;
}
// Recalcule l'empreinte sur "timestamp.corps" avec ton secret ENTIER
// (préfixe whsec_ inclus) et compare en temps constant.
const expected = createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
const provided = Buffer.from(parts.v1 ?? '', 'hex');
const wanted = Buffer.from(expected, 'hex');
return provided.length === wanted.length && timingSafeEqual(provided, wanted);
}
export async function POST(request: Request) {
// Lis le corps en texte d'abord. Le parser avant de vérifier la
// signature change les octets et la vérification échoue.
const rawBody = await request.text();
const signature = request.headers.get('x-growwriter-signature') ?? '';
const secret = process.env.GROWWRITER_WEBHOOK_SECRET ?? '';
if (!isSignedByGrowWriter(rawBody, signature, secret)) {
return new Response('Invalid signature', { status: 401 });
}
const payload = JSON.parse(rawBody);
// « Envoyer un événement de test » envoie un ping sans article dedans.
// Répondre 200, c'est ce qui fait réussir le test.
if (payload.event === 'ping') {
return new Response('pong');
}
// Un vrai article (ou sa suppression : article.unpublished ne porte que
// l'id). Pour l'instant, prouve juste qu'il est arrivé ; le guide montre
// comment l'enregistrer. Une fois enregistré, Response.json({ url }) avec
// l'URL publique du billet donne un lien « Voir l'article » à la boîte de
// dialogue de publication.
console.log(`${payload.event}: ${payload.article.id}`);
return new Response('OK');
}Donne le secret à ton site et déploie
Ton code lit le secret depuis une variable d'environnement : un réglage que ton hébergeur garde en dehors de ton code. Dans le tableau de bord de ton hébergeur (Vercel : Settings, puis Environment Variables), ajoute :
GROWWRITER_WEBHOOK_SECRET=whsec_colle_ton_secret_iciColle la valeur entière, whsec_ inclus. Puis déploie ton site pour que le
nouveau fichier et la nouvelle variable soient en ligne.
Envoie l'événement de test
De retour dans la boîte de dialogue GrowWriter, clique sur Envoyer un
événement de test. GrowWriter signe un petit ping et le poste à ton
adresse. Quand ton fichier répond, la boîte de dialogue affiche
Événement de test livré. Clique sur Terminé.
Si ça échoue, la boîte de dialogue nomme la raison. Les deux que tu as le plus de chances de voir :
- L'URL de ton endpoint redirige. Saisis l'adresse vers laquelle elle
redirige et réessaie : ton site répond à une autre adresse (en général
wwwcontre sanswww), et le message affiche laquelle utiliser. Clique sur Modifier l'URL sur la ligne du webhook pour la changer. - Ton endpoint a rejeté la livraison : avec un
401, le secret chez ton hébergeur ne correspond pas ; avec un404, le fichier n'est pas à l'adresse que tu as saisie.
Tout le reste est sur la page de dépannage.
Prouve que la vérification fonctionne
Facultatif, mais ça vaut une minute. Ce script signe un ping exactement comme GrowWriter le fait et l'envoie à ton site :
SECRET="whsec_colle_ton_secret_ici"
URL="https://www.example.com/webhooks/growwriter"
BODY='{"version":"2026-09-06","event":"ping","deliveryId":"9d2f7c1e-6a3b-4c8d-b5e0-1f2a3b4c5d6e","sentAt":"2026-09-01T09:30:00.000Z"}'
TIMESTAMP=$(date +%s)
SIGNATURE=$(printf '%s.%s' "$TIMESTAMP" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')
curl -X POST "$URL" \
-H "Content-Type: application/json" \
-H "X-GrowWriter-Event: ping" \
-H "X-GrowWriter-Delivery: 9d2f7c1e-6a3b-4c8d-b5e0-1f2a3b4c5d6e" \
-H "X-GrowWriter-Signature: t=$TIMESTAMP,v1=$SIGNATURE" \
--data "$BODY"Tu dois obtenir pong. Maintenant, change un seul caractère dans BODY et
relance : tu dois obtenir un 401. C'est ta vérification de signature qui
refuse une requête modifiée, et c'est tout l'intérêt.
Ce que tu as maintenant
Un endpoint public qui n'accepte que les requêtes signées par GrowWriter, et
une connexion qui affiche Connecté sur la page Canaux. Publier un
article le livrera à ce fichier sous forme d'événement article.published,
et la ligne console.log affichera son id dans les logs de ton hébergeur.
Ensuite : enregistre l'article
Le fichier ci-dessus se contente de logger l'article. Pour le stocker, lis Enregistre l'article dans ton CMS dans le guide : six règles courtes sur les ids, les dates, l'état publié, les mots-clés, les images et l'échappement, chacune apprise d'un vrai récepteur qui s'était trompé. Les exemples complets de récepteurs qui s'y trouvent appliquent les six.
Tu te demandes pourquoi la signature et le secret existent ? Le guide l'explique en quatre étapes simples.
Publier sur BaseHub
Connecte ton repository BaseHub pour que chaque article devienne une ligne d'une collection que ton site lit déjà. Sans code.
Publier avec des webhooks
Envoie chaque article publié dans GrowWriter directement vers ton propre site web. Configure l'intégration webhook étape par étape, avec du code prêt à l'emploi.