How to use the Postoria Public API
The Postoria Public API lets you connect external tools, scripts, and internal systems to Postoria.
You can use it to list your workspaces and connected social accounts, upload media, create posts, schedule posts, add posts to queues, list posts, check post status, and delete posts.
Public API is available on Pro and Agency plans.
Before you start
Here are the main things to know before using the API:
- You need an active Pro or Agency plan.
- Each Postoria account can have one active API key.
- API keys are account-level, not workspace-level.
- Workspace-specific endpoints require a
workspace_idin the URL. - The API uses bearer token authentication.
- The API is rate limited to 300 requests per 5 minutes per account.
- Media processing is asynchronous.
- API responses use
snake_caseJSON fields. - API v1 uses the
/v1path prefix.
Base URL
Use this base URL:
https://api.postoria.io/v1
API documentation is available here: https://api.postoria.io/v1/docs/.
The OpenAPI document is available here: https://api.postoria.io/v1/openapi.json.
Create an API key
- Open Postoria.
- Go to Settings.
- Find the Public API section.
- Click Create API key.
- Copy the key and store it securely.
Postoria shows the full API key only once. After closing the dialog, you will only see the key prefix.
If you lose the key, revoke it and create a new one.
Authenticate requests
Send the API key in the Authorization header:
Authorization: Bearer pst_live_your_api_key
Example:
curl https://api.postoria.io/v1/workspaces \
-H "Authorization: Bearer pst_live_your_api_key"
If the key is missing, invalid, or revoked, Postoria returns 401 invalid_api_key.
Response format
Single-resource responses return the object directly.
List responses use this format:
{
"data": [],
"pagination": {
"has_more": false,
"next_cursor": null,
"next": null
}
}
When a list endpoint supports pagination, has_more tells you whether another page is available. Use next to request the next page directly, or send the returned next_cursor as the cursor query parameter.
Error responses use this format:
{
"error": {
"code": "validation_failed",
"message": "One or more fields are invalid.",
"param": null,
"details": null,
"request_id": "req_abc123"
}
}
Rate limit
The Public API allows:
300 requests per 5 minutes per account
If you exceed the limit, Postoria returns 429 rate_limit_exceeded with retry headers.
Example:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1770000000
Endpoints
Public API v1 includes these endpoints:
GET /v1/workspaces
GET /v1/workspaces/{workspace_id}/social-accounts
GET /v1/workspaces/{workspace_id}/queues
POST /v1/workspaces/{workspace_id}/media/uploads
POST /v1/workspaces/{workspace_id}/media/{media_id}/complete
POST /v1/workspaces/{workspace_id}/media/imports
GET /v1/workspaces/{workspace_id}/media/{media_id}
POST /v1/workspaces/{workspace_id}/posts
GET /v1/workspaces/{workspace_id}/posts
GET /v1/workspaces/{workspace_id}/posts/{post_id}
DELETE /v1/workspaces/{workspace_id}/posts/{post_id}
List workspaces
Use this endpoint to get the workspaces available to your account:
GET /v1/workspaces
Example response:
{
"data": [
{
"id": 1,
"name": "My Workspace",
"timezone": "America/New_York"
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"next": null
}
}
Use the returned id as workspace_id in workspace-specific endpoints.
List social accounts
Use this endpoint to get connected social accounts in a workspace:
GET /v1/workspaces/{workspace_id}/social-accounts
Example response:
{
"data": [
{
"id": 123,
"name": "Postoria",
"description": "postoria.app",
"network": "instagram",
"url": "https://www.instagram.com/postoria.app"
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"next": null
}
}
Use the returned account IDs in social_account_ids when creating posts.
List queues
Use this endpoint to get queues in a workspace:
GET /v1/workspaces/{workspace_id}/queues
Example response:
{
"data": [
{
"id": 456,
"name": "Morning posts",
"is_paused": false
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"next": null
}
}
Use the returned queue ID when creating a post with publish_mode set to queue.
Upload media
There are two ways to add media through the API:
- Create an upload URL and upload the file yourself.
- Import media from a public HTTPS URL.
Both methods create a media object. Use the Get media status endpoint to check when it is ready.
A media item must have status set to ready before you can reference it when creating a post.
Supported upload types include common image, video, and document formats such as JPEG, PNG, WebP, GIF, MP4, MOV, and PDF.
Upload media with an upload URL
First, create an upload:
POST /v1/workspaces/{workspace_id}/media/uploads
Request:
{
"name": "image.jpg",
"content_type": "image/jpeg"
}
Example response:
{
"id": 9001,
"status": "waiting_for_upload",
"upload": {
"url": "https://temporary-upload-url.example"
}
}
Upload the file bytes to the returned upload.url using an HTTP PUT request. Send the raw file bytes as the request body and use the same content_type value you used when creating the upload.
Example:
curl -X PUT "https://temporary-upload-url.example" \
-H "Content-Type: image/jpeg" \
--data-binary "@image.jpg"
The upload URL is temporary. If it expires before you upload and complete the media item, create a new upload.
After uploading the file, complete the upload:
POST /v1/workspaces/{workspace_id}/media/{media_id}/complete
Example response:
{
"id": 9001,
"status": "processing",
"file_id": null,
"error_code": null,
"error_message": null
}
Postoria will process the media in the background.
Import media from a URL
Use this endpoint when the media file is already available at a public HTTPS URL:
POST /v1/workspaces/{workspace_id}/media/imports
Request:
{
"url": "https://example.com/video.mp4"
}
Example response:
{
"id": 9002,
"status": "processing",
"file_id": null,
"error_code": null,
"error_message": null
}
Only public HTTPS URLs are supported. Private URLs, authenticated URLs, local files, and relative paths are not supported.
Check media status
Use this endpoint to check if a media item is ready:
GET /v1/workspaces/{workspace_id}/media/{media_id}
Example ready response:
{
"id": 9001,
"status": "ready",
"file_id": 701,
"error_code": null,
"error_message": null
}
Example failed response:
{
"id": 9001,
"status": "failed",
"file_id": null,
"error_code": "media_processing_failed",
"error_message": "The file format is not supported."
}
Media statuses:
waiting_for_uploadprocessingreadyfailed
Create a post
Use this endpoint to create a post:
POST /v1/workspaces/{workspace_id}/posts
The API does not create drafts. A post is created for one of these publishing modes:
publish_nowschedulequeue
scheduled_time is required only for schedule. queue_id is required only for queue. Neither field should be sent for publish_now.
All selected social accounts must support the selected content type; otherwise, the request is rejected.
Example scheduled post request:
{
"publish_mode": "schedule",
"social_account_ids": [123],
"content_type": "image",
"media": [
{
"media_id": 9001
}
],
"caption": "Post caption",
"first_comment": "More details in the first comment.",
"comment_delay": 5,
"scheduled_time": "2026-06-01T10:00:00Z"
}
Example response:
{
"id": 3001,
"status": "scheduled",
"date": "2026-06-01T10:00:00Z",
"queue_id": null,
"results": [
{
"account_id": 123,
"link_to_post": null,
"error": null
}
],
"instagram": {
"content": "image",
"caption": "Post caption",
"files": [
{
"url": "https://assets.postoria.io/w/1/image.jpg?st=temporary_signed_token"
}
],
"comment": "More details in the first comment.",
"comment_delay": 5
}
}
Post responses include one object for each enabled social network in the post, such as facebook, instagram, linkedin, youtube, or tiktok. Each network object contains:
content: the effective content type for that network.caption: the caption text for that network.files: media files for that network. File URLs are temporary signed URLs that can be opened without authentication for about one hour. A file can also includethumbnail_urlwhen a thumbnail is available.
Depending on the network and content type, a network object can also include comment and comment_delay, link, or network-specific publishing options. comment_delay is measured in minutes. Link posts and first comments are available only where the selected network and content type support them. Stories do not support first comments.
Publication outcomes are returned per account in results when available. For scheduled and queued posts, results may not be available until the post has been processed. A post can have a mix of successful and failed account results.
Date and time fields
Date/time fields use ISO 8601 UTC strings.
Example:
"scheduled_time": "2026-06-01T10:00:00Z"
Use UTC and include the trailing Z.
If you are scheduling based on a local time, convert it to UTC before sending it to the API.
Create a post now
Set publish_mode to publish_now.
{
"publish_mode": "publish_now",
"social_account_ids": [123],
"content_type": "image",
"media": [
{
"media_id": 9001
}
],
"caption": "Publishing from Postoria Public API"
}
Schedule a post
Set publish_mode to schedule and provide scheduled_time.
{
"publish_mode": "schedule",
"social_account_ids": [123],
"content_type": "image",
"media": [
{
"media_id": 9001
}
],
"caption": "Scheduled from Postoria Public API",
"scheduled_time": "2026-06-01T10:00:00Z"
}
scheduled_time must be in the future.
Add a post to a queue
Set publish_mode to queue and provide queue_id.
{
"publish_mode": "queue",
"social_account_ids": [123],
"content_type": "image",
"media": [
{
"media_id": 9001
}
],
"caption": "Queued from Postoria Public API",
"queue_id": 456
}
The queue must belong to the same workspace.
Content types
Supported content_type values:
textimagevideodocumentcarousellinkstoryreel
If content_type is not provided, Postoria tries to determine it from the request data:
- Multiple media items →
carousel - One media item → the matching media type, such as
image,video, ordocument - Link URL without media →
link - Caption only →
text
Social network-specific validation still applies. All selected social accounts must support the requested content type; otherwise, the API returns a validation error and does not create the post.
Add media to a post
Use the media array to reference media items created by the upload or import endpoints. Each item must have status set to ready.
{
"media": [
{
"media_id": 9001
}
]
}
For a video, you can optionally provide a custom thumbnail. thumbnail_media_id belongs to the corresponding media_id and must reference a ready image media item.
{
"media": [
{
"media_id": 9002,
"thumbnail_media_id": 9003
}
]
}
Link posts
For link posts, provide link_url:
{
"publish_mode": "schedule",
"social_account_ids": [123],
"content_type": "link",
"caption": "Useful link",
"link_url": "https://example.com/article",
"scheduled_time": "2026-06-01T10:00:00Z"
}
Postoria will import link information when creating the post.
First comment
Use first_comment to add a first comment where the selected network supports it. Use comment_delay to delay the first comment; the value is measured in minutes.
{
"first_comment": "More details in the first comment."
}
Network-specific rules still apply. The first-comment response fields are returned only for networks where first comments are supported.
Instagram options
Use the instagram object for Instagram-specific options:
{
"instagram": {
"collaborators": ["creator_one"],
"publish_as_trial_reel": false,
"auto_share_if_performs_well": false,
"user_tags": [
{
"media_id": 9001,
"username": "creator_one",
"x": 0.5,
"y": 0.5
}
]
}
}
user_tags.media_id must reference media attached to the same post. In post responses, user tags use file_id instead of media_id.
Pinterest options
Use the pinterest object for Pinterest-specific options:
{
"pinterest": {
"title": "Pin title",
"website": "https://example.com/article",
"alt_text": "A description of the image"
}
}
website is the destination URL for the Pin.
Google Business Profile options
Use the google_business_profile object to add an action button:
{
"google_business_profile": {
"button_type": "LEARN_MORE",
"button_url": "https://example.com"
}
}
Supported button types are BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP, and CALL. A button URL is required for all button types except CALL.
Repost settings
Use repost to configure reposting.
Example:
{
"repost": {
"frequency": "do_not_repeat",
"until": null
}
}
If you set a repost frequency, until must be a future UTC date/time when required by the selected repost settings.
YouTube options
Use the youtube object when creating posts for YouTube accounts.
Example:
{
"youtube": {
"title": "Video title",
"visibility": "public",
"category": "People & Blogs",
"made_for_kids": false,
"video_language": "en",
"recording_date": "2026-06-01T00:00:00Z",
"tags": ["tag1", "tag2"]
}
}
Use YouTube fields only when at least one selected social account is a YouTube account.
For supported YouTube values, see the Bulk Upload documentation: How to bulk upload posts with a CSV file in Postoria.
TikTok options
Use the tiktok object when creating posts for TikTok accounts.
Example:
{
"tiktok": {
"who_can_watch": "public",
"allow_comments": true,
"allow_duet": false,
"allow_stitch": false,
"disclose_post_content": false,
"your_brand": false,
"branded_content": false,
"photo_title": "Photo title",
"auto_add_music": false
}
}
Supported TikTok fields:
who_can_watch:public,followers,friends, orprivateallow_comments:trueorfalseallow_duet:trueorfalseallow_stitch:trueorfalsedisclose_post_content:trueorfalseyour_brand:trueorfalsebranded_content:trueorfalsephoto_title: plain text up to 90 charactersauto_add_music:trueorfalse
Use TikTok fields only when at least one selected social account is a TikTok account.
List posts
Use this endpoint to list posts in a workspace:
GET /v1/workspaces/{workspace_id}/posts
Optional query parameters:
account_ids: social account IDs. Repeat the parameter or use comma-separated values.queue_id: queue ID.status: one ofdraft,scheduled,in_progress,posted, orqueued.networks: one or more network values such asinstagram,facebook,linkedin,youtube, ortiktok.date_from: scheduled date/time at or after this UTC value.date_to: scheduled date/time before this UTC value.limit: number of posts to return. Default is25; maximum is100.cursor: pagination cursor returned from the previous page.
account_ids and queue_id must belong to the specified workspace.
Example request:
curl "https://api.postoria.io/v1/workspaces/1/posts?status=scheduled&limit=25" \
-H "Authorization: Bearer pst_live_your_api_key"
Example response:
{
"data": [
{
"id": 3001,
"status": "scheduled",
"date": "2026-06-01T10:00:00Z",
"queue_id": null,
"results": [
{
"account_id": 123,
"link_to_post": null,
"error": null
}
],
"instagram": {
"caption": "Scheduled post caption",
"files": [
{
"url": "https://assets.postoria.io/w/1/image.jpg?st=temporary_signed_token"
}
]
}
}
],
"pagination": {
"has_more": true,
"next_cursor": "eyJJZCI6MzAwMSwiRGF0ZSI6IjIwMjYtMDYtMDFUMTA6MDA6MDBaIiwiUXVldWVQb3NpdGlvbiI6bnVsbH0",
"next": "https://api.postoria.io/v1/workspaces/1/posts?status=scheduled&limit=25&cursor=eyJJZCI6MzAwMSwiRGF0ZSI6IjIwMjYtMDYtMDFUMTA6MDA6MDBaIiwiUXVldWVQb3NpdGlvbiI6bnVsbH0"
}
}
To request the next page, call next directly or pass next_cursor back as cursor:
GET /v1/workspaces/{workspace_id}/posts?status=scheduled&limit=25&cursor=eyJJZCI6MzAwMSwiRGF0ZSI6IjIwMjYtMDYtMDFUMTA6MDA6MDBaIiwiUXVldWVQb3NpdGlvbiI6bnVsbH0
Check post status
Use this endpoint to check the status of a post:
GET /v1/workspaces/{workspace_id}/posts/{post_id}
date is the scheduled publication time. It can be null for queued and immediate posts.
Example response:
{
"id": 3001,
"status": "posted",
"date": "2026-06-01T10:00:00Z",
"queue_id": null,
"results": [
{
"account_id": 123,
"link_to_post": "https://www.instagram.com/p/example",
"error": null
}
],
"instagram": {
"caption": "Published post caption",
"files": [
{
"url": "https://assets.postoria.io/w/1/image.jpg?st=temporary_signed_token"
}
]
}
}
Post statuses:
draftscheduledin_progresspostedqueued
Result items mean:
link_to_postis set when the post was published successfully and a public link is available.erroris set when publishing failed for that account.- Both
link_to_postanderrorcan benullbefore the post is published.
Delete a post
Use this endpoint to delete a post:
DELETE /v1/workspaces/{workspace_id}/posts/{post_id}
Successful response:
204 No Content
The post must belong to the specified workspace.
Deleting a post removes it from Postoria. It does not delete posts already published to social networks. If publishing has already started, deleting the Postoria post does not stop that publication. Account results are removed with the post and cannot be retrieved afterwards.
Common errors
Invalid API key
{
"error": {
"code": "invalid_api_key",
"message": "The API key is invalid or has been revoked.",
"param": null,
"details": null,
"request_id": "req_abc123"
}
}
Plan required
{
"error": {
"code": "public_api_plan_required",
"message": "Public API access is available on Pro and Agency plans.",
"param": null,
"details": null,
"request_id": "req_abc123"
}
}
Validation failed
{
"error": {
"code": "validation_failed",
"message": "One or more fields are invalid.",
"param": "content_type",
"details": {
"reason": "The selected social account does not support this content type."
},
"request_id": "req_abc123"
}
}
Workspace not found
{
"error": {
"code": "workspace_not_found",
"message": "The requested workspace was not found.",
"param": "workspace_id",
"details": null,
"request_id": "req_abc123"
}
}
Best practices
- Store your API key securely.
- Do not expose the API key in frontend code.
- Upload or import media first, then wait until the media status is
ready. - Use
GET /posts/{post_id}to check status after creating a post. - Handle validation errors and show the returned message to your users.
- Retry only after respecting rate limit headers.
- Revoke the key immediately if you think it has been exposed.