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, 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 profile 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
}
}
Pagination is included for future compatibility. In the initial v1 release, has_more is always false and next_cursor is always null.
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/{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
}
}
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
}
}
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
}
}
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 GET /media/{media_id} to check when it is ready.
A media item must have status set to ready before you can use it in POST /posts.
Supported upload types include common image and video formats such as JPEG, PNG, WebP, GIF, MP4, and MOV.
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
Example scheduled post request:
{
"publish_mode": "schedule",
"social_account_ids": [123],
"content_type": "image",
"media_ids": [9001],
"caption": "Post caption",
"link_url": null,
"first_comment": null,
"scheduled_time": "2026-06-01T10:00:00Z",
"queue_id": null,
"repost": null,
"youtube": null,
"tiktok": null
}
Example response:
{
"id": 3001,
"status": "scheduled",
"results": [
{
"account_id": 123,
"link_to_post": null,
"error": null
}
]
}
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_ids": [9001],
"caption": "Publishing from Postoria Public API",
"link_url": null,
"first_comment": null,
"scheduled_time": null,
"queue_id": null,
"repost": null,
"youtube": null,
"tiktok": null
}
Schedule a post
Set publish_mode to schedule and provide scheduled_time.
{
"publish_mode": "schedule",
"social_account_ids": [123],
"content_type": "image",
"media_ids": [9001],
"caption": "Scheduled from Postoria Public API",
"scheduled_time": "2026-06-01T10:00:00Z",
"queue_id": null
}
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_ids": [9001],
"caption": "Queued from Postoria Public API",
"scheduled_time": null,
"queue_id": 456
}
The queue must belong to the same workspace.
Content types
Supported content_type values:
textimagevideocarousellinkstoryreel
If content_type is not provided, Postoria tries to determine it from the request data:
- Multiple media IDs →
carousel - One media ID →
imageorvideo - Link URL without media →
link - Caption only →
text
Social network-specific validation still applies. If the selected social account does not support the requested content type, the API returns a validation error and does not create the post.
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",
"media_ids": [],
"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.
{
"first_comment": "More details in the first comment."
}
Network-specific rules still apply.
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
}
}
Use TikTok fields only when at least one selected social account is a TikTok account.
Check post status
Use this endpoint to check the status of a post:
GET /v1/workspaces/{workspace_id}/posts/{post_id}
Example response:
{
"id": 3001,
"status": "posted",
"results": [
{
"account_id": 123,
"link_to_post": "https://www.instagram.com/p/example",
"error": null
}
]
}
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.
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.