Docs

Avvio rapido dei webhook

Collega GrowWriter al tuo sito web e ricevi il tuo primo evento di prova firmato, in una sola pagina, con un solo file di codice.

Ultimo aggiornamento il

Questa pagina ti porta da zero a Evento di prova consegnato. Un solo stack, un solo file, niente teoria. Quando la prova riesce, la guida ti mostra come salvare gli articoli che seguiranno, e il riferimento del payload elenca tutto ciò che contengono.

Questa pagina è per la persona che può aggiungere un file al tuo sito web e distribuirlo. Se non sei tu, mandale questo link; le basta un solo file. Il codice è per Next.js, la configurazione dietro la maggior parte dei siti su Vercel e Netlify. Gli altri stack sono nella guida; i passaggi di questa pagina restano gli stessi.

Connetti il webhook in GrowWriter

Apri la pagina Pubblica, cerca la scheda Webhook nel gruppo Automazione e fai clic su Connetti.

Inserisci l'indirizzo su cui risponderà il codice. Per il file qui sotto è il dominio del tuo sito più /webhooks/growwriter, per esempio https://www.example.com/webhooks/growwriter. Usa l'indirizzo esatto che il tuo sito serve: se reindirizza example.com a www.example.com, inserisci quello con www. Fai clic su Crea connessione.

La finestra ora mostra il tuo Secret di firma, una stringa che inizia con whsec_. Fai clic su Copia secret. Viene mostrato una sola volta, quindi tieni la finestra aperta o incollalo in un posto sicuro.

Aggiungi il file del ricevitore

Crea questo file nel tuo progetto. Legge ogni richiesta esattamente com'è arrivata, controlla che l'abbia firmata GrowWriter e risponde all'evento di prova.

app/webhooks/growwriter/route.ts
import { createHmac, timingSafeEqual } from 'node:crypto';

// Una richiesta firmata più vecchia di così viene rifiutata, quindi una
// richiesta catturata non può essere rimandata più tardi.
const MAX_AGE_SECONDS = 5 * 60;

function isSignedByGrowWriter(rawBody: string, header: string, secret: string) {
  // L'header ha questa forma: 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;
  }
  // Ricalcola l'impronta su "timestamp.corpo" con il tuo secret INTERO
  // (prefisso whsec_ incluso) e confronta in tempo costante.
  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) {
  // Leggi il corpo come testo per primo. Farne il parsing prima di
  // controllare la firma cambia i byte e il controllo fallisce.
  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);

  // "Invia evento di prova" manda un ping senza articolo. Rispondere 200
  // è ciò che fa riuscire la prova.
  if (payload.event === 'ping') {
    return new Response('pong');
  }

  // Un articolo vero (o la sua rimozione: article.unpublished porta solo
  // l'id). Per ora, dimostra solo che è arrivato; la guida mostra come
  // salvarlo. Quando lo salverai, Response.json({ url }) con l'URL
  // pubblico del post darà alla finestra di pubblicazione un link "Vedi
  // articolo".
  console.log(`${payload.event}: ${payload.article.id}`);
  return new Response('OK');
}

Dai il secret al tuo sito e distribuisci

Il tuo codice legge il secret da una variabile d'ambiente: un'impostazione che il tuo hosting provider conserva fuori dal codice. Nel pannello del tuo host (Vercel: Settings, poi Environment Variables) aggiungi:

Variabile d'ambiente
GROWWRITER_WEBHOOK_SECRET=whsec_incolla_qui_il_tuo_secret

Incolla il valore intero, whsec_ incluso. Poi distribuisci il tuo sito, così che il nuovo file e la nuova variabile siano online.

Invia l'evento di prova

Torna nella finestra di GrowWriter e fai clic su Invia evento di prova. GrowWriter firma un piccolo ping e lo invia al tuo indirizzo. Quando il tuo file risponde, la finestra mostra Evento di prova consegnato. Fai clic su Fatto.

Se fallisce, la finestra ne indica il motivo. I due che vedrai più probabilmente:

  • L'URL del tuo endpoint reindirizza. Inserisci l'indirizzo a cui reindirizza e riprova: il tuo sito risponde su un indirizzo diverso (di solito www contro senza www), e il messaggio mostra quale usare. Fai clic su Modifica URL nella riga del webhook per cambiarlo.
  • Il tuo endpoint ha rifiutato la consegna: con un 401, il secret sul tuo host non corrisponde; con un 404, il file non si trova all'indirizzo che hai inserito.

Tutto il resto è nella pagina di risoluzione dei problemi.

Dimostra che il controllo funziona

Facoltativo, ma vale un minuto. Questo script firma un ping esattamente come fa GrowWriter e lo invia al tuo sito:

send-test-ping.sh
SECRET="whsec_incolla_qui_il_tuo_secret"
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"

Dovresti ricevere pong. Ora cambia un solo carattere dentro BODY ed esegui di nuovo: dovresti ricevere 401. È il tuo controllo della firma che rifiuta una richiesta manomessa, ed è esattamente lo scopo.

Cosa hai adesso

Un endpoint pubblico che accetta solo richieste firmate da GrowWriter, e una connessione che mostra Connesso nella pagina Canali. Pubblicare un articolo lo consegnerà a questo file come evento article.published, e la riga console.log mostrerà il suo id nei log del tuo host.

Prossimo passo: salva l'articolo

Il file qui sopra registra soltanto l'articolo nei log. Per conservarlo, leggi Salva l'articolo nel tuo CMS nella guida: sei brevi regole su id, date, stato di pubblicazione, parole chiave, immagini ed escape, ognuna imparata da un ricevitore vero che le aveva sbagliate. Gli esempi completi di ricevitore che trovi lì le applicano tutte e sei.

Ti incuriosisce perché esistono la firma e il secret? La guida lo spiega in quattro passaggi semplici.

In questa pagina