Posttar API

Posts

18 endpoints for posts, with parameters and a real response example.

GET/posts

List posts

Lists the workspace's posts: status, scheduled date, and the first words of the caption. Use it to find which post to act on next, since every other post endpoint needs its id. Filter by status, period, or project to narrow the search; without filters, returns the most recent.

ParameterInTypeDescription
statusquerystringComma-separated list of statuses to filter by.
fromquerystringISO date. Filters by scheduled date.
toquerystringISO date. Filters by scheduled date.
projectIdquerystring
limitqueryintegerDefault 25, max 100.
cursorquerystringOpaque cursor from a previous response's next field.

Response

{
  "posts": [
    {
      "id": "8c64bee5-f756-47b7-a64a-01f5db597202",
      "status": "draft",
      "scheduledFor": null,
      "textContent": "Seu nicho pode estar amplo demais sem você perceber. Quando a mensagem tenta alcançar todo mundo, ela deixa de ser memorável para qualquer pessoa.\nQual desses sinais aparece mai...",
      "projectId": "c85848ba-2881-4a2e-9bdd-841b26d07359",
      "contentFormat": "animated_audio",
      "theme": "Tres sinais de que o seu nicho esta amplo demais"
    },
    {
      "id": "a6eed866-eed5-4f60-b3a5-1aaba4bee2eb",
      "status": "draft",
      "scheduledFor": null,
      "textContent": "Your first SaaS customers probably aren’t waiting for an ad. They’re already dealing with a painful problem you can solve.\n\nStart with direct conversations and a simple offer. W...",
      "projectId": "c85848ba-2881-4a2e-9bdd-841b26d07359",
      "contentFormat": "animated_audio",
      "theme": "How to land your first 10 SaaS customers without spending on ads"
    }
  ],
  "next": "eyJjaGF2ZSI6IjIwMjYtMDktMTNUMDU6NTg6MzYuNDUyNTI4KzAwOjAwIiwiaWQiOiJhNmVlZDg2Ni1lZWQ1LTRmNjAtYjNhNS0xYWFiYTRiZWUyZWIifQ"
}
POST/posts202

Create a post, in any of the six formats

Creates a post from a theme and starts generating it. The format parameter picks which of the six formats to make, and defaults to carrossel. Every format costs 1 credit and takes on the order of a minute (the carousel: median 43s, p99 87s, measured in production). Fire-and-forget: responds 202 with state: "generating"; poll GET /posts/{id} for the outcome. The four formats in preview are refused with 403 unless the workspace has them enabled, and nothing is charged.

Answers 202. The work finishes in the background; poll GET /posts/:id for the outcome.

ParameterInTypeDescription
projectIdrequiredbodystring
themebodystringWhat the post is about, in the client's words.
formatbody"carousel" | "caption_reel" | "animated_audio" | "narrated_photos" | "premium_carousel" | "infographic"Which format to generate. Defaults to carrossel. Formats in preview (audio_animado, narrated_photos, carrossel_profissional, infografico) are refused with 403 unless the workspace has them enabled.
linkbodystringA URL to read before writing. When present, theme becomes the instruction for what to do with it. Only the carrossel format reads a link; any other format is refused.
GET/posts/{id}

Get a post, whatever its format

Returns one post in full, in any of the six formats. The envelope is always the same, format says which format it is, and content carries what belongs to that format: slides for the three carousel-shaped formats, the text blocks and look for caption_reel, the script and scenes for the two narrated ones. content is null while the post is still generating, which is a real state and not an error: read status to know.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.

Response

{
  "id": "e7869afa-d470-4e9b-a4c9-4c1936604a4b",
  "format": "carousel",
  "status": "draft",
  "projectId": "c85848ba-2881-4a2e-9bdd-841b26d07359",
  "workspaceId": "2bd5c04d-1dd4-456e-8704-9d7b84703fd0",
  "scheduledFor": null,
  "textContent": null,
  "mediaUrls": [
    {
      "url": "https://.../post-images/ai-edits/e7869afa-d470-4e9b-a4c9-4c1936604a4b/b14c1fbe-b6f0-4ae0-bfd0-b1aaaf67a52b.webp",
      "type": "image"
    }
  ],
  "content": {
    "slides": [
      {
        "id": "1663f551-6958-41f6-bedb-e4294a9ff9a9",
        "order": 0,
        "variant": null,
        "fields": [
          {
            "name": "profissional",
            "value": {
              "blocos": [
                {
                  "peso": "etiqueta",
                  "texto": "04 · USO"
                },
                {
                  "peso": "forte",
                  "texto": "Metricaas: mede se a galera realmente usa"
                }
              ],
              "destaque": ""
            }
          }
        ],
        "titleFont": null,
        "bodyFont": null,
        "colors": {
          "background": "#fff1e2",
          "text": "#1D2939",
          "brand": "#ff6e05"
        }
      }
    ]
  }
}
PATCH/posts/{id}

Update a post, whatever its format

