Publish a post
Publishing is asynchronous: you create a publication, Warmup queues it and posts to each selected network, and you poll for the result.
What each network supports
Section titled “What each network supports”| Network | text |
photo |
story |
Text limit |
|---|---|---|---|---|
| yes | yes | yes | 63,206 | |
| — | yes | yes | 2,200 | |
| Threads | yes | yes | — | 500 |
A single publication can target 1–3 networks. Every network in the list must support the chosen kind.
-
Upload the image (skip for
kind: text). Up to 15 MB; Warmup converts it to JPEG.Terminal window curl -X POST https://api.warmup.social/projects/$PROJECT_ID/media \-H "Authorization: Bearer $WARMUP_TOKEN" \-F "file=@photo.jpg"{ "id": "6f1c…", "url": "https://…", "width": 1080, "height": 1350 }For the Instagram feed the aspect ratio must be between 4:5 (portrait) and 1.91:1 (landscape). Stories work best at 9:16.
-
Create the publication.
Terminal window curl -X POST https://api.warmup.social/projects/$PROJECT_ID/publications \-H "Authorization: Bearer $WARMUP_TOKEN" \-H "Content-Type: application/json" \-d '{"kind": "photo","platforms": ["instagram", "threads"],"text": "New collection is live","mediaId": "6f1c…"}'The API answers
202 Acceptedwith the publication and a target per network in statusqueued. -
Poll until every target is final.
Terminal window curl https://api.warmup.social/projects/$PROJECT_ID/publications/$PUBLICATION_ID \-H "Authorization: Bearer $WARMUP_TOKEN"Each target moves
queued→publishing→publishedorfailed. Poll every few seconds; most posts finish within a minute.
Polling example
Section titled “Polling example”const api = "https://api.warmup.social";const headers = { Authorization: `Bearer ${process.env.WARMUP_TOKEN}` };
async function waitForPublication(projectId, publicationId) { for (let attempt = 0; attempt < 40; attempt++) { const res = await fetch(`${api}/projects/${projectId}/publications/${publicationId}`, { headers }); const publication = await res.json(); if (publication.targets.every((t) => t.status === "published" || t.status === "failed")) { return publication; } await new Promise((resolve) => setTimeout(resolve, 3000)); } throw new Error("Publication is still in progress");}Result
Section titled “Result”A published target has permalink (link to the post), externalPostId and publishedAt. A failed target has errorCode:
errorCode |
What to do |
|---|---|
needs_reauth, connection_not_ready |
Reconnect the network (guide). |
media_rejected |
The network rejected the image — check size and aspect ratio. |
media_aspect_ratio |
The image doesn’t fit the Instagram feed. |
rate_limit |
The network’s own posting limit — try later. |
meta_unavailable |
Meta is temporarily unavailable — try later. |
published_unconfirmed |
Meta published the post but didn’t return its id. The post most likely went out — check the account before retrying. |
Schedule for later
Section titled “Schedule for later”A publication is a plan: state is scheduled by default, and without scheduledAt it goes out right away. Pass a future scheduledAt (ISO 8601 with offset) and the publication is sent at that moment, within about half a minute. timezone is the IANA zone you entered the time in — Warmup stores it to show the post in the planner at the right local time.
{ "kind": "photo", "platforms": ["instagram"], "mediaId": "6f1c…", "text": "Friday drop", "scheduledAt": "2026-11-06T18:00:00+02:00", "timezone": "Europe/Kyiv"}state: draftkeeps the publication in the planner without sending it. Drafts don’t need connected networks and may have no date at all.- Until a publication is sent (
stateisdraftorscheduled),PATCH /projects/{id}/publications/{publicationId}changes any field;scheduledAt: nullremoves the date,state: scheduledwithout a date sends it right away. After sending,PATCHanswers409 publication_dispatched. POST /projects/{id}/publications/{publicationId}/publishsends a draft or a scheduled publication right away.DELETE /projects/{id}/publications/{publicationId}removes it from the planner; a publication that is stillqueuedis cancelled.GET /projects/{id}/publications?from=…&to=…returns the planner window plus every draft without a date;statesummarises the per-network result (publishing,published,failed).
Rules and limits
Section titled “Rules and limits”textis required forkind: text;mediaIdis required forphotoandstoryand not allowed fortext.- Networks in
platformsmust be connected andactive, otherwise the API answers409withconnection_missingorconnection_not_ready. - Upload and publication requests share a limit of 30 per minute per user (
429above it). GET /projects/{id}/publicationswithoutfrom/tolists the 50 most recent publications.