Search

Search the docs…

API

REST API reference

A small, predictable JSON API with the same rules as the app and the MCP server. If you use an AI client, the MCP server covers everything here without keys.

Overview

https://postika.app/api/v1
Auth
Bearer API key or OAuth token. See Authentication.
Format
JSON in, JSON out. Successful responses wrap the result in { "data": … }; errors return { "error": "…" }.
project_id
Query parameter (or body field on POST). Optional with an API key or a single project; required for OAuth tokens that reach several projects.
IDs
UUIDs.
Dates
Project local time, YYYY-MM-DD HH:MM. No time zones in the payload.
CORS
Open (*), so you can call it from any origin. Never expose a key in client code.
Caching
Every response is Cache-Control: no-store.

List projects

GET/api/v1/projects

Projects this credential can reach. An API key always returns its own project; an OAuth token returns every project the user belongs to, oldest first, with the user's role. active says whether the project owner's subscription is active; if not, reason says what to do and the other endpoints answer 402 for that project.

curl "https://postika.app/api/v1/projects" \
  -H "Authorization: Bearer $POSTIKA_KEY"
200 OK
{
  "data": [
    {
      "id": "3f6a1d2e-7c41-4b8e-a0f5-9d2c8e1b7a63",
      "name": "Acme",
      "timezone": "Europe/Madrid",
      "role": "owner",
      "active": true,
      "reason": null,
      "subscription_status": "active"
    }
  ]
}

Account status

GET/api/v1/account

Plan, subscription status, trial end and renewal (only for the owner), channels used against the plan limit, role, whether the credential can publish directly or approve, pending approvals and a list of warnings with links. Works even when the subscription is inactive.

curl "https://postika.app/api/v1/account?project_id=3f6a1d2e-7c41-4b8e-a0f5-9d2c8e1b7a63" \
  -H "Authorization: Bearer $POSTIKA_KEY"

List channels

GET/api/v1/channels

Connected channels of the project. Channels that need to be reconnected are left out.

Query parameters
project_idstring
Required only for OAuth tokens with several projects.
Channel object
idstring
Use it in channel_ids.
networkstring
Instagram, TikTok, Facebook, YouTube, X, LinkedIn, Threads or Pinterest.
handlestring
Account username.
demoboolean
Demo channels simulate publishing without reaching the network.
max_charsinteger
Character limit of the network.
needs_mediaboolean
Whether the network requires a photo or video.
curl "https://postika.app/api/v1/channels" \
  -H "Authorization: Bearer $POSTIKA_KEY"
200 OK
{
  "data": [
    {
      "id": "8d0c6f8e-2b7a-4c1e-9f43-2f1d7a8b5c10",
      "network": "Instagram",
      "handle": "acme",
      "demo": false,
      "max_chars": 2200,
      "needs_media": true
    }
  ]
}

List posts

GET/api/v1/posts

Calendar posts in a range of days, in project local time.

Query parameters
project_idstring
Required only for OAuth tokens with several projects.
fromstring
First day, YYYY-MM-DD. Defaults to today.
daysinteger
Number of days, 1 to 62. Defaults to 14.
statusstring
Only posts with this status, regardless of date (latest 100). Useful for undated drafts or failed posts.

Post status

StatusMeaning
draftSaved, not scheduled.
pending_approvalWaiting for a person to approve it in the app.
scheduledWill be published at when.
publishingBeing published right now.
publishedPublished on every channel.
partialPublished on some channels; others failed.
failedPublishing failed on every channel.

from_agent is true for posts created through the API or MCP.

curl "https://postika.app/api/v1/posts?from=2026-11-09&days=7" \
  -H "Authorization: Bearer $POSTIKA_KEY"
