PostWharf
Programa y publica publicaciones en Instagram, TikTok, X, LinkedIn, YouTube, Facebook, Threads, Pinterest, Bluesky y Telegram desde cualquier cliente MCP, con un recibo de entrega por red.
Servidor MCP alojado
npx add-mcp 'https://mcp.postwharf.com/mcp'Se instala en Claude Code, Codex, Cursor y más
Documentación
Autenticación
Cada solicitud lleva una clave de workspace como token de portador. Las claves están limitadas a un solo workspace, por lo que una clave para una marca nunca puede publicar en otra. Créalas y revócalas en Configuración → Claves de API.
# every request
curl https://api.postwharf.com/v1/channels \
-H "Authorization: Bearer wf_live_..."
Nunca envíes una clave a un navegador. Las claves publican en tu nombre. Mantenlas en el lado del servidor, en una variable de entorno, y rota inmediatamente si una se filtra.
API REST
URL base https://api.postwharf.com/v1. JSON de entrada, JSON de salida.
GET/platforms
GET/channels
GET/connector-requests
POST/connector-requests
POST/media/upload-url
POST/media
GET/media
PATCH/media/:id
POST/posts
GET/posts
GET/posts/:id
PATCH/posts/:id
DELETE/posts/:id
GET/analytics
GET/events
Cada ruta, con sus parámetros y rechazos, está en la referencia de la API.
Cuatro conectores son solo de solicitud. Reddit, Discord, Snapchat y WordPress permanecen visibles, pero aún no pueden crear canales ni publicar. POST /connector-requests registra la demanda del workspace una vez por plataforma.
Crear una publicación
Selecciona cualquier conjunto de canales. Proporciona publish_at para programar, u omítelo para publicar de inmediato. Las anulaciones por canal permiten que una sola carga lleve un pie de foto diferente para cada red.
POST /v1/posts
{
"text": "Most founders think they have a marketing problem.",
"media": ["med_8f2a"],
"channels": ["ch_x_kevin", "ch_li_rm", "ch_ig_hs"],
"publish_at": "2026-08-18T09:00:00+04:00",
"overrides": {
"ch_x_kevin": { "text": "Short version for X →" }
}
}
Respuesta
{
"id": "post_31ba",
"status": "scheduled",
"deliveries": [
{ "channel": "ch_x_kevin", "status": "pending" },
{ "channel": "ch_li_rm", "status": "pending" }
]
}
Consulta GET /posts/:id o suscríbete a un webhook. Una vez publicada, cada entrega obtiene un url que apunta a la publicación en la red, y un url_state que explica por qué cuando no lo tiene: none (no se publicó nada en esa etapa), pending (se publicó y la dirección aún no se conoce, por lo que vale la pena preguntar de nuevo), o not_reported (se publicó y esa red no devuelve ninguna dirección).
El array media está ordenado. Los archivos se publican en el orden en que los listas, no en el orden en que se subieron, por lo que un carrusel llega tal como lo ensamblaste. Enviar media en PATCH /posts/:id reemplaza la lista completa, que también es la forma de reordenar una.
Preguntar qué acepta cada red
GET /platforms devuelve las reglas como datos: el límite de texto para cada red, el más corto que se aplica una vez que se adjunta un archivo, cuántas imágenes y videos puede llevar una publicación, las formas que publica y si esta implementación publica allí en absoluto. Cada número es aquel contra el que se escriben los rechazos, por lo que no hay nada que descubrir al hacer que una publicación sea rechazada.
GET /v1/platforms
{
"platforms": [
{ "platform": "x", "text_limit": 280, "caption_limit": 280,
"media": { "images": 4, "videos": 1, "mixed": false },
"post_types": ["feed", "long_form"], "publishes": "live", "measures": true }
],
"upload": { "available": true, "max_image_bytes": 26214400, "max_video_bytes": 536870912 }
}
Verificar una publicación antes de crearla
Envía dry_run: true y la llamada ejecuta todas las verificaciones que ejecuta la real y luego no escribe nada. Una publicación que sería rechazada se rechaza de manera idéntica, con el mismo cuerpo, para que un lote pueda validarse antes de que se ponga en cola el primero en lugar de descubrirse a mitad de camino. Una ejecución de prueba no gasta una clave de idempotencia y no cuenta contra tus publicaciones mensuales.
Los archivos que aún no has registrado se pueden describir con media_preview, por lo que un ensayo no cuesta ninguna subida. Se acepta solo en una ejecución de prueba.
POST /v1/posts
{
"text": "Most founders think they have a marketing problem.",
"channels": ["ch_x_kevin", "ch_ig_hs"],
"media_preview": [{ "kind": "video" }],
"dry_run": true
}
Ejecutar la misma llamada dos veces
Envía un encabezado Idempotency-Key y una repetición de la misma llamada devuelve la publicación que hizo la primera, con un 200 en lugar de un 201. Un lote que falla a mitad de camino se puede volver a ejecutar completo: las llamadas que ya se realizaron no cuestan nada y no crean nada.
POST /v1/posts
Idempotency-Key: sept-campaign-day-03-x
Guardar un borrador
Envía draft: true y la publicación se guarda sin enviarse. Un borrador es la única publicación que puede no tener canales todavía, porque la gente escribe primero y elige las redes después. No cuenta contra tus publicaciones mensuales hasta que se publica.
POST /v1/posts
{
"text": "Most founders think they have a marketing problem.",
"draft": true
}
Lee el cajón de vuelta con GET /posts?status=draft. Un estado no reconocido es un 422, no una lista vacía, por lo que un error tipográfico no puede leerse como "sin borradores".
Editar una publicación
PATCH /posts/:id cambia un borrador, o una publicación que aún no se ha publicado. Cada campo es opcional y omitir uno significa dejarlo solo, por lo que mover una hora no puede dejar el texto en blanco por omisión. Lo que se verifica es la publicación fusionada, no el parche: agregar un canal vuelve a verificar el texto contra el límite de esa red, y mover la hora lo vuelve a verificar contra el reloj.
PATCH /v1/posts/post_31ba
{
"publish_at": "2026-08-19T09:00:00+04:00",
"channels": ["ch_x_kevin", "ch_bs_kevin"]
}
Establecer draft: false es cómo se libera un borrador a la cola; draft: true devuelve una publicación programada al cajón. Una vez que una publicación ha comenzado a publicarse, está terminada, y la llamada se rechaza con 409 post_not_editable en lugar de aplicarse a medias. post_type es el único campo que no se puede parchear: una publicación mantiene la forma con la que se creó, y convertir silenciosamente una Story en una publicación de feed es la sustitución que esta API existe para prevenir.
Subir un archivo
No tienes que alojar nada. POST /media/upload-url toma un tipo de contenido y un recuento de bytes y devuelve una dirección PUT prefirmada más la dirección pública que tendrá el archivo. Envía los bytes directamente a ella — nunca pasan por la API — y la fila de medios vuelve en la misma respuesta, lista para nombrar en una publicación.
POST /v1/media/upload-url
{ "content_type": "video/mp4", "bytes": 18234112 }
{
"upload_url": "https://…",
"public_url": "https://media.postwharf.com/…",
"media": { "id": "med_8f2a" }
}
Ambos encabezados con los que se firmó la dirección prefirmada — Content-Type y Content-Length — deben enviarse en el PUT, y la longitud debe coincidir con el recuento de bytes que solicitaste.
POST /media es la otra mitad: un archivo que ya alojas, registrado por dirección. No obtiene la dirección por defecto. Pasa verify: true para que se verifique una vez, allí y entonces, para que un enlace que ha caducado se rechace mientras aún lo sostienes en lugar de cuatro semanas después como una publicación programada sin nada detrás.
Describir una imagen
POST /media y POST /media/upload-url ambos toman un alt opcional: una descripción del archivo, de hasta 2.000 caracteres. Una descripción de solo espacios en blanco se almacena como ninguna. GET /media la devuelve. Las redes que llevan una descripción por imagen la publican — en Bluesky se convierte en el texto alternativo de la imagen.
POST /v1/media
{
"url": "https://cdn.example.com/desk.jpg",
"kind": "image",
"alt": "Two people at a standing desk, mid-conversation."
}
Para agregar o cambiar una descripción más tarde, PATCH /media/:id con alt. Envía null para quitar la descripción. El campo es obligatorio en esta llamada — un cuerpo sin alt es un 422 alt_required en lugar de una no operación silenciosa.
PATCH /v1/media/med_8f2a
{ "alt": "Two people at a standing desk, mid-conversation." }
Servidor MCP
El conector expone tus canales a cualquier cliente MCP como herramientas. Una clave de workspace limita cada llamada a un solo workspace, por lo que un agente solo puede actuar sobre la marca que le entregaste — y si ejecutas varias marcas, eso significa una conexión por marca, cada una con su propia clave.
Apunta un cliente alojado a https://mcp.postwharf.com/mcp con tu clave de workspace.
Cómo se conecta cada cliente, qué hace cada herramienta y qué acepta cada red se detallan en la página del servidor MCP de redes sociales.
La forma más rápida de entrar es desde el panel de control. Agente y MCP te da un bloque con tu clave ya incluida: cópiala, pégala en tu agente como mensaje, y el agente se configura solo. El servidor luego le dice al agente cómo subir un archivo, publicar un video y ajustar un conjunto de imágenes a cada red, para que preguntes en palabras simples y haga ese trabajo por sí mismo.
get_workspace Qué marca alcanza esta clave, su plan y la zona horaria en la que programa
list_channels Cada canal conectado y su estado de token
describe_networks Qué acepta cada red: formas, recuentos de archivos, límites de texto, sus propios ajustes
connect_channel Adjuntar un canal al workspace
stage_upload Una URL de subida y una dirección pública para un archivo que acabas de hacer
upload_media Registrar una imagen o video que ya alojas, obtener un id de medio
describe_media Escribir o reemplazar el texto alternativo en un archivo ya registrado
create_post Publicar en uno o muchos canales
schedule_post Poner en cola una publicación para una hora determinada
schedule_many Poner en cola un lote — un mes de un calendario en una sola llamada
save_draft Escribir una publicación y dejarla para que una persona la apruebe
list_drafts Cada borrador en el workspace, guardado pero no en cola
update_post Editar un borrador o una publicación en cola antes de que se publique
publish_draft Enviar un borrador, o ponerlo en cola para una hora
get_status Estado de entrega, enlace permanente, texto de error
list_queue Qué está programado y cuándo
cancel_post Sacar algo de la cola
list_events El feed de recibos de entrega
health Si la API es accesible y a qué redes realmente publica
CLI
Ideal para cron, CI, un hook posterior a la exportación, un agente o memoria muscular. Cada comando, con las banderas para programación, ejecuciones de prueba y reintentos, está en la página de la CLI de redes sociales.
# authenticate once — or set POSTWHARF_API_KEY and skip this entirely
wharf auth --key wf_live_…
# what this key can do, before you queue a month of posts
wharf whoami
plan pro
posts 18 used of 1000, 982 left this month
# what each network takes, without sending a post to find out
wharf platforms
# a local file. It is uploaded for you; nothing needs hosting
wharf post "New reel" --to instagram,tiktok --media ./out/reel.mp4 --at "tue 9am"
# check it against every network first. Writes nothing, uploads nothing
wharf post "Same idea, two lengths" --to instagram,pinterest \
--text-for pinterest:"the short one" --dry-run
# re-run a batch that died halfway. The ones that landed cost nothing
wharf post "Day 3" --to x --idempotency-key sept-day03-x
# what happened this week
wharf status --since 7d --metrics
✓ 41 live ⚠ 1 retrying ✗ 0 failed
# and which of them worked
wharf analytics --days 7 --by post
# pipe a caption in
cat caption.txt | wharf post --to linkedin,x
Webhooks
Esta es la parte que todos los demás programadores omiten. Se te notifica cuando una publicación se publica y cuando falla, en lugar de descubrirlo una semana después.
{
"event": "delivery.failed",
"post": "post_31ba",
"channel": "ch_ig_hs",
"attempt": 3,
"error": "token_expired",
"action": "reconnect_required"
}
Eventos: delivery.succeeded, delivery.failed, delivery.retrying, channel.token_expiring, channel.disconnected.
token_expiring se dispara temprano. Las redes caducan los tokens OAuth cada 60–90 días. Recibes la advertencia antes de que el canal se apague, no después de una semana publicando en la nada.
Clientes de IA
C
Claude Code
Agrega el conector y tus canales se convierten en herramientas. Redacción, cola y estado funcionan desde la terminal.
M
Clientes MCP
Cualquier cliente que hable Streamable HTTP MCP puede conectarse al servidor alojado con una clave de workspace.
⏱
Cron y n8n
La CLI sale con código distinto de cero en caso de fallo, por lo que un trabajo programado falla de forma audible en lugar de silenciosa.
{ }
Tu propio código
REST simple con un token de portador. No se requiere SDK, aunque uno está en camino.
Límites y errores
No publicamos ningún límite de tasa por clave. El rendimiento de publicación está limitado por los propios límites de cada red, no por los nuestros, y hacemos cola contra ellos en lugar de fallar. El inicio de sesión, el registro y el restablecimiento de contraseña tienen límite de tasa por dirección y por cuenta.
| Código | Significado | Qué hacer |
|---|---|---|
| 401 | Clave incorrecta o revocada | Reemite en Configuración → Claves de API |
| 403 | La clave está limitada a otro workspace | Usa la clave de ese workspace |
| 409 | El canal necesita reconexión | Token caducado — vuelve a ejecutar OAuth |
| 422 | Contenido, plataforma o conector solo de solicitud no válido | Usa el código de error y la pista; connector_request_only significa solicítalo en su lugar |
| 429 | Límite de tasa | Retrocede; Retry-After está establecido |