postmatic

Posts

Create a post now or scheduled, understand every status, track it to completion, reschedule and cancel. Idempotency and automatic retries.

A post is the caption, the images and one or more target accounts. Each account is a target (platforms[]) with its own state; the post status is derived from its targets.

Creating

POST /v1/posts
curl -X POST https://api.uat.postmatic.dev/v1/posts \
  -H "x-access-key: pm_live_…" \
  -H "content-type: application/json" \
  -d '{
    "content": "Now live.",
    "platforms": [{ "platform": "instagram", "accountId": "int_…" }],
    "mediaItems": [{ "type": "image", "url": "https://cdn.example.com/photo.jpg" }],
    "scheduledFor": "2026-09-15T13:00:00-03:00",
    "idempotencyKey": "launch-2026-09-15"
  }'
FieldRequiredDescription
contentnoCaption, up to 2,200 characters. Applies to every target unless overridden.
platforms[]yes1 to 5 targets, no repeated accountId. Each: platform (instagram), accountId, optional content (caption override for that account).
mediaItems[]yes1 to 10 items. Each one has type (image or video) and either url (https) or mediaId from Media. One item publishes to the feed (image) or as a Reel (video). Two or more items, images and videos mixed, become a carousel — all with the same aspect ratio.
platformSpecificDatanoInstagram options, inside each entry of platforms[]. An unknown field answers 400.
publishNownotrue publishes right away. Do not combine with scheduledFor.
scheduledFornoISO 8601 date with Z or an offset, between 1 minute and 75 days ahead.
timezonenoIANA zone (America/Sao_Paulo), stored with the post for display. Does not change the instant of scheduledFor.
idempotencyKeynoUp to 128 characters. See below.
profileIdnoAssociates the post with a profile of the project.

One of publishNow: true or scheduledFor is required. publishNow: false without scheduledFor is rejected.

Response

The API answers 202 and returns the post in its initial state. Publishing happens in the background, even with publishNow.

Response 202
{
  "success": true,
  "postId": "post_…",
  "status": "scheduled",
  "idempotencyKey": "launch-2026-09-15",
  "content": "Now live.",
  "scheduledFor": "2026-09-15T16:00:00.000Z",
  "timezone": null,
  "profileId": null,
  "platforms": [
    {
      "platform": "instagram",
      "accountId": "int_…",
      "targetId": "tgt_…",
      "status": "pending",
      "platformPostId": null,
      "platformPostUrl": null,
      "errorCode": null,
      "errorMessage": null,
      "attemptCount": 0
    }
  ],
  "mediaUrls": ["https://…/media/…jpg"],
  "createdAt": "2026-09-08T14:00:00.000Z",
  "updatedAt": "2026-09-08T14:00:00.000Z"
}

Before accepting, Postmatic validates the accounts (they exist, are connected, token alive), downloads and validates images given by URL, and checks each account's publishing quota with Meta. Any problem comes back as a synchronous error: 404 NOT_FOUND, 409 TOKEN_INVALID, 400 MEDIA_INVALID, 409 RATE_LIMIT_ACCOUNT.

Instagram options

Go in platformSpecificData, inside each entry of platforms[].

FieldApplies toDescription
contentTypeimage or video"story" publishes as a Story: one item only, no caption (Meta ignores text so we refuse content), Business accounts only. No other option works alongside it.
shareToFeedvideofalse publishes only to the Reels tab, without showing up in the profile grid. Defaults to true.
coverUrlvideoAn https URL of an image for the Reel cover. Needs to be reachable at publish time.
thumbOffsetvideoMillisecond of the video to use as the cover. Ignored when coverUrl is present.
audioNamevideoName of the audio track shown on the Reel, up to 100 characters.
collaboratorsvideo and imageUp to 3 accounts invited as co-authors. Each one needs to accept on Instagram.
Post with video
{
  "content": "Behind the scenes of the new collection.",
  "platforms": [{
    "platform": "instagram",
    "accountId": "int_…",
    "platformSpecificData": { "shareToFeed": true, "thumbOffset": 1500 }
  }],
  "mediaItems": [{ "type": "video", "url": "https://cdn.example.com/reel.mp4" }],
  "publishNow": true
}

Story

Story of a 9:16 image
{
  "content": "",
  "platforms": [{ "platform": "instagram", "accountId": "int_…", "platformSpecificData": { "contentType": "story" } }],
  "mediaItems": [{ "type": "image", "url": "https://cdn.example.com/story.jpg" }],
  "publishNow": true
}

