Docs

Solución de problemas de webhooks

Arregla un evento de prueba o una entrega fallidos por síntoma, con los mensajes exactos que muestra GrowWriter, qué significa cada uno y qué hacer.

Última actualización el

Cada entrada de abajo empieza por lo que ves, dice qué significa en palabras llanas y termina con la solución. Empieza por la primera entrada: casi todos los problemas de una primera conexión se resuelven encontrando el código de estado real.

Primero, encuentra el código de estado real

Qué hacer. Envía una petición de prueba sin firmar a tu endpoint desde tu propio ordenador y mira solo la línea de estado y la cabecera Location:

Comprueba qué responde de verdad tu endpoint
curl -sS -o /dev/null -D - -X POST \
  -H "Content-Type: application/json" -d '{}' \
  https://your-site.com/webhooks/growwriter | grep -iE "^(HTTP|Location)"

Cómo leer el resultado. La petición no va firmada, así que un 401 es la respuesta buena: tu endpoint está activo y rechaza las peticiones sin firmar, exactamente como debe.

RecibesSignifica
HTTP … 401 o 400Bien. El endpoint funciona y comprueba las firmas. Las peticiones firmadas funcionarán.
HTTP … 3xx + Location:Tu URL redirige. Usa la dirección de Location: en su lugar. Mira redirecciones.
HTTP … 404Ruta equivocada, o la ruta no está desplegada.
HTTP … 405La ruta existe pero no acepta POST.
HTTP … 500Tu código falló. Normalmente falta una variable de entorno (el secreto).
Error de conexión / timeoutDNS, firewall, o el sitio no es público.

Si recibes un 3xx, ejecuta el comando otra vez con la dirección de Location: hasta que recibas un 4xx. Esa dirección final es la que debes introducir en GrowWriter.

El evento de prueba falla con HTTP 301, 302, 303, 307 o 308

Qué ves. El diálogo muestra La URL de tu endpoint redirige. Introduce la dirección a la que redirige e inténtalo de nuevo, con el destino de la redirección en la línea de abajo.

Qué significa. Tu sitio respondió "ve allí en vez de aquí". Los navegadores lo siguen en silencio, así que tu sitio se ve bien cuando lo abres. GrowWriter nunca sigue una redirección: seguirla podría perder el cuerpo de la petición o romper la firma. Así que una redirección siempre cuenta como entrega fallida, y los tres intentos van a la URL exacta que introdujiste.

Las causas habituales:

CausaRedirección típica
example.com frente a www.example.comTu host redirige uno al otro. Usa aquel al que redirige.
http:// en lugar de https://http://… → https://…
Una barra final que tu framework añade o quita/webhook → /webhook/ o al revés
Un prefijo de idioma que tu framework añade/api/webhook → /en/api/webhook
Una URL de previsualización que se reasignó*.vercel.app → tu dominio de producción
Una regla de CDN o proxy ("Always use HTTPS", reglas de página)cualquiera de las anteriores

Solución. Copia la dirección del error (o de la cabecera Location: en la comprobación de arriba) e introdúcela como URL del endpoint. Si el diálogo de conexión sigue abierto, haz clic en Volver; si ya lo cerraste, haz clic en Editar URL en la fila del webhook de la página Canales. Las dos opciones conservan tu secreto de firma. Desconectar y volver a conectar, en cambio, crea un secreto nuevo que tendrías que actualizar en tu servidor.

"Tu endpoint no respondió a tiempo"

Qué significa. GrowWriter esperó 10 segundos una respuesta y se rindió. Cada uno de los tres intentos tiene sus propios 10 segundos.

Solución. Responde antes de hacer el trabajo lento. La guía describe dos patrones seguros: mantén el handler seguro de ejecutar dos veces y deja que un reintento termine el trabajo, o responde 200 primero y haz el trabajo pesado en un proceso en segundo plano. Mira ¿Y el límite de 10 segundos?.

"Tu endpoint rechazó la entrega"

Qué significa. Tu endpoint respondió con un estado que no es 2xx. El mensaje cita ese estado y los primeros 200 caracteres del cuerpo de tu respuesta, así que devuelve un motivo corto en texto plano desde tu handler y lo leerás directamente en el diálogo. El estado te dice dónde mirar:

  • 401 o 403: tu comprobación de firma dijo que no. Mira la firma nunca coincide.
  • 404: ruta equivocada. Compara la URL de GrowWriter con tu ruta.
  • 405: la ruta no acepta POST.
  • 413: tu servidor rechaza cuerpos tan grandes. Un artículo completo puede ocupar varios cientos de kilobytes. Mira payloads grandes.
  • 500: tu código falló. Revisa los logs de tu servidor; la causa más común es que falte la variable de entorno del secreto.

Falta "Ver publicación" o abre la página equivocada

Qué significa. El enlace es la URL que devolvió tu endpoint en el cuerpo de su respuesta 2xx, como {"url": "https://…"}. Responde con cualquier otra cosa y no hay enlace. GrowWriter no tiene otra forma de saber dónde puso tu sitio la entrada.

