El canal Custom no publica en una red. Envía cada publicación programada, como JSON, a una URL que tú controlas, y lo que ocurra después depende de tu código.
Úsalo para un CMS al que Ocoya no se conecta, un generador de sitios estáticos, una cola interna de revisión o cualquier cosa que prefieras construir antes que esperar.
Conectar un endpoint

El formulario de conexión. El panel junto a los campos es el contrato de respuesta: un 2xx y la dirección a la que enlazar.
Abre Channels
Selecciona Channels en la barra lateral izquierda y después Connect channel.
Elige Custom
Elige Custom en el panel Add a connection.
Ponle un nombre
Dale un nombre que reconozcas en la lista de canales, como Mi blog. Es solo una etiqueta.
Introduce tu URL de publicación
La URL completa, incluido el esquema: https://example.com/hooks/content. Tiene que ser accesible desde los servidores de Ocoya, así que una dirección de tu propio equipo o de una red privada no funcionará.
Si tu sitio redirige (de example.com a www.example.com, o de http a https), sirven ambas formas. Ocoya sigue la redirección después de comprobar la nueva dirección igual que comprobó la primera.
Opcional: añade una URL de eliminación
En Advanced options. Una segunda dirección, que se usa cuando se elimina una publicación en Ocoya: https://example.com/hooks/content/delete. Si la dejas vacía, eliminar una publicación en Ocoya la deja donde se publicó.
Tiene que ser una URL distinta de la anterior. Tu endpoint de publicación crea algo con POST; si la eliminación fuera al mismo sitio, crearía una segunda copia en cualquier receptor que no compruebe el nombre del evento.
Opcional: añade cabeceras
También en Advanced options. La mayoría de los endpoints quieren saber que la solicitud es tuya antes de aceptarla: añade Authorization con el valor Bearer your-token, o la cabecera que compruebe tu receptor. Cada una se envía con todas las solicitudes, a ambas URL.
Sin una cabecera de autorización, la URL es la única credencial: cualquiera que la conozca puede publicar en tu endpoint. Añade una o, como mínimo, usa una ruta larga e imposible de adivinar.
Los valores de las cabeceras se guardan igual que las credenciales y nunca se devuelven al navegador, así que el formulario de conexión muestra una sección Headers vacía incluso para un destino que las tiene. Al reconectar la misma URL se sustituye todo el conjunto: vuelve a introducir todas las cabeceras que quieras conservar.
Qué recibe tu endpoint
Un POST con Content-Type: application/json. Lleva lo que necesita un blog y nada más:
{
"event": "post.published",
"publishedAt": "2026-09-17T09:00:00.000Z",
"post": {
"id": "clx…",
"title": "Three labels, one warmer palette",
"caption": "Testing a softer set of creams…",
"image": "https://…/image.jpg"
}
}| Campo | Qué es |
|---|---|
post.id | El id de Ocoya para esta publicación. No cambia si se reintenta una entrega, así que úsalo como clave para actualizar en lugar de publicar una segunda copia |
post.title | El título, o null si no se ha definido ninguno |
post.caption | El cuerpo, exactamente como se redactó. Markdown si escribiste Markdown |
post.image | La primera imagen de la publicación, como una URL que descargar: descárgala, no la enlaces directamente. null si no hay ninguna. Los vídeos no se envían |
post.options | Campos de artículo, cuando la publicación los tiene. Se enumeran más abajo |
Dentro de post.options
Solo los artículos los tienen: los escritos por una campaña de blog. Una publicación hecha a mano no los tiene, y options se omite por completo. Trata todos los campos como opcionales.
| Campo | Tipo | Qué es |
|---|---|---|
markdownMode | boolean | true cuando post.caption es Markdown. Renderízalo en consecuencia |
slug | string | Un slug apto para URL derivado del título: why-your-content-is-not-converting. Puedes usarlo o ignorarlo |
excerpt | string | Un resumen de una o dos frases, para una tarjeta o un feed |
seoTitle | string | Hasta 70 caracteres, para <title> |
seoDescription | string | Hasta 200 caracteres, para <meta name="description"> |
tags | string[] | Etiquetas del artículo. Normalmente una |
readingMinutes | number | Calculado a partir del cuerpo terminado |
Un artículo llega así:
{
"event": "post.published",
"publishedAt": "2026-09-22T09:00:00.000Z",
"post": {
"id": "clx…",
"title": "Why your content is not converting",
"caption": "You're posting every day and still refreshing an empty inbox.\n\n## The three pillars\n\n- A clear offer, repeated\n- One place to send people\n",
"image": "https://…/cover.png",
"options": {
"markdownMode": true,
"slug": "why-your-content-is-not-converting",
"excerpt": "Volume is rarely the problem. Nothing you publish asks anybody to do anything.",
"seoTitle": "Why your content is not converting",
"seoDescription": "Volume is rarely the problem. Here is the system that fixes it.",
"tags": ["content-marketing"],
"readingMinutes": 7
}
}
}post.caption es Markdown cuando markdownMode es true. Si lo publicas sin renderizarlo, aparecerá ## The three pillars en tu sitio tal cual se escribió, que es justo lo que parece.
¿Necesitas algo que no está aquí? Cuéntanoslo. Los campos se añaden cuando un receptor los necesita, no se envían por si acaso.
Eliminar una publicación
Eliminar una publicación en Ocoya la elimina en las redes a las que fue. Un destino personalizado es tu sistema, así que Ocoya solo puede avisarle, y lo hace enviando un POST a la delete URL, si indicaste una.
El cuerpo es otra vez la publicación publicada, con tres añadidos: el nombre del evento, las marcas de tiempo y, el único campo que necesitas, el id que tu endpoint devolvió al publicar.
{
"event": "post.deleted",
"id": "9f2c1a",
"publishedAt": "2026-09-22T09:00:00.000Z",
"deletedAt": "2026-09-28T14:12:00.000Z",
"post": {
"id": "clx…",
"title": "Why your content is not converting",
"caption": "…",
"image": null,
"options": { "slug": "why-your-content-is-not-converting" }
}
}Elimina por id: el identificador que tu endpoint devolvió al publicar, devuelto tal cual en el nivel superior para que no haya que extraerlo de una dirección. La url que devolviste no se envía: un endpoint que elimina por su propio id no necesita una dirección que ya conoce.
Si no hay ninguna URL de eliminación configurada, no se envía nada. La publicación se elimina en Ocoya y el canal indica que su copia sigue activa, en lugar de no hacer nada sin avisar.
Responde con cualquier 2xx, igual que en una publicación. Si la publicación ya no existe en tu lado, responde 404 o 410 y Ocoya la registra como ya eliminada en lugar de como un fallo. Cualquier otra respuesta se indica en la publicación, y la publicación se elimina en Ocoya de todos modos: que un destino se niegue nunca es motivo para conservar una publicación que pediste eliminar.
Qué espera recibir Ocoya
Responde con cualquier estado 2xx. Cualquier otra respuesta se registra como una publicación fallida, y el estado y el cuerpo de la respuesta se muestran en la publicación para que veas qué dijo tu endpoint.
Devuelve un id y una url
Tu endpoint debe responder con ambos, como JSON:
{
"id": "9f2c1a",
"url": "https://yourblog.com/post"
}| Campo | Qué es | Qué hace Ocoya con él |
|---|---|---|
id | Tu propio identificador de lo que acabas de crear: un id de fila, un id de documento | Lo devuelve a tu URL de eliminación como id. Es por lo que eliminas. |
url | La dirección en la que publicaste | Se convierte en el enlace View post de la publicación |
Ambos son obligatorios. Un 2xx sin ellos se registra como una publicación fallida, y el mensaje lo indica en la publicación, incluido que el contenido puede existir ya en tu destino, por lo que volver a publicar a ciegas crearía una segunda copia.
url es la única clave que se lee para la dirección: permalink se aceptaba como sinónimo en versiones anteriores y ya no.
Devuelve ambos en la misma respuesta. Ocoya los lee una sola vez, cuando tu endpoint responde; no hay ninguna devolución de llamada para enviarlos después, así que un endpoint que pone el trabajo en cola tiene que conocer su id y su dirección final antes de responder, no después.
Tu endpoint tiene 30 segundos para responder. Haz el trabajo lento después de responder, no antes: confirma la solicitud y luego procésala.
Una redirección se sigue en lugar de tratarse como un fallo, siempre que la dirección a la que apunta supere la misma comprobación que la original: accesible públicamente y fijada a lo que resuelve. Se mantiene el método, así que tu endpoint sigue recibiendo un POST con el cuerpo. El límite es de tres saltos.
Límites
| Título | 300 caracteres |
| Cuerpo | 200 000 caracteres |
| Multimedia | 20 elementos |
| Tiempo de espera | 30 segundos |
| Cabeceras | Hasta 10, con valores de 2000 caracteres |
Detrás de un webhook no hay ningún proveedor, así que no hay nada real con lo que validar: el extremo receptor es tuyo y tú decides qué acepta. Son barreras de seguridad más que límites: lo bastante amplias para un artículo largo con su multimedia, y lo bastante estrechas para que una generación descontrolada se detecte en el compositor y no en tu endpoint.
Problemas habituales
“A destination URL must start with http:// or https://.” La URL no tiene esquema. Inclúyelo.
“”Content-Type” is set by Ocoya and cannot be overridden.” Algunas cabeceras describen la propia solicitud en lugar de autenticarla: las cabeceras de contenido, Host, Connection, Transfer-Encoding. Ocoya las define, así que tus propias cabeceras no pueden sustituirlas.
“”…” is not a valid header name.” Un nombre de cabecera son letras, dígitos y guiones. Un espacio o dos puntos en el campo del nombre suele significar que se pegó toda la línea Name: value en él: el nombre va en el campo izquierdo y el valor en el derecho.
“That is not a valid URL.” No se pudo interpretar la dirección. Comprueba si hay erratas o espacios sobrantes.
“Your endpoint could not be reached. Check the URL is correct and publicly accessible.” El DNS no se resolvió o se rechazó la conexión. Un endpoint en localhost o en una red privada no es accesible desde Ocoya.
“Your endpoint answered 200 but did not return id or url.” La solicitud llegó a tu endpoint y la aceptó, pero a la respuesta le faltaba uno de los campos obligatorios o ambos. Ocoya lo registra como una publicación fallida porque, sin un id, no hay nada por lo que eliminar más adelante.
Ten en cuenta que el contenido puede existir ya en tu destino: el endpoint sí respondió correctamente. Compruébalo antes de volver a publicar, o acabarás con dos copias.
“This destination has no delete endpoint.” Se eliminó una publicación en Ocoya y este canal no tiene URL de eliminación, así que no se envió nada y la copia en tu destino sigue ahí. Vuelve a conectar el destino con una URL de eliminación para cambiarlo.
“Your endpoint did not respond in time.” Tardó más de 30 segundos. Confirma primero, procesa después.
“Your endpoint redirected to https://…” La redirección salió de la dirección que indicaste: otro host u otro esquema que Ocoya no pudo volver a comprobar, o una que se resolvió a una dirección privada. Usa la dirección que responde directamente. Una redirección que se mantiene en una dirección accesible públicamente se sigue por ti, hasta tres saltos.
“Your endpoint returned 500: …” Tu código lanzó un error. Lo que aparece tras el estado es lo que devolvió tu endpoint, truncado.