Posts
A post is one piece of content published to one or more accounts. Every account you target gets its own result, so one post to Instagram and Facebook can succeed on one and fail on the other.
Endpoints
Section titled “Endpoints”| Method | Path | Body / query | Returns |
|---|---|---|---|
| POST | /v1/posts |
create body, see below. ?wait=true optional |
201 post |
| GET | /v1/posts |
query: workspace, status, from, to, external_ref, page, limit |
list |
| GET | /v1/posts/:id |
post | |
| PATCH | /v1/posts/:id |
any of caption, media, targets, schedule_at, options, external_ref |
post |
| DELETE | /v1/posts/:id |
204. Cancels a scheduled post, never deletes on the network |
|
| POST | /v1/posts/:id/publish |
?wait=true optional |
post. Publishes now |
Create
Section titled “Create”{ "workspace": "ws7k2m9p4q1r8t3", "caption": "Fresh cuts, Friday walk-ins welcome", "media": ["med9x2c4v6b8n1m"], "targets": ["acig4h2k5m7p9r1", "acfb8n2c4v6b1m3"], "schedule_at": "2026-09-01T09:00:00Z", "external_ref": "acme:post:1234", "options": { "instagram": { "media_type": "IMAGE", "first_comment": "#salon #friday", "share_to_feed": true }, "facebook": { "link": "https://salonnova.example/book" } }, "status": "draft"}| Field | Required | Notes |
|---|---|---|
workspace |
yes | The workspace that owns the targets and media |
caption |
yes for Facebook text posts, otherwise optional | The text. Can be overridden per target |
media |
Instagram: at least one. Facebook: optional | Media ids from this workspace, in display order. Two to ten images make an Instagram carousel |
targets |
yes, at least one | Account ids, or objects with a caption override, see below |
schedule_at |
no | ISO-8601 UTC. Present: the post is scheduled. Absent: it publishes now |
external_ref |
no | Your own id for this post. Comes back in every webhook and is filterable on GET /v1/posts |
options |
no | Per-network settings, see below |
status |
no | "draft" to save without publishing or scheduling |
What happens on create:
- No
schedule_atand nostatus: "draft": the post publishes immediately. The call returns at once withstatus: "publishing"; the outcome arrives by webhook or by polling. Add?wait=trueto hold the request for up to 25 seconds and get the final post back instead. schedule_atset: the post isscheduledand goes out at that time.status: "draft": the post is saved and nothing else happens until you patch aschedule_aton it or callPOST /v1/posts/:id/publish.
Validation runs before anything is stored. Targets must be active accounts in the workspace, media ids must exist in the workspace, and Instagram targets must have media. Failures return validation_error with field, or account_disconnected when a target cannot be used.
Targets with per-network captions
Section titled “Targets with per-network captions”targets accepts plain account ids, objects, or a mix. An object overrides the caption for that account:
{ "caption": "Fresh cuts, Friday walk-ins welcome. Book at the link.", "targets": [ { "account": "acig4h2k5m7p9r1", "caption": "Fresh cuts, Friday walk-ins welcome. Link in bio." }, "acfb8n2c4v6b1m3" ]}The Instagram target gets its own caption. The Facebook target uses the post-level caption.
Options
Section titled “Options”options is keyed by network and applies to every target on that network.
| Network | Option | Notes |
|---|---|---|
instagram |
media_type |
IMAGE, CAROUSEL or REELS. Derived from media when omitted: one image is IMAGE, several are CAROUSEL, a video is REELS |
instagram |
first_comment |
Posted as the first comment right after publishing. The usual place for hashtags |
instagram |
share_to_feed |
Reels only. true shows the Reel on the profile grid as well |
facebook |
link |
A URL to attach. With no media the post becomes a link post with a preview |
Unknown options are rejected with validation_error.
The wait flag
Section titled “The wait flag”POST /v1/posts?wait=true and POST /v1/posts/:id/publish?wait=true hold the request until the post is done or 25 seconds have passed. Images normally finish inside that window. Reels often do not: Meta processes the video first, and the response then comes back with status: "publishing". Treat publishing as “not finished yet” and rely on the webhook or a poll for the final state.
The post object
Section titled “The post object”{ "id": "pst5g7j9l2n4q6s", "workspace": "ws7k2m9p4q1r8t3", "external_ref": "acme:post:1234", "caption": "Fresh cuts, Friday walk-ins welcome", "media": [{ "id": "med9x2c4v6b8n1m", "kind": "image", "mime": "image/jpeg", "width": 1080, "height": 1350 }], "targets": [ { "account": "acig4h2k5m7p9r1", "network": "instagram", "username": "salonnova", "status": "published", "platform_post_id": "17900000000000001", "permalink": "https://www.instagram.com/p/C_abc123/", "error": null, "published_at": "2026-08-25T09:20:11Z" }, { "account": "acfb8n2c4v6b1m3", "network": "facebook", "username": "salonnova", "status": "failed", "platform_post_id": null, "permalink": null, "error": "(#200) The user hasn't authorized the application to perform this action", "published_at": null } ], "schedule_at": null, "status": "partial", "published_at": "2026-08-25T09:20:11Z", "attempts": 1, "last_error": "facebook: (#200) The user hasn't authorized the application to perform this action", "created_by": "api", "created": "2026-08-25T09:19:58Z", "updated": "2026-08-25T09:20:11Z"}| Field | Notes |
|---|---|
media |
The media objects, in order, as they were at creation |
targets[].status |
pending until the network answers, then published or failed |
targets[].platform_post_id, permalink |
Meta’s id and the public URL once published |
targets[].error |
Meta’s error text for a failed target |
status |
draft, scheduled, publishing, published, partial, failed or canceled. Lifecycle in Scheduling |
attempts |
How many publish runs the post has had |
last_error |
The most recent failure across targets, prefixed with the network |
created_by |
api, embed, dashboard or mcp |
GET /v1/posts with any of:
| Query | Notes |
|---|---|
workspace |
Filter to one workspace. Required with a partner key if you do not want the whole partner |
status |
One status |
from, to |
ISO-8601 bounds on schedule_at, falling back to created for posts without a schedule. This is what a calendar view uses |
external_ref |
Exact match on your id |
page, limit |
Pagination, default 50, max 200 |
curl "https://social.missless.tel/v1/posts?workspace=ws7k2m9p4q1r8t3&status=scheduled&from=2026-09-01T00:00:00Z&to=2026-09-30T23:59:59Z" \ -H "Authorization: Bearer $MISSLESS_API_KEY"PATCH /v1/posts/:id accepts caption, media, targets, schedule_at, options and external_ref. It works on posts in draft, scheduled or failed. Anything else returns conflict (409): a post that is publishing or already published cannot be edited through MissLess, and MissLess never edits on the network.
curl -X PATCH https://social.missless.tel/v1/posts/pst5g7j9l2n4q6s \ -H "Authorization: Bearer $MISSLESS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "schedule_at": "2026-09-02T09:00:00Z" }'Patching schedule_at onto a draft moves it to scheduled. Patching a failed post lets you fix the reason before calling publish again.
Delete
Section titled “Delete”DELETE /v1/posts/:id returns 204. On a scheduled post it cancels the schedule and the post shows canceled. On a draft it removes it. On a published post it removes only the MissLess record; the content stays on the network. Nothing is ever deleted on Facebook or Instagram through this API.
Publish now
Section titled “Publish now”POST /v1/posts/:id/publish publishes a draft, scheduled or failed post immediately. On a failed post it is a retry and increments attempts. Add ?wait=true to wait for the result.
curl -X POST "https://social.missless.tel/v1/posts/pst5g7j9l2n4q6s/publish?wait=true" \ -H "Authorization: Bearer $MISSLESS_API_KEY"