Inicio rápido de webhooks
Conecta GrowWriter a tu propio sitio web y recibe tu primer evento de prueba firmado, en una sola página, con un solo archivo de código.
Última actualización el
Esta página te lleva de cero a Evento de prueba entregado. Un stack, un archivo, nada de teoría. Cuando la prueba funcione, la guía te enseña a guardar los artículos que vengan después, y la referencia del payload lista todo lo que contienen.
Esta página es para la persona que puede añadir un archivo a tu sitio web y desplegarlo. Si no eres tú, pásale este enlace; le lleva un solo archivo. El código es para Next.js, la base de la mayoría de los sitios en Vercel y Netlify. Los demás stacks están en la guía; los pasos de esta página no cambian.
Conecta el webhook en GrowWriter
Abre la página Publicar, busca la tarjeta Webhook en el grupo Automatización y haz clic en Conectar.
Introduce la dirección en la que responderá el código. Para el archivo de
abajo es el dominio de tu sitio más /webhooks/growwriter, por ejemplo
https://www.example.com/webhooks/growwriter. Usa la dirección exacta que
sirve tu sitio: si redirige example.com a www.example.com, introduce la
de www. Haz clic en Crear conexión.
El diálogo muestra ahora tu Secreto de firma, una cadena que empieza por
whsec_. Haz clic en Copiar secreto. Solo se muestra una vez, así que
deja el diálogo abierto o pégalo en un lugar seguro.
Añade el archivo receptor
Crea este archivo en tu proyecto. Lee cada petición exactamente como llegó, comprueba que GrowWriter la firmó y responde al evento de prueba.
import { createHmac, timingSafeEqual } from 'node:crypto';
// Una petición firmada más antigua que esto se rechaza, así que una
// petición capturada no se puede repetir más tarde.
const MAX_AGE_SECONDS = 5 * 60;
function isSignedByGrowWriter(rawBody: string, header: string, secret: string) {
// La cabecera tiene esta 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;
}
// Recalcula la huella sobre "timestamp.cuerpo" con tu secreto COMPLETO
// (prefijo whsec_ incluido) y compara en tiempo constante.
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) {
// Lee el cuerpo como texto primero. Parsearlo antes de comprobar la
// firma cambia los bytes y la comprobación falla.
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);
// "Enviar evento de prueba" manda un ping sin ningún artículo dentro.
// Responder 200 es lo que hace que la prueba tenga éxito.
if (payload.event === 'ping') {
return new Response('pong');
}
// Un artículo real (o su eliminación: article.unpublished solo lleva el
// id). Por ahora, solo demuestra que llegó; la guía enseña a guardarlo.
// Cuando lo guardes, Response.json({ url }) con la URL pública de la
// entrada le da al diálogo de publicación un enlace "Ver publicación".
console.log(`${payload.event}: ${payload.article.id}`);
return new Response('OK');
}Dale el secreto a tu sitio y despliega
Tu código lee el secreto de una variable de entorno: un ajuste que tu proveedor de hosting guarda fuera de tu código. En el panel de tu host (Vercel: Settings, luego Environment Variables) añade:
GROWWRITER_WEBHOOK_SECRET=whsec_paste_your_secret_herePega el valor completo, whsec_ incluido. Después despliega tu sitio para
que el archivo nuevo y la variable nueva estén en producción.
Envía el evento de prueba
De vuelta en el diálogo de GrowWriter, haz clic en Enviar evento de
prueba. GrowWriter firma un pequeño ping y lo envía a tu dirección.
Cuando tu archivo responde, el diálogo muestra Evento de prueba
entregado. Haz clic en Hecho.
Si falla, el diálogo indica el motivo. Los dos que más probablemente verás:
- La URL de tu endpoint redirige. Introduce la dirección a la que redirige
e inténtalo de nuevo: tu sitio responde en otra dirección (normalmente
wwwfrente a sinwww), y el mensaje muestra cuál usar. Haz clic en Editar URL en la fila del webhook para cambiarla. - Tu endpoint rechazó la entrega: con un
401, el secreto de tu host no coincide; con un404, el archivo no está en la dirección que introdujiste.
Todo lo demás está en la página de solución de problemas.
Demuestra que la comprobación funciona
Opcional, pero merece un minuto. Este script firma un ping exactamente como lo hace GrowWriter y lo envía a tu sitio:
SECRET="whsec_paste_your_secret_here"
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"Deberías recibir pong. Ahora cambia un carácter dentro de BODY y
ejecútalo otra vez: deberías recibir un 401. Esa es tu comprobación de
firma rechazando una petición manipulada, que es justo de lo que se trata.
Qué tienes ahora
Un endpoint público que solo acepta peticiones firmadas por GrowWriter, y una
conexión que aparece como Conectado en la página Canales. Publicar un
artículo lo entregará a este archivo como un evento article.published, y la
línea console.log mostrará su id en los logs de tu host.
Siguiente paso: guarda el artículo
El archivo de arriba solo registra el artículo en el log. Para almacenarlo, lee Guarda el artículo en tu CMS en la guía: seis reglas cortas sobre ids, fechas, estado de publicación, palabras clave, imágenes y escapado, cada una aprendida de un receptor real que se equivocó en ellas. Los ejemplos completos de receptor que hay allí aplican las seis.
¿Te preguntas por qué existen la firma y el secreto? La guía lo explica en cuatro pasos sencillos.
Publicar en BaseHub
Conecta tu repositorio de BaseHub para que cada artículo sea una fila en una colección que tu web ya lee. Sin código.
Publicar con webhooks
Envía cada artículo que publicas en GrowWriter directamente a tu propio sitio web. Configura la integración de webhooks paso a paso, con código listo para usar.