Stories disappear from the profile in 24 hours and don't show up on the grid. Response and tracking are the same as for a normal post; platformPostUrl is set while the Story is live. Creator accounts answer 403 PLATFORM_NOT_AVAILABLE.

Images and videos can go together in mediaItems. Carousel video is limited to 60 seconds and 100 MB (different from Reels), and all items must have the same aspect ratio — Instagram crops everything to match the first item's ratio, so the API refuses a difference of over 1% with MEDIA_INVALID, reason: aspect and details.position pointing to the item.

Idempotency

Send a unique idempotencyKey per post (the id of your own record, for instance). If the request is repeated with the same key, the API returns 200 with the original post and does not create another; the body of the repeat is ignored. The key never expires. Without idempotencyKey, Postmatic generates one and returns it in the response.

Status

Post statusMeaning
scheduledScheduled, waiting for its time.
pendingAccepted and waiting for the queue (immediate publish, or a schedule whose time has come).
publishingAt least one target is in progress.
publishedEvery target published.
partialSome published, others failed.
failedEvery target failed, was cancelled or missed its time.
draftNo targets. Not created by the API today.

Each target in platforms[] has a finer state:

Target statusMeaning
pendingWaiting for its time.
queuedIn the publishing queue.
creating_container, awaiting_container, publishingPublishing steps on Meta.
publishedPublished. platformPostId and platformPostUrl are set.
failedFailed after exhausting retries. errorCode and errorMessage explain.
missedThe time passed more than 30 minutes ago without publishing starting (prolonged outage).
cancelledCancelled by you. errorCode is CANCELLED.

Tracking

GET /v1/posts/:id
curl https://api.uat.postmatic.dev/v1/posts/post_… \
  -H "x-access-key: pm_live_…"

Poll every 15 to 30 seconds until the status is terminal (published, partial or failed). An immediate publish usually takes 30 seconds to 2 minutes; Meta processes the image before publishing. To avoid polling in a loop, register a webhook and receive the final event.

Automatic retries

Temporary Meta failures (instability, app-level limits) are retried on their own, with intervals of 1, 5, 15 and 60 minutes, up to 5 attempts. attemptCount shows which one it is on. Definitive errors (revoked account, rejected media, blocked content) are not retried and the target goes straight to failed.

Listing

GET /v1/posts
curl "https://api.uat.postmatic.dev/v1/posts?status=scheduled&limit=50" \
  -H "x-access-key: pm_live_…"
ParameterDefaultDescription
statusOne of the post statuses.
profileIdFilter by profile; "null" returns those without one.
limit201 to 100.
offset0How many to skip.
sortdescasc or desc, by creation date.

The response is { success, total, posts[] }, each post in the same shape as on creation.

Rescheduling

PATCH /v1/posts/:id
curl -X PATCH https://api.uat.postmatic.dev/v1/posts/post_… \
  -H "x-access-key: pm_live_…" \
  -H "content-type: application/json" \
  -d '{ "scheduledFor": "2026-09-16T13:00:00-03:00", "timezone": "America/Sao_Paulo" }'

Only for scheduled posts. Same window rules as creation. If any target already started, the response is 409 POST_NOT_CANCELLABLE.

Cancelling

DELETE /v1/posts/:id
curl -X DELETE https://api.uat.postmatic.dev/v1/posts/post_… \
  -H "x-access-key: pm_live_…"

Cancels the targets still pending. The post is not deleted: it stays in the history with status failed and errorCode: CANCELLED on each target. A post that already started publishing, or whose time has passed, answers 409 POST_NOT_CANCELLABLE. Nothing is removed from Instagram.

Retrying failed targets

POST /v1/posts/:id/retry
curl -X POST https://api.uat.postmatic.dev/v1/posts/post_…/retry -H "x-access-key: pm_live_…"

Reopens the targets in failed, missed or cancelled with the original caption and media; targets already published are left untouched. With no body, it publishes right away; with { "scheduledFor": "…", "timezone": "…" }, it schedules again. Answers 202 with the post. 400 when there is nothing to retry; 409 POST_NOT_CANCELLABLE if some target is still publishing.

Limits

  • Up to 10 images per post (2 to 10 become a carousel) and 5 accounts per request.
  • Caption up to 2,200 characters.
  • 100 posts per account every 24 hours, Meta's quota. Postmatic rejects with RATE_LIMIT_ACCOUNT when the quota is exhausted.
  • One video per post, published as a Reel. Stories and carousels with video are not accepted yet; see the Roadmap.
Posts — Postmatic Documentation