Crear publicaciones
Una petición crea una publicación por cada cuenta de destino. Cada una es independiente, con su propia programación y su propio resultado; solo comparten un id de campaña.
https://antwork.io/api/v1/postsPermisowrite · publishPetición
curl https://antwork.io/api/v1/posts \
-H "Authorization: Bearer $ANTWORK_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"accounts": ["acc_linkedin", "acc_x"],
"text": "Shipped the API today.",
"scheduledFor": "2026-10-01T09:00:00Z"
}'Respuesta
La respuesta es 202 Accepted, nunca 200. Nada se publica dentro de la petición: la publicación se encola y un worker la envía, así que la respuesta dice qué se ha aceptado, no qué se ha publicado.
{
"object": "post_batch",
"campaignId": "b3f1...",
"posts": [
{
"object": "post_result",
"id": "pQ7x...",
"accountId": "acc_linkedin",
"platform": "linkedin",
"status": "accepted",
"reason": null,
"message": null,
"readiness": {
"characterCount": 22,
"characterLimit": 3000,
"overLimit": false,
"mediaRequired": false,
"settingsRequired": false,
"publishBlocker": null
},
"editUrl": "https://antwork.io/workspace/ws_1/compose?postId=pQ7x...",
"settingsUrl": "https://antwork.io/workspace/ws_1/compose?postId=pQ7x...&focus=settings"
},
{
"object": "post_result",
"id": null,
"accountId": "acc_x",
"platform": "x",
"status": "rejected",
"reason": "text_too_long",
"message": "@antwork: Text exceeds x character limit",
"readiness": null,
"editUrl": null,
"settingsUrl": null
}
]
}202 puede contener rechazos. Lee todas las entradas de posts, no solo el código de estado. Solo cuando no se acepta ninguna la respuesta es un 400, y el array viaja igualmente con ella.Una entrada por publicación
posts asigna una entrada a una publicación, así que cada una lleva su propio texto, hashtags, etiquetas, medios y ajustes. Los hashtags se añaden al texto donde la plataforma los publica (YouTube los guarda como etiquetas del vídeo). userTags etiqueta una página de empresa de LinkedIn ({"company": "https://www.linkedin.com/company/acme"}, con @Acme en el texto) o a personas en medios de Instagram ({"type": "photo_tag", "username": "acme", "x": 0.5, "y": 0.5}). Los medios tienen que ser archivos de la biblioteca de este espacio de trabajo; si no, la petición se rechaza con media_not_in_library. Más de una entrada forma una campaña.
{
"draft": true,
"posts": [
{ "accountId": "acc_linkedin", "text": "Shipped the API today. @Acme", "hashtags": ["buildinpublic"],
"userTags": [{ "company": "https://www.linkedin.com/company/acme" }] },
{ "accountId": "acc_youtube", "text": "How the API works", "media": ["https://firebasestorage.googleapis.com/..."],
"options": { "privacyStatus": "unlisted", "title": "The Antwork API in 60 seconds" } },
{ "accountId": "acc_pinterest", "text": "Ship notes", "media": ["https://firebasestorage.googleapis.com/..."],
"options": { "boardId": "1234567890" } }
]
}Qué le falta a una publicación
La entrada de cada publicación creada lleva readiness y dos enlaces al editor de Antwork. readiness.publishBlocker es el motivo por el que se rechazaría publicarla ahora mismo (en un borrador: media_required, tiktok_privacy_required, pinterest_board_required, etc.), o null. mediaRequired, settingsRequired, overLimit, characterCount y characterLimit explican por qué. editUrl abre la publicación en el editor y settingsUrl abre sus ajustes. Una entrada rechazada tiene los tres a null.
{
"object": "post_result",
"id": "pQ7x...",
"accountId": "acc_tiktok",
"platform": "tiktok",
"status": "accepted",
"reason": null,
"message": null,
"readiness": {
"characterCount": 42,
"characterLimit": 2200,
"overLimit": false,
"mediaRequired": false,
"settingsRequired": true,
"publishBlocker": "tiktok_privacy_required"
},
"editUrl": "https://antwork.io/workspace/ws_1/compose?postId=pQ7x...",
"settingsUrl": "https://antwork.io/workspace/ws_1/compose?postId=pQ7x...&focus=settings"
}Qué significa cada estado
accepted— creada y programada (o guardada, si es un borrador). Consulta el id para ver qué pasa.rejected— rechazada antes de escribir nada. No existe; corrigereasony vuelve a enviar.failed— se creó pero no se pudo programar. Existe y no va a salir.
Programación
Omite scheduledFor para publicar de inmediato. Indica una hora ISO 8601 para programar: hasta 30 días vista en Free, sin límite en los planes de pago. En Free, una hora posterior se rechaza con scheduled_for_too_far, y el error indica la última hora que admite. Una hora en el pasado se rechaza con scheduled_for_in_past.
Cuerpo de la petición
accountsstring[]posts. Ids de cuenta de GET /api/v1/accounts, como máximo 25. Se crea una publicación por cuenta.postsobject[]accounts: una entrada por publicación, como mucho 25. Cada una admite accountId (obligatorio), text, hashtags, goal, userTags, media y options. Nombra una cuenta dos veces para tener dos versiones en ella. No se combina con accounts, text, texts, media ni options.textstringtexts.textsobjecttext para esa cuenta. Úsalo cuando una plataforma necesite una versión más corta.mediastring[]GET /api/v1/media o POST /api/v1/media, o URLs de medios de Antwork, no cualquiera. Un archivo tiene que estar en tu biblioteca antes de adjuntarlo: añade primero un archivo externo con POST /api/v1/media. Una URL externa se rechaza con media_not_hosted, y un id desconocido con media_not_found, en lugar de aceptarse y fallar al publicar.scheduledForISO 8601draftbooleantrue crea un borrador y no envía nada, y solo necesita el permiso write. Cualquier otro valor crea una publicación que se enviará, lo que necesita publish.optionsobjectoptions.youtube.title). Consulta Opciones por plataforma. En posts, las options de cada entrada llevan directamente los ajustes de su plataforma.workspaceIdstringworkspace_required. Todas las cuentas deben pertenecer a él.campaignIdstringoptions de su entrada de posts[] (quién puede verla, cada interacción, la declaración de contenido comercial y userConsented: true cuando acepta la declaración de TikTok). Una publicación de TikTok que vaya a salir sin ellas se rechaza con tiktok_choices_needed, cuyo tiktokChoices lista las opciones actuales del creador para que tu interfaz pregunte. platform_not_available ya no se devuelve.Opciones por plataforma
Todo lo específico de una plataforma va en options, indexado por plataforma y aplicado a todas las cuentas de esa plataforma en la petición. Son los ajustes que ofrece el editor de Antwork, con los mismos valores y límites. Los ajustes de TikTok los elige el usuario en cada publicación, así que un options.tiktok de nivel superior se rechaza con tiktok_settings_need_the_creator: envíalos por publicación, en posts[].options.
| Plataforma | Acepta |
|---|---|
| x | threadParts |
firstComment | |
publishType, firstComment | |
| threads | firstComment |
publishType, postToGrid, coverUrl, firstComment | |
| youtube | privacyStatus, title, categoryId, madeForKids, containsSyntheticMedia, thumbnailUrl, tags, playlist, captions, firstComment |
| tiktok | no acepta opciones |
boardId, pinTitle, link | |
| bluesky | firstComment |
| discord | no acepta opciones |
| mastodon | firstComment |
| telegram | no acepta opciones |
| google_business | callToAction, callToActionUrl |
| slack | channel |
400 que nombra el campo, no una publicación que sale sin el ajuste que pediste.Idempotencia
Envía una cabecera Idempotency-Key en cada creación, para que un reintento no publique dos veces. Cómo se comporta la clave está en la página de Idempotencia. Idempotencia →
¿Algo no cuadra? Dinos cuál.