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_id in 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_case JSON fields.
  • API v1 uses the /v1 path 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

  1. Open Postoria.
  2. Go to Settings.
  3. Find the Public API section.
  4. Click Create API key.
  5. 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:

  1. Create an upload URL and upload the file yourself.
  2. 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_upload
  • processing
  • ready
  • failed

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_now
  • schedule
  • queue

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:

  • text
  • image
  • video
  • carousel
  • link
  • story
  • reel

If content_type is not provided, Postoria tries to determine it from the request data:

  • Multiple media IDs → carousel
  • One media ID → image or video
  • 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.

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:

  • draft
  • scheduled
  • in_progress
  • posted
  • queued

Result items mean:

  • link_to_post is set when the post was published successfully and a public link is available.
  • error is set when publishing failed for that account.
  • Both link_to_post and error can be null before 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.