Solución. Devuelve la URL pública de la entrada desde tu handler una vez guardada la entrada. Tiene que ser una URL absoluta http o https; las rutas relativas y otros esquemas se ignoran. Mira La respuesta para conocer las reglas. Dos cosas que debes saber:

  • Si respondes 200 antes de crear la entrada (el patrón del trabajo en segundo plano), todavía no puedes saber su URL, así que el diálogo no muestra ningún enlace.
  • El enlace guardado se reemplaza en cada entrega exitosa. Si un enlace apunta a una dirección antigua, publica el artículo otra vez y la respuesta actual de tu endpoint lo reemplaza.

"La entrega falló tras varios intentos"

Qué significa. GrowWriter no pudo conectar con tu endpoint en ninguno de los tres intentos: falló el DNS, la conexión fue rechazada o el sitio no es accesible desde internet.

Solución. Comprueba que la URL está activa, usa https:// y es pública. Las direcciones de redes privadas y localhost están bloqueadas por seguridad. Para recibir eventos reales en tu máquina mientras desarrollas, usa un servicio de túnel (ngrok, cloudflared) e introduce la dirección HTTPS del túnel.

La URL se rechaza al conectar

GrowWriter comprueba la URL antes de guardarla. Los tres mensajes y su significado:

  • La URL del webhook debe usar HTTPS: solo se acepta https://.
  • La URL del webhook apunta a una dirección privada y no se puede usar: el nombre de host resuelve a una dirección de red local o privada (localhost, 10.x, 192.168.x y similares). Usa una dirección pública o un túnel.
  • La URL del webhook no es válida: la URL no se puede parsear, contiene un usuario o una contraseña, o su nombre de host no se puede resolver.

GrowWriter no comprueba si el endpoint responde en este punto. Para eso está Enviar evento de prueba.

La firma nunca coincide

Repasa esta lista en orden. Cada punto explica una clase entera de fallos:

  1. Verifica sobre el cuerpo sin procesar. Calcula la firma sobre los bytes exactos que recibiste, antes de cualquier parseo de JSON. Parsear y volver a serializar cambia los bytes.
  2. Usa el secreto completo. La clave es la cadena entera, prefijo whsec_ incluido.
  3. Comprueba la variable de entorno. Mismo nombre en tu código y en tu hosting, definida para el entorno que sirve el endpoint, y con un nuevo despliegue después de definirla.
  4. Comprueba la ventana de cinco minutos. Si el reloj de tu servidor va desfasado más de cinco minutos, todas las firmas parecen caducadas. Sincroniza el reloj.
  5. Compara el formato de la cabecera. X-GrowWriter-Signature es t=<segundos unix>,v1=<64 caracteres hex>, y la cadena firmada es "<t>.<cuerpo sin procesar>".

La prueba en local firma una petición igual que GrowWriter, así que puedes confirmar tu comprobación sin esperar una entrega real.

La prueba funciona pero los artículos reales fallan

Qué significa. El ping es diminuto. Un artículo real lleva su contenido tres veces (markdown, HTML y bloques) y suele ocupar unos cientos de kilobytes; los artículos largos pueden superar 1 MB. Los servidores y los frameworks suelen limitar los cuerpos JSON muy por debajo de eso.

Solución. Sube el límite de tamaño del cuerpo en la ruta (por ejemplo express.raw({ type: 'application/json', limit: '10mb' }); el valor por defecto de Express es 100 KB) y asegúrate de que tu lógica de guardado maneja el payload completo, no solo los campos que usó la prueba.

La prueba funciona, pero el primer artículo falla con un 500 en Vercel o Netlify

Qué significa. Tu handler escribe un archivo junto a tu código. Los hosts serverless montan ese directorio en solo lectura, así que la escritura lanza un error (EROFS) y el endpoint responde 500. La prueba funciona porque el ping responde antes de que ocurra ningún guardado.

Solución. Guarda el artículo en una base de datos, en la API de un CMS o en un almacenamiento de objetos en lugar de en un archivo local. Los ejemplos de Next.js y Express de la guía registran la entrada en el log exactamente por esta razón; sustituye la línea del log por tu llamada de almacenamiento. Si solo necesitas un archivo temporal, /tmp es escribible pero se vacía entre invocaciones.

Perdí mi secreto de firma

Qué significa. El secreto se muestra una sola vez, en el diálogo de conexión, y se guarda cifrado. GrowWriter no puede mostrarlo de nuevo.

Solución. Desconecta el webhook en la página Canales y vuelve a conectarlo. Eso crea un secreto nuevo y retira el anterior: actualiza la variable de entorno en tu servidor, vuelve a desplegar y después envía un evento de prueba.

El artículo está en línea en mi sitio, pero el panel de mi CMS muestra un error de validación

Qué ves. Algo como Key on object value "growwriterId" is not allowed, o un valor de fecha rechazado.

