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 connect and reconnect social accounts, list your workspaces and connected accounts, upload media, create and manage posts, and retrieve current or aggregated post analytics.
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/social-account-connection-options
POST /v1/workspaces/{workspace_id}/social-account-connections
GET /v1/workspaces/{workspace_id}/social-account-connections/{state}
POST /v1/workspaces/{workspace_id}/social-account-connections/{state}/accounts
POST /v1/workspaces/{workspace_id}/social-account-connections/{state}/reconnect
GET /v1/workspaces/{workspace_id}/social-accounts
PATCH /v1/workspaces/{workspace_id}/social-accounts/{social_account_id}
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}
GET /v1/workspaces/{workspace_id}/analytics/posts
GET /v1/workspaces/{workspace_id}/analytics/post-performance/summary
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.
Connect or reconnect social accounts
The Public API uses an interactive OAuth flow to connect new social accounts or refresh authorization for existing ones. Your application starts an authorization, opens the returned provider URL for a user, and checks the connection state after the provider redirects the user back to Postoria.
The same authorization flow can return both new and existing accounts:
connectable_accountscontains provider accounts that are not connected in the specified workspace.reconnectable_accountscontains existing accounts in that workspace that can be re-authorized with the completed OAuth grant.
After inspecting these lists, call the connect endpoint with provider PIDs, the reconnect endpoint with Postoria account IDs, or both endpoints when appropriate.
List connection options
Get the social networks and authentication methods currently available through the Public API:
GET /v1/social-account-connection-options
Example response:
{
"data": [
{
"network": "facebook",
"auth_methods": [
"facebook_login",
"meta_business_portfolio"
]
},
{
"network": "instagram",
"auth_methods": [
"instagram_login",
"facebook_login",
"meta_business_portfolio"
]
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"next": null
}
}
Do not hard-code the example response as the complete list. Use this endpoint as the source of truth because supported options can change.
The initial release supports these options:
| Network | Authentication methods |
|---|---|
facebook | facebook_login, meta_business_portfolio |
instagram | instagram_login, facebook_login, meta_business_portfolio |
linkedin | linkedin_login |
tumblr | tumblr_login |
youtube | google_login |
pinterest | pinterest_login |
tiktok | tiktok_api_for_business |
google_business_profile | google_login |
threads | threads_login |
Start an authorization
Create a connection state for a workspace:
POST /v1/workspaces/{workspace_id}/social-account-connections
Example request:
{
"network": "instagram",
"auth_method": "instagram_login"
}
Successful response (201 Created):
{
"state": "e4b69043-ead1-428e-9c9a-5e212c4f058e",
"is_completed": false,
"authorization_url": "https://www.instagram.com/oauth/authorize?...",
"expires_at": "2026-09-07T11:25:28.222872Z"
}
Open authorization_url in a browser and let the user complete the provider flow. The provider redirects the browser to Postoria’s hosted callback, which records the OAuth result against state. Your application does not need to supply a return URL or call a separate completion endpoint.
The state expires one hour after it is created. Start a new authorization if expires_at has passed. An expired state, or a state belonging to another workspace or Postoria account, returns 404 social_account_connection_not_found.
Check the authorization result
After the user finishes the provider flow, request the connection state:
GET /v1/workspaces/{workspace_id}/social-account-connections/{state}
You can poll this endpoint while is_completed is false. This field means that Postoria has not yet received and stored the OAuth callback; it does not mean that accounts have already been connected or reconnected.
Example completed response:
{
"state": "e4b69043-ead1-428e-9c9a-5e212c4f058e",
"is_completed": true,
"expires_at": "2026-09-07T11:25:28.222872Z",
"network": "instagram",
"auth_method": "instagram_login",
"error": null,
"connectable_accounts": [
{
"pid": "17841400000000001",
"name": "Postoria Demo",
"username": "postoria.demo",
"description": "Demo account",
"url": "https://www.instagram.com/postoria.demo/",
"logo_url": "https://example.com/profile.jpg",
"account_category": "profile"
}
],
"reconnectable_accounts": [
{
"account_id": 123,
"pid": "17841400000000002",
"name": "Postoria",
"username": "postoria.app",
"description": "Postoria",
"url": "https://www.instagram.com/postoria.app/",
"logo_url": "https://example.com/profile-2.jpg",
"account_category": "profile"
}
]
}
If is_completed is true and error is not null, the provider authorization failed or was declined. Do not call either account action endpoint; show the error or start a new authorization.
Connect new accounts
Select one or more PIDs exactly as returned in connectable_accounts:
POST /v1/workspaces/{workspace_id}/social-account-connections/{state}/accounts
Example request:
{
"pids": [
"17841400000000001"
]
}
The request fails validation if a PID is not available through this authorization or is already connected in the workspace.
Reconnect existing accounts
Select one or more Postoria account IDs exactly as returned in reconnectable_accounts:
POST /v1/workspaces/{workspace_id}/social-account-connections/{state}/reconnect
Example request:
{
"account_ids": [123, 456]
}
Every requested account must belong to the specified workspace and network, and the completed OAuth grant must provide access to it. If any requested account is unavailable, the API returns 400 social_accounts_not_available before reconnecting the selected accounts.
An existing account can be reconnected through any authentication method currently supported for its network; it does not have to match the method used for the original connection. Always select the returned account_id rather than trying to match accounts yourself.
Account action response
Both the connect and reconnect endpoints return the affected Postoria accounts:
{
"state": "e4b69043-ead1-428e-9c9a-5e212c4f058e",
"accounts": [
{
"id": 123,
"name": "Postoria",
"custom_name": "Channel 113",
"description": "postoria.app",
"network": "instagram",
"url": "https://www.instagram.com/postoria.app/",
"metadata": {
"channel_number": "113"
}
}
]
}
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",
"custom_name": "Channel 113",
"description": "postoria.app",
"network": "instagram",
"url": "https://www.instagram.com/postoria.app",
"metadata": {
"channel_number": "113",
"owner_account": "acme-media"
}
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"next": null
}
}
name is the account name received from the social network. custom_name is an optional name set in Postoria. metadata is an optional object containing string keys and string values controlled by your integration. Metadata keys retain their original casing.
Use the returned account IDs in social_account_ids when creating posts. You can also use metadata to associate each connected account with a stable identifier in your own system.
Update a social account
Use this endpoint to set or update the custom name and metadata of a connected social account:
PATCH /v1/workspaces/{workspace_id}/social-accounts/{social_account_id}
Example request:
{
"custom_name": "Channel 113",
"metadata": {
"channel_number": "113",
"owner_account": "acme-media",
"group": "north-america"
}
}
Both fields are optional, but the request must include at least one of them. Omitted fields remain unchanged.
Important behavior:
custom_nameis trimmed before it is stored and can contain up to 255 characters.- Set
custom_nametonullor an empty string to stop using a custom name in the Postoria interface. metadatamust be a JSON object containing string keys and string values.- Metadata can contain up to 50 entries. Keys can contain up to 64 characters, and values can contain up to 1,024 characters.
- Supplying
metadatareplaces the complete metadata object; it does not merge individual keys. - Set
metadatatonullto clear it, or to{}to keep an empty metadata object. - Custom names and metadata remain attached to the Postoria social account when it is reconnected or re-authorized.
Successful response:
{
"id": 123,
"name": "Postoria",
"custom_name": "Channel 113",
"description": "postoria.app",
"network": "instagram",
"url": "https://www.instagram.com/postoria.app",
"metadata": {
"channel_number": "113",
"owner_account": "acme-media",
"group": "north-america"
}
}
If the social account does not exist in the specified workspace, the API returns 404 social_account_not_found.
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,
"is_ai_generated": true,
"scheduled_time": "2026-06-01T10:00:00Z"
}
Example response:
{
"id": 3001,
"status": "scheduled",
"date": "2026-06-01T10:00:00Z",
"queue_id": null,
"is_ai_generated": true,
"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.
AI-generated content disclosure
Set the top-level is_ai_generated field to true when the post should carry the supported social networks’ AI-generated-content disclosure.
{
"is_ai_generated": true
}
Postoria sends the corresponding disclosure when supported by the destination and content type:
- Instagram accounts
- TikTok video posts
- YouTube videos
- X posts
- Pinterest Pins
The setting is not sent for TikTok photo posts. Unsupported destinations and content types ignore it.
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.
Facebook options
Use the facebook object for Facebook-specific options:
{
"facebook": {
"location_id": "12345678901234567890",
"also_publish_media_to_stories": true
}
}
location_id is optional and must be a positive numeric string containing no more than 64 digits. It identifies the Facebook Page for the physical location that Meta should associate with the post. Send the ID as a JSON string, not a number, so large IDs are preserved exactly.
When also_publish_media_to_stories is true, Postoria creates the regular Facebook publication first and then publishes each attached media file as a separate Facebook Story. The option has no effect when content_type is story or link.
Instagram options
Use the instagram object for Instagram-specific options:
{
"instagram": {
"location_id": "12345678901234567890",
"also_publish_media_to_stories": true,
"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
}
]
}
}
location_id is optional and follows the same format as the Facebook option: a positive numeric string containing no more than 64 digits. It must identify a Facebook Page associated with a physical location.
When also_publish_media_to_stories is true, Postoria creates the regular Instagram publication first and then publishes each attached media file as a separate Instagram Story. The option has no effect when content_type is story.
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.
Tumblr options
Use the tumblr object to attach native Tumblr tags separately from the post caption:
{
"caption": "Explore our latest indie game",
"tumblr": {
"tags": ["gaming", "indiegame", "steam", "hades2"]
}
}
Postoria accepts up to 30 Tumblr tags. It trims surrounding whitespace, removes a leading #, ignores empty values, and removes duplicate tags without regard to letter case. An individual array item cannot contain a comma or a double quotation mark. Use Tumblr options only when at least one selected social account is a Tumblr 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,
"is_ai_generated": true,
"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,
"is_ai_generated": true,
"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.
Get analytics for specific posts
Use this endpoint to retrieve the latest available analytics for one to 100 Postoria post IDs:
GET /v1/workspaces/{workspace_id}/analytics/posts?post_ids=3001&post_ids=3002
Repeat post_ids for each post. IDs must be positive integers. Duplicate IDs are accepted and treated as one ID.
Every requested post must belong to the workspace. If any post is missing or belongs to another workspace, the entire request fails with 404 post_not_found; the response does not identify which IDs failed.
The response contains one row for each selected social-account publication associated with the requested posts. Metrics are represented as name/value pairs because availability differs by network and can change over time:
{
"data": [
{
"post_id": 3001,
"social_account_id": 123,
"network": "tiktok",
"content_type": "video",
"published_at": "2026-08-01T10:00:00Z",
"analytics_refreshed_at": "2026-08-25T12:34:56Z",
"metrics": [
{ "name": "views", "value": 1250 },
{ "name": "likes", "value": 84 }
]
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"next": null
}
}
Unavailable metrics are omitted. A known zero is returned as zero. analytics_refreshed_at is the ISO 8601 UTC time when Postoria last successfully refreshed the publication’s analytics from the social network. If a publication exists but analytics is not available yet, analytics_refreshed_at is null and metrics is an empty array.
Network values in analytics use canonical identifiers such as linkedin, youtube, tiktok, and google_business_profile.
YouTube metrics use distinct youtube_ names. Examples include youtube_views, youtube_engaged_views, youtube_likes, youtube_dislikes, youtube_estimated_minutes_watched, youtube_average_view_duration, and youtube_subscribers_gained. The post analytics endpoint can return both additive metrics and non-additive averages or rates.
Get an aggregated post-performance summary
Use this endpoint to aggregate the latest available metrics for posts published during a UTC interval:
GET /v1/workspaces/{workspace_id}/analytics/post-performance/summary?published_from=2026-08-01T00:00:00Z&published_to=2026-09-01T00:00:00Z&granularity=day&group_by=network
Required query parameters:
published_from: inclusive ISO 8601 UTC timestamp usingZor+00:00.published_to: exclusive ISO 8601 UTC timestamp usingZor+00:00.
The interval must be greater than zero and cannot exceed 366 days.
Optional query parameters:
granularity:hour,day,month, oryear. Omit it to return no publication-time buckets.group_by:network,content_type, orsocial_account. Omit it to return no additional grouping dimension.
granularity and group_by are independent. For example, you can group by network without time buckets, use daily buckets without grouping by a dimension, combine both, or omit both for one total row.
When granularity is present, buckets use the workspace timezone. The response includes that IANA timezone and a published_period for each row. Period start and end are UTC instants, end is exclusive, and key is the corresponding workspace-local bucket label.
{
"data": [
{
"published_period": {
"start": "2026-08-01T04:00:00Z",
"end": "2026-08-02T04:00:00Z",
"key": "2026-08-01"
},
"network": "linkedin",
"post_count": 3,
"metrics": [
{ "name": "views", "value": 4200 },
{ "name": "comments", "value": 17 }
]
}
],
"timezone": "America/New_York"
}
If granularity is omitted, both published_period and the top-level timezone field are omitted. When group_by is omitted, no grouping field is returned. Otherwise, each row contains exactly one applicable field: network, content_type, or social_account_id.
The summary groups posts by when they were published. It sums their latest available metrics; it does not show when views, reactions, or other interactions occurred. Zero and unavailable metric totals are omitted from summary rows. Non-additive metrics such as video_skip_rate, video_average_watch_time_milliseconds, YouTube averages, and YouTube rates are not included because they cannot be summed correctly.
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. - Treat analytics metric names as extensible instead of hard-coding a fixed set.
- Use UTC for summary filters; when using
granularity, interpret bucket keys in the returned workspace timezone. - 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.