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

Cuadro de diálogo Connect a custom destination con los campos Name, Publish URL y Delete URL opcional a la izquierda, un panel gris a la derecha titulado What your endpoint should reply con un fragmento JSON que devuelve una url, y un botón Connect destination

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.

1

Abre Channels

Selecciona Channels en la barra lateral izquierda y después Connect channel.

2

Elige Custom

Elige Custom en el panel Add a connection.

3

Ponle un nombre

Dale un nombre que reconozcas en la lista de canales, como Mi blog. Es solo una etiqueta.

4

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.

5

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.

6

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"
  }
}
CampoQué es
post.idEl 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.titleEl título, o null si no se ha definido ninguno
post.captionEl cuerpo, exactamente como se redactó. Markdown si escribiste Markdown
post.imageLa 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.optionsCampos 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.

CampoTipoQué es
markdownModebooleantrue cuando post.caption es Markdown. Renderízalo en consecuencia
slugstringUn slug apto para URL derivado del título: why-your-content-is-not-converting. Puedes usarlo o ignorarlo
excerptstringUn resumen de una o dos frases, para una tarjeta o un feed
seoTitlestringHasta 70 caracteres, para <title>
seoDescriptionstringHasta 200 caracteres, para <meta name="description">
tagsstring[]Etiquetas del artículo. Normalmente una
readingMinutesnumberCalculado 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"
}
CampoQué esQué hace Ocoya con él
idTu propio identificador de lo que acabas de crear: un id de fila, un id de documentoLo devuelve a tu URL de eliminación como id. Es por lo que eliminas.
urlLa dirección en la que publicasteSe 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ítulo300 caracteres
Cuerpo200 000 caracteres
Multimedia20 elementos
Tiempo de espera30 segundos
CabecerasHasta 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.

Relacionado