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/projectsList projectsGET/accountAccount statusGET/channelsList channelsGET/postsList postsPOST/postsCreate a postGET/posts/:idGet a postPATCH/posts/:idUpdate a postPOST/posts/:id/approveApprove a postDELETE/posts/:idDelete a post- 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
/api/v1/projectsProjects 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"{
"data": [
{
"id": "3f6a1d2e-7c41-4b8e-a0f5-9d2c8e1b7a63",
"name": "Acme",
"timezone": "Europe/Madrid",
"role": "owner",
"active": true,
"reason": null,
"subscription_status": "active"
}
]
}Account status
/api/v1/accountPlan, 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
/api/v1/channelsConnected channels of the project. Channels that need to be reconnected are left out.
project_idstring- Required only for OAuth tokens with several projects.
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"{
"data": [
{
"id": "8d0c6f8e-2b7a-4c1e-9f43-2f1d7a8b5c10",
"network": "Instagram",
"handle": "acme",
"demo": false,
"max_chars": 2200,
"needs_media": true
}
]
}List posts
/api/v1/postsCalendar posts in a range of days, in project local time.
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 orfailedposts.
Post status
| Status | Meaning |
|---|---|
| draft | Saved, not scheduled. |
| pending_approval | Waiting for a person to approve it in the app. |
| scheduled | Will be published at when. |
| publishing | Being published right now. |
| published | Published on every channel. |
| partial | Published on some channels; others failed. |
| failed | Publishing 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"{
"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
/api/v1/postsproject_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.
modeenumrequiredschedule,approval,draftornow.whenstringYYYY-MM-DD HH:MMin project local time. Required forscheduleandapproval, optional fordraft, ignored fornow. 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.
| mode | Result | Rules checked |
|---|---|---|
| schedule | scheduled at when | Yes |
| approval | pending_approval at when | When approved |
| draft | draft | No |
| now | published right away (or partial / failed) | Yes |
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"
}'{
"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
}
}{
"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
/api/v1/posts/:idOne 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
/api/v1/posts/:idChange 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
/api/v1/posts/:id/approveMoves 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
/api/v1/posts/:idRemoves 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.
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"{
"data": {
"deleted": "f2b1c0de-5a4e-4d0b-8a77-0c6e3b9d1a42"
}
}