Qué significa. Tu endpoint guardó un campo que tu CMS no declara (normalmente el id de GrowWriter), o un valor en un formato que el campo no acepta (normalmente un timestamp completo en un campo de fecha sin hora).

Solución. Añade un campo propio para el id a tu modelo de contenido y convierte las fechas al formato que espera tu CMS. Las dos cosas se explican en Guarda el artículo en tu CMS.

Una entrada volvió a borrador sin avisar

Qué significa. El payload no tiene indicador de publicado. Si tu CMS trata un campo de borrador ausente como "borrador", la entrada solo está publicada hasta que alguien la guarda en el panel de administración.

Solución. Establece tú mismo el estado de publicación, de forma explícita, cuando gestiones article.published y article.updated. Mira la regla 3.

Mi build falla por un { o un < dentro del artículo

Qué significa. El texto del artículo contiene caracteres normales como {, } y <. Si compilas el markdown con MDX, JSX o un motor de plantillas, esos caracteres se leen como código.

Solución. Guarda el markdown como datos y renderízalo con un renderizador de Markdown, o escapa esos caracteres antes de compilar. content.html ya viene escapado y es seguro para insertarlo directamente. Mira la regla 6.

Las imágenes son enormes, faltan o sus URLs cambiaron

  • Enormes: las imágenes llegan a su resolución original y pueden superar los 10 MB. Redimensiónalas y comprímelas al descargarlas.
  • Faltan: coverImage se omite cuando el artículo no tiene portada; images es un array vacío cuando no hay imágenes interiores. Comprueba que la clave existe antes de leerla.
  • URLs cambiadas: una imagen sustituida en el artículo recibe una URL nueva en la siguiente entrega. Las imágenes que no cambian conservan sus URLs.

Las tres cosas se tratan en la regla 5.

Recibí el mismo artículo dos veces

  • Mismo id de entrega: un reintento. Tu endpoint respondió tarde o con un error en el primer intento. Sáltate el trabajo que ya hiciste para ese id.
  • Id de entrega distinto, article.published otra vez: el artículo se publicó en una segunda conexión de webhook, o la primera conexión aún no tenía ninguna entrega exitosa. Haz upsert por article.id y la segunda copia sobrescribe la primera.

Eliminé un artículo en GrowWriter, pero sigue en mi sitio

Qué significa. Eliminar un artículo (o desconectar el webhook) envía article.unpublished con el id, el slug y el language del artículo, y nada más. Si tu handler trata todo evento que no es un ping como un artículo que guardar, o bien ignoró el evento o bien intentó guardar un artículo sin contenido y respondió 500.

Solución. Gestiona article.unpublished antes del guardado: busca la entrada por article.id y después ocúltala o elimínala, lo que prefiera tu sitio. Todos los ejemplos de receptor de la guía tienen esa rama. El evento sigue las reglas de entrega normales (tres intentos y después nada), así que si tu endpoint estaba caído en ese momento la entrada se queda; GrowWriter no reintenta más tarde.

El slug contiene caracteres no latinos, o no cambió con el título

El slug se deriva del título una sola vez, cuando se genera el brief. Los acentos latinos se eliminan (qué → que), pero las letras de otros alfabetos se conservan, así que un título en japonés produce un slug en japonés: codifícalo con porcentajes antes de ponerlo en una URL. Nunca está vacío. Editar el título en el editor conserva el slug, así que la dirección de la entrada se mantiene estable; solo elegir un título nuevo en el writer produce un slug nuevo. Nunca uses el slug como nombre de archivo ni como clave; usa article.id y trata el slug como dato de presentación.

"Demasiadas solicitudes. Inténtalo más tarde"

Qué significa. Tu cuenta alcanzó un límite: 20 solicitudes de publicación por hora, o 60 eventos de prueba por hora. No se pierde nada. El artículo sigue en tu Biblioteca y la conexión queda como estaba.

Solución. Espera unos minutos y vuelve a publicar o a enviar el evento de prueba. Si publicas en varios canales a la vez, cada uno cuenta como una solicitud.

La fila del webhook dice "Sin verificar"

Qué significa. El endpoint nunca ha respondido a un evento de prueba ni a una publicación. GrowWriter comprueba la dirección al conectar, pero no la llama hasta que tú lo haces.

Solución. Haz clic en Enviar evento de prueba en la fila del webhook. Cuando tenga éxito, la fila pasa a Conectado. Si falla, empieza por la comprobación del estado y sigue con redirecciones o entrega rechazada. Publicar en un webhook Sin verificar está permitido, y la primera entrega con éxito también lo verifica.

¿Sigues atascado?

Escríbenos desde la aplicación e incluye: el id de entrega (de la cabecera X-GrowWriter-Delivery o del error), la hora del intento, el estado que devolvió tu servidor y la salida de la comprobación del estado. Con esas cuatro cosas normalmente podemos responder en un solo mensaje.

En esta página