200 OK
{
  "data": [
    {
      "id": "f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42",
      "status": "scheduled",
      "when": "2026-11-12 09:30",
      "content": "Hello from the Postika API",
      "channel_ids": [
        "8d0c6f8e-2b7a-4c1e-9f43-2f1d7a8b5c10"
      ],
      "channels": [
        {
          "channel_id": "8d0c6f8e-…",
          "network": "LinkedIn",
          "handle": "acme",
          "status": "pending",
          "error": null,
          "url": null
        }
      ],
      "media": [],
      "from_agent": true,
      "note": null
    }
  ]
}

Create a post

POST/api/v1/posts
Body
project_idstring
Required only for OAuth tokens with several projects.
contentstringrequired
Text, 1 to 5000 characters. Each channel's own limit applies when scheduling or publishing.
channel_idsstring[]required
At least one channel of the project.
modeenumrequired
schedule, approval, draft or now.
whenstring
YYYY-MM-DD HH:MM in project local time. Required for schedule and approval, optional for draft, ignored for now. Can't be in the past.
media_urlsstring[]
Up to 10 public https:// links straight to the files: JPG, PNG, WebP, GIF (15 MB) or MP4, MOV (100 MB). Postika downloads them with SSRF protection (see MCP → media).
notestring
Note for whoever approves it. Not published.
modeResultRules checked
schedulescheduled at whenYes
approvalpending_approval at whenWhen approved
draftdraftNo
nowpublished right away (or partial / failed)Yes
Media and roles
Instagram, TikTok and Pinterest need a photo or video and YouTube a video: send them in media_urls. With an OAuth token of an editor, schedule and now are saved as pending_approval and the response includes a notice.
curl https://postika.app/api/v1/posts \
  -H "Authorization: Bearer $POSTIKA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "We just shipped dark mode.",
    "channel_ids": ["8d0c6f8e-2b7a-4c1e-9f43-2f1d7a8b5c10"],
    "when": "2026-11-12 09:30",
    "mode": "schedule"
  }'
200 OK
{
  "data": {
    "id": "f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42",
    "status": "scheduled",
    "when": "2026-11-12 09:30",
    "content": "We just shipped dark mode.",
    "channels": [ … ],
    "media": [],
    "from_agent": true
  }
}
400 Bad Request
{
  "error": "Instagram needs a photo or video",
  "code": "needs_media",
  "hint": "Pass media_urls with public https links to a JPG, PNG, WebP or GIF photo, or an MP4/MOV video."
}

Get a post

GET/api/v1/posts/:id

One post with text, time, media IDs, and the status, error and published URL of each channel.

curl "https://postika.app/api/v1/posts/f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42" \
  -H "Authorization: Bearer $POSTIKA_KEY"

Update a post

PATCH/api/v1/posts/:id

Change a post that hasn't been published yet. Every field is optional and omitted fields stay as they are: content, channel_ids, when, mode, media_urls (added) and keep_media_ids (media to keep, in order; [] removes them all). An editor's change to a scheduled post sends it back to approval.

curl -X PATCH https://postika.app/api/v1/posts/f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42 \
  -H "Authorization: Bearer $POSTIKA_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "when": "2026-11-13 18:00", "media_urls": ["https://example.com/photo.jpg"] }'

Approve a post

POST/api/v1/posts/:id/approve

Moves a pending_approval post to scheduled (in one minute if its time has passed), after checking each network's rules. Owners, admins and API keys only; editors get 403 approval_forbidden. To list what is waiting, use GET /posts?status=pending_approval.

curl -X POST https://postika.app/api/v1/posts/f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42/approve \
  -H "Authorization: Bearer $POSTIKA_KEY"

Delete a post

DELETE/api/v1/posts/:id

Removes the post from Postika, whatever its status. The only post that can't be deleted is one being published right now. Deleting a post that was already published removes it from your calendar, not from the network.

Parameters
idpathrequired
Post ID.
project_idquery
Required only for OAuth tokens with several projects.

Every error code and message is listed in Errors & limits.

curl -X DELETE https://postika.app/api/v1/posts/f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42 \
  -H "Authorization: Bearer $POSTIKA_KEY"
200 OK
{
  "data": {
    "deleted": "f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42"
  }
}