PosteAhora Posts API
The Posts API from PosteAhora — 3 operation(s) for posts.
The Posts API from PosteAhora — 3 operation(s) for posts.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/posteahora:posteahora-posts-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: PosteAhora Public Posts API
version: 1.0.0
description: 'Key-authenticated REST gateway over the same publishing pipeline as the PosteAhora web app. It powers the MCP server, the CLI, the n8n node, and any third-party integration. This is the frozen **v1** contract: additive changes only.
Human-readable docs: https://posteahora.com/docs/api'
contact:
name: PosteAhora
url: https://posteahora.com/docs/api
servers:
- url: https://api.posteahora.com/functions/v1/api
description: Production. The /functions/v1/ segment is part of the stable URL — do not strip it.
security:
- ApiKey: []
tags:
- name: Posts
paths:
/posts:
get:
tags:
- Posts
summary: List posts
parameters:
- name: status
in: query
schema:
type: string
enum:
- draft
- scheduled
- queued
- published
- partial_published
- failed
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 200
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
posts:
type: array
items:
$ref: '#/components/schemas/Post'
operationId: getPosts
x-operation-id-source: derived
post:
tags:
- Posts
summary: Create a draft, schedule, or publish now (controlled by status)
description: Multi-platform posts fan out into one row per platform at publish time. Publishing is asynchronous — a "published" create returns status "queued"; poll GET /posts/{id} and read platform_results.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePostRequest'
examples:
multiPlatformVideo:
summary: One video → YouTube Shorts + TikTok + Instagram Reels, per-platform metadata
value:
caption: Fallback text if a platform override is missing
mediaUrls:
- https://cdn.posteahora.com/…/clip.mp4
mediaType: video
postType: reel
status: published
accountMappings:
- platform: youtube
accountId: <yt-account-id>
- platform: tiktok
accountId: <tt-account-id>
- platform: instagram
accountId: <ig-account-id>
platformCaptions:
youtube: Full YouTube description — links, timestamps, etc.
tiktok: 'TikTok caption #fyp'
instagram: Reel caption for IG ✨
platformOptions:
youtube:
title: My video title
categoryId: '22'
madeForKids: false
privacyStatus: public
tags:
- demo
- api
tiktok:
privacyLevel: PUBLIC_TO_EVERYONE
disableComment: false
brandContentToggle: false
brandOrganicToggle: false
isAigc: false
instagram:
shareToFeed: true
coverUrl: https://cdn.posteahora.com/…/cover.jpg
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePostResult'
'400':
$ref: '#/components/responses/BadRequest'
'402':
description: Monthly post quota reached
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
$ref: '#/components/responses/Forbidden'
operationId: postPosts
x-operation-id-source: derived
/posts/{id}:
parameters:
- $ref: '#/components/parameters/Id'
get:
tags:
- Posts
summary: Read one post (includes connected_account_id and platform_results)
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
post:
$ref: '#/components/schemas/Post'
'404':
$ref: '#/components/responses/NotFound'
operationId: getPostsById
x-operation-id-source: derived
patch:
tags:
- Posts
summary: Edit a draft or scheduled post (only sent fields are touched)
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdatePostRequest'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
post:
$ref: '#/components/schemas/Post'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
operationId: patchPostsById
x-operation-id-source: derived
delete:
tags:
- Posts
summary: Soft-delete a post
responses:
'200':
$ref: '#/components/responses/Deleted'
'404':
$ref: '#/components/responses/NotFound'
operationId: deletePostsById
x-operation-id-source: derived
/posts/{id}/publish:
parameters:
- $ref: '#/components/parameters/Id'
post:
tags:
- Posts
summary: Publish an existing draft/scheduled post immediately
description: Enters the async pipeline. Poll GET /posts/{id} for platform_results.
responses:
'200':
description: Queued
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePostResult'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
operationId: postPostsByIdPublish
x-operation-id-source: derived
components:
responses:
Forbidden:
description: Key lacks the required scope (or viewer-role key attempting a write)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Deleted:
description: Deleted
content:
application/json:
schema:
type: object
properties:
id:
type: string
deleted:
type: boolean
NotFound:
description: Resource not found (or not in the key's workspace)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
schemas:
UpdatePostRequest:
type: object
description: Edit a draft or scheduled post. Only sent fields are touched.
properties:
title:
type: string
caption:
type: string
hashtags:
type: array
items:
type: string
mediaUrls:
type: array
items:
type: string
format: uri
mediaType:
type: string
enum:
- image
- video
postType:
type: string
enum:
- post
- reel
- story
platforms:
type: array
items:
type: string
connectedAccountId:
type: string
platformOptions:
$ref: '#/components/schemas/PlatformOptions'
status:
type: string
enum:
- draft
- scheduled
scheduledAt:
type: string
format: date-time
CreatePostRequest:
type: object
properties:
title:
type: string
caption:
type: string
description: Shared caption. Per-network override via platformCaptions.
accountMappings:
type: array
items:
$ref: '#/components/schemas/AccountMapping'
description: Canonical channel selection. Prefer this over platforms+accountId.
platforms:
type: array
items:
type: string
description: Convenience form for a single-channel post (combine with accountId).
accountId:
type: string
description: Used only with the platforms convenience form.
mediaUrls:
type: array
items:
type: string
format: uri
mediaType:
type: string
enum:
- image
- video
postType:
type: string
enum:
- post
- reel
- story
default: post
hashtags:
type: array
items:
type: string
platformCaptions:
type: object
additionalProperties:
type: string
description: Per-platform caption/description override, keyed by platform id.
platformOptions:
$ref: '#/components/schemas/PlatformOptions'
status:
type: string
enum:
- draft
- scheduled
- published
default: draft
scheduledAt:
type: string
format: date-time
description: Required (and must be in the future) when status = scheduled.
required:
- accountMappings
CreatePostResult:
type: object
properties:
postIds:
type: array
items:
type: string
format: uuid
status:
type: string
enum:
- draft
- scheduled
- queued
dispatchDeferred:
type: boolean
description: When true, rows are stored but the worker wasn't reached synchronously; the cron sweep will publish them.
BlueskyOptions:
type: object
properties:
langs:
type: array
items:
type: string
TikTokOptions:
type: object
properties:
privacyLevel:
type: string
enum:
- PUBLIC_TO_EVERYONE
- MUTUAL_FOLLOW_FRIENDS
- FOLLOWER_OF_CREATOR
- SELF_ONLY
disableComment:
type: boolean
brandContentToggle:
type: boolean
brandOrganicToggle:
type: boolean
isAigc:
type: boolean
postMode:
type: string
enum:
- DIRECT_POST
- MEDIA_UPLOAD
default: DIRECT_POST
disableDuet:
type: boolean
description: video only
disableStitch:
type: boolean
description: video only
videoCoverTimestampMs:
type: number
description: video only
autoAddMusic:
type: boolean
description: photo only
photoCoverIndex:
type: number
description: photo only
photoTitle:
type: string
maxLength: 90
description: photo only
required:
- privacyLevel
- disableComment
- brandContentToggle
- brandOrganicToggle
- isAigc
PlatformResult:
type: object
properties:
platform:
type: string
success:
type: boolean
error:
type: string
remote_post_id:
type: string
remote_publish_id:
type: string
remote_permalink:
type: string
format: uri
required:
- platform
- success
MastodonOptions:
type: object
properties:
visibility:
type: string
enum:
- public
- unlisted
- private
- direct
spoilerText:
type: string
sensitive:
type: boolean
language:
type: string
Post:
type: object
properties:
id:
type: string
format: uuid
title:
type:
- string
- 'null'
caption:
type:
- string
- 'null'
platforms:
type: array
items:
type: string
status:
type: string
enum:
- draft
- scheduled
- queued
- published
- partial_published
- failed
scheduled_at:
type:
- string
- 'null'
format: date-time
published_at:
type:
- string
- 'null'
format: date-time
media_urls:
type: array
items:
type: string
format: uri
media_type:
type:
- string
- 'null'
enum:
- image
- video
- null
connected_account_id:
type:
- string
- 'null'
format: uuid
platform_results:
type: array
items:
$ref: '#/components/schemas/PlatformResult'
created_at:
type: string
format: date-time
InstagramOptions:
type: object
description: Set postType "reel" (top level) for a Reel, "story" for a Story.
properties:
shareToFeed:
type: boolean
coverUrl:
type: string
format: uri
thumbOffsetMs:
type: number
audioName:
type: string
collaborators:
type: array
items:
type: string
locationId:
type: string
userTags:
type: array
items:
type: object
properties:
username:
type: string
x:
type: number
y:
type: number
required:
- username
altText:
type: string
isAiGenerated:
type: boolean
isTrialReel:
type: boolean
description: reel only
trialGraduationStrategy:
type: string
enum:
- MANUAL
- SS_PERFORMANCE
description: reel only
TelegramOptions:
type: object
properties:
disableNotification:
type: boolean
protectContent:
type: boolean
AccountMapping:
type: object
properties:
platform:
type: string
example: youtube
accountId:
type: string
description: connected_accounts.id. Required for every network except a few that don't need account selection.
required:
- platform
PlatformOptions:
type: object
description: Per-network settings, keyed by platform id.
properties:
youtube:
$ref: '#/components/schemas/YouTubeOptions'
tiktok:
$ref: '#/components/schemas/TikTokOptions'
instagram:
$ref: '#/components/schemas/InstagramOptions'
threads:
$ref: '#/components/schemas/ThreadsOptions'
bluesky:
$ref: '#/components/schemas/BlueskyOptions'
mastodon:
$ref: '#/components/schemas/MastodonOptions'
telegram:
$ref: '#/components/schemas/TelegramOptions'
discord:
$ref: '#/components/schemas/DiscordOptions'
pinterest:
$ref: '#/components/schemas/PinterestOptions'
additionalProperties: true
ThreadsOptions:
type: object
properties:
replyControl:
type: string
enum:
- everyone
- accounts_you_follow
- mentioned_only
- parent_post_author_only
- followers_only
topic:
type: string
altText:
type: string
linkAttachment:
type: string
format: uri
quotePostId:
type: string
locationId:
type: string
allowlistedCountryCodes:
type: array
items:
type: string
chainItems:
type: array
items:
type: object
properties:
text:
type: string
mediaUrl:
type: string
format: uri
mediaType:
type: string
enum:
- image
- video
altText:
type: string
required:
- text
Error:
type: object
properties:
error:
type: string
required:
- error
DiscordOptions:
type: object
properties:
channelId:
type: string
PinterestOptions:
type: object
description: boardId is REQUIRED and validated on create (400 without it). A Pin needs at least one image; 2–5 images make a carousel.
required:
- boardId
properties:
boardId:
type: string
description: Board id from GET /accounts/{id}/boards
boardName:
type: string
description: Display only
title:
type: string
maxLength: 100
link:
type: string
format: uri
altText:
type: string
maxLength: 500
coverUrl:
type: string
format: uri
description: 'Video Pins: 2:3 cover image URL'
thumbOffsetMs:
type: integer
minimum: 0
description: 'Video Pins: keyframe used as cover when coverUrl is absent (ms)'
YouTubeOptions:
type: object
description: 'The video description is the post caption (platformCaptions.youtube, ≤5000 chars). The video title is the required `title` field. There is no "Shorts" flag — a vertical clip ≤3 min is auto-classified as a Short.
'
properties:
title:
type: string
maxLength: 100
categoryId:
type: string
example: '22'
madeForKids:
type: boolean
privacyStatus:
type: string
enum:
- public
- unlisted
- private
default: private
tags:
type: array
items:
type: string
defaultLanguage:
type: string
containsSyntheticMedia:
type: boolean
embeddable:
type: boolean
publicStatsViewable:
type: boolean
license:
type: string
enum:
- youtube
- creativeCommon
thumbnailUrl:
type: string
format: uri
required:
- title
- categoryId
- madeForKids
parameters:
Id:
name: id
in: path
required: true
schema:
type: string
format: uuid
securitySchemes:
ApiKey:
type: http
scheme: bearer
description: 'A PosteAhora API key: `Authorization: Bearer pah_live_…` (or `pah_test_…`). Keys are created in the app under /api and carry scopes (ideas:read/write, posts:read/write, analytics:read, accounts:read, media:write). A missing scope returns 403.
'
x-provenance:
method: harvested
publisher: PosteAhora
source: https://posteahora.com/openapi.yaml
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)