Changes the caption and, on the formats that have one, the content inside the video: reel on caption_reel, narration on animated_audio and narrated_photos. Send only what changes; the caption is replaced in full and never merged. Sending reel on a post that is not a reel (or narration on one that is not narrated) is refused with the field name, never ignored. Only works before the post publishes.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
captionbodystringmax 2200 charsThe Instagram caption, replaced in full. Up to 2200 characters, the same ceiling Instagram has.
reelbodyobjectOnly on the caption_reel format: the three text blocks and the look of the video.
narrationbodyobjectOnly on animated_audio and narrated_photos: the spoken script and what is drawn over it. Changing script does NOT re-record the audio.
DELETE/posts/{id}

Delete a post

Permanently deletes the post. Irreversible.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
POST/posts/{id}/media

Replace a post's media

Replaces a single-image post's media with the given list. Does not apply to a carousel (its image is generated from its slides) or to a reel (its background video is replaced via POST /posts/{id}/clip). An empty list removes the media. Only works before the post publishes.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
mediarequiredbodyobject[]max 10 itemsThe full media list, at most 10 items (the Instagram carousel limit). An empty list removes the media.
POST/posts/{id}/schedule

Schedule a post

Schedules the post to publish on its own at a future date and time, or changes the date of a post already scheduled. Only works on a draft, a previously failed post, or one already scheduled: a post in flight (publishing, queued, generating) or already published cannot be rescheduled this way.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
whenrequiredbodystringISO 8601 with a timezone, in the future. Either Z or an offset like -03:00.
POST/posts/{id}/unschedule

Unschedule a post

Takes the post out of the schedule queue and returns it to draft, without deleting anything. Only works on a scheduled post.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
POST/posts/{id}/archive

Archive a post

Removes the post from the Posttar calendar without deleting it; reactivate brings it back. Does NOT remove anything from Instagram: an already published post stays published there.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
POST/posts/{id}/reactivate

Reactivate a post

Takes the post out of the archive and returns it to draft, ready to edit and schedule again. Only works on an archived post.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
POST/posts/{id}/publish202

Publish a post now

Publishes the post to Instagram right away. Fire-and-forget: responds 202 with the post in publishing state (median 38s, p99 61s, measured in production); poll GET /posts/{id} for the outcome. Irreversible.

Answers 202. The work finishes in the background; poll GET /posts/:id for the outcome.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
POST/posts/{id}/slides

Add a slide

Appends a new slide to the end of the carousel, inheriting the last slide's layout with placeholder text. Edit that text afterwards with PATCH /slides/{id}. Carousel only.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
layoutIdbodystringWithout it, inherits the layout of the post's last slide.
POST/posts/{id}/slides/order

Reorder slides

Changes the order of the carousel's slides. Send the complete list of slide ids in the new order; a missing or repeated id is rejected, because the order cannot have a gap.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
orderrequiredbodystring[]max 50 itemsThe complete list of slide ids, in the new order.
GET/posts/{id}/edit-budget

Get a post's image-edit budget

Returns how many AI image edits (POST /slides/{id}/reimagine) this post has used and how many remain, so a client can check before spending one (about $0.015 each, capped at 2 on the standard plan) instead of risking a call just to find the budget empty.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.

Response

{
  "used": 1,
  "cap": 2,
  "remaining": 1
}
GET/posts/{id}/clips

List a reel's available clips

Lists the background clips available to this reel from the project's video library: id and description of each, before choosing one with POST /posts/{id}/clip.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.

Response

{
  "clips": []
}
POST/posts/{id}/clip

Set a reel's background clip

Replaces the reel's background video with a clip from the project's video library. clipId must come from GET /posts/{id}/clips.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
clipIdrequiredbodystring
GET/posts/{id}/tracks

List a reel's available tracks

Lists the music tracks this reel can use: name, description, duration, which one is currently in use, and a link to listen to each, before choosing one with POST /posts/{id}/track.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.

Response

{
  "tracks": [
    {
      "id": "94917ea8-17e6-47de-a2df-c79146cb5771",
      "name": "Bad Bunny - MONACO (Instrumental) - TYPE",
      "description": null,
      "durationSeconds": 267.377778,
      "suggestedStartSeconds": 19,
      "url": "https://.../audio-tracks/posttar/bad-bunny-monaco-instrumental-type.mp3",
      "inUse": false
    },
    {
      "id": "b6bb3c6d-9324-4df2-aced-70a6aead9a55",
      "name": "INSONAMIA - Ronald Figo",
      "description": null,
      "durationSeconds": 181.36815,
      "suggestedStartSeconds": 15,
      "url": "https://.../audio-tracks/posttar/insonamia-ronald-figo.mp3",
      "inUse": false
    }
  ],
  "inUse": "fda25fc1-6f3f-4eb6-b7d5-c53501a8c077"
}
POST/posts/{id}/track

Set a reel's track

Sets, changes, or removes the reel's music. trackId must come from GET /posts/{id}/tracks; null mutes the reel. startSeconds picks which second of the track the reel's 7 seconds start from.

ParameterInTypeDescription
idrequiredpathstringOpaque id from a previous response.
trackIdrequiredbodystring | nullFrom GET /posts/:id/tracks. Null mutes the reel.
startSecondsbodynumberWhat second of the track the reel's 7 seconds start from.