Publishing
Endpoints related to publishing content, such as posts and drafts.
General
This endpoint allows users to upload media by providing a URL. The uploaded media will be processed and stored, returning a new media URL that is used to publish a new post. Most of the platforms require validated URLs for posting images.
You can upload:
publicly accessible URLs
base64 encoded image data
Media uploads are limited to 1GB file size or smaller.
Media upload has a user-level rate limit of 10 requests / minute.
Upload Google Drive
If you have a link in google drive like this:
https://drive.google.com/file/d/18-UgDEaKG7YR7AewIDd_Qi4QCLCX5Kop/view?usp=drivesdk
You can use the following link for your Blotato "upload media" API call:
https://drive.google.com/uc?export=download&id=18-UgDEaKG7YR7AewIDd_Qi4QCLCX5Kop
Note how the IDs match: 18-UgDEaKG7YR7AewIDd_Qi4QCLCX5Kop
To see examples of how to upload to Blotato from a Google Drive, you can also check out these tutorials and templates:
n8n: https://youtu.be/D9okDd_1tBI
make: https://youtu.be/f4Stdm4lDNM
Seeing error "Google Drive can't scan this file for viruses"?
This is the most common issue when using Google Drive. When you try to access your file, you see this popup "Google Drive can't scan this file for viruses".
The issue is when you host a large video on google drive, it will show this popup, which prevents Blotato from accessing the video.
Recommended workaround: if you're regularly posting large videos (100MB+), I recommend using frame.io, an AWS S3 bucket, or similar tool where there is no issue passing around large video files.
The URL of the media to upload.
https://example.com/image.jpgDefault Response
Uploaded and validated blotato media URL.
https://database.blotato.io/media/12345.jpgThe internal ID of the uploaded media.
media_12345Forbidden
Validation error
Rate limit exceeded
Server error
POST /v2/media HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 39
{
"url": "https://example.com/image.jpg"
}{
"url": "https://database.blotato.io/media/12345.jpg",
"id": "media_12345"
}Creates a presigned URL for direct file upload. Use this when you have a local file to upload rather than a publicly accessible URL. The returned presignedUrl accepts a PUT request with the file body, and publicUrl is the final media URL to use when publishing a post.
The filename including extension, used to determine content type.
my-video.mp4Default Response
URL to PUT the file to. Expires after a short period.
The final public URL of the uploaded media, to be used when creating a post.
Forbidden
Default Response
POST /v2/media/uploads HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 27
{
"filename": "my-video.mp4"
}{
"presignedUrl": "text",
"publicUrl": "text"
}Lists the current user's posts (scheduled, published, and failed) within a time window, ordered by post time (most recent first). Supports cursor-based pagination and filtering by status and platform. Post listing has a user-level rate limit of 60 requests / minute.
Only include posts whose post time is on or after this ISO 8601 timestamp. Defaults to 7 days ago.
2026-10-05T20:55:09.937ZOnly include posts whose post time is on or before this ISO 8601 timestamp. Defaults to 7 days from now.
2026-10-19T20:55:09.937ZMaximum number of posts to return. Defaults to 50.
50Opaque cursor returned by a previous call. Pass it to fetch the next page.
Which published posts to include: 'blotato' (default) returns only posts published through Blotato; 'all' also includes any externally-published posts that were brought into Blotato.
Default Response
Cursor for the next page. Absent when there are no more posts.
Forbidden
Validation error
Server error
GET /v2/posts HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{
"items": [
{
"id": "text",
"postTime": "text",
"account": {
"id": "text",
"name": "text",
"subaccount": {
"id": "text",
"name": "text"
}
},
"state": {
"type": "scheduled"
},
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
],
"platform": "twitter"
}
],
"cursor": "text"
}General
Creates a new post with the provided content and optional scheduling. The post can be published immediately or scheduled for a later time.
Every post is scheduled on a queue. Failed posts are available at https://my.blotato.com/failed. The most common issue of failed post is incorrect JSON structure. Please make sure that JSON payload conforms to the structure described above. If you are still having trouble with identifying the issue, please contact support via Intercom and provide your postSubmissionId.
Post creation has a user-level rate limit of 30 requests / minute to prevent spamming / abusing social media endpoints
Examples
Post to a Platform Immediately
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
Headers:
{
"post": {
"accountId": "acc_12345",
"content": {
"text": "Hello, world!",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}Post at a Scheduled Time
Post an Image or a Video
Post a Twitter-like Thread with Multiple Posts
The ID of the existing post draft to use for creating the post. Unused in the API call
12345If provided, indicates whether to use the next available free slot for scheduling the post. If set to true, the post will be scheduled at the next available slot time for the specified platform. If neither scheduledTime nor slot is provided, and this is set to true, the post will be scheduled at the next available slot time.
The timestamp (ISO 8601) when the post should be published.
2026-10-19T20:55:09.937ZSubmitted
Submitted
The ID of the post submission. Use this ID to track the status of the post. This status code is returned when the post is already scheduled.
123e4567-e89b-12d3-a456-426614174000The resolved UTC time the post is scheduled to publish. Omitted when the post is published immediately.
2025-03-10T15:30:00ZSubmitted
Forbidden
Validation error
Rate limit exceeded
Server error
POST /v2/posts HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 328
{
"post": {
"target": {
"targetType": "tiktok",
"isYourBrand": false,
"autoAddMusic": false,
"disabledDuet": false,
"privacyLevel": "SELF_ONLY",
"isAiGenerated": false,
"disabledStitch": false,
"disabledComments": false,
"isBrandedContent": false
},
"content": {
"text": "Hello, blotato!",
"mediaUrls": [
"https://database.blotato.io/some-media-path.mp4"
]
}
}
}{
"postSubmissionId": "123e4567-e89b-12d3-a456-426614174000",
"scheduledTime": "2025-03-10T15:30:00Z"
}Fetches the status of a post by its submission ID. This is useful for checking if a post was successfully published or if it failed. Post lookup has a user-level rate limit of 60 requests / minute to prevent spamming / abusing social media endpoints
The ID of the post submission to check.
123e4567-e89b-12d3-a456-426614174000Default Response
The ID of the post submission.
123e4567-e89b-12d3-a456-426614174000The current status of the post.
publishedPossible values: The scheduled time of the post if it is scheduled. Null if the post was published immediately.
2025-03-11T15:30:00.000ZThe public URL of the post if it was published.
https://x.com/post/12345The error message if the post failed.
Unsupported media typeForbidden
Not found
Rate limit exceeded
Server error
GET /v2/posts/{postSubmissionId} HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{
"postSubmissionId": "123e4567-e89b-12d3-a456-426614174000",
"status": "published",
"scheduledTime": "2025-03-11T15:30:00.000Z",
"publicUrl": "https://x.com/post/12345",
"errorMessage": "Unsupported media type"
}Paginated search over a user's published posts, optionally filtered by platform and full-text query, with the latest analytics snapshot attached when available.
020Default Response
Forbidden
Validation error
Server error
GET /v2/published-posts HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{
"items": [
{
"id": "text",
"content": "text",
"postUrl": "text",
"platform": "twitter",
"createdAt": "text",
"mediaUrls": [
"text"
],
"latestMetrics": {
"fetchedAt": "text",
"metrics": {
"clicksCount": "text",
"commentsCount": "text",
"followsCount": "text",
"impressionsCount": "text",
"interactionsSum": "text",
"likesCount": "text",
"navigationsCount": "text",
"playsCount": "text",
"profileActivityCount": "text",
"profileVisitsCount": "text",
"reachCount": "text",
"repliesCount": "text",
"savesCount": "text",
"sharesCount": "text",
"viewTimeMsSum": "text",
"viewsCount": "text",
"watchTimeMsAvg": "text",
"twitterRetweetsCount": "text",
"twitterQuotesCount": "text",
"blueskyRepostsCount": "text",
"blueskyQuotesCount": "text",
"threadsRepostsCount": "text",
"threadsQuotesCount": "text",
"linkedinFirstLevelCommentsCount": "text",
"linkedinReactionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"pinterestPinClicksCount": "text",
"pinterestReactionsCount": "text",
"pinterestVideoP95ViewsCount": "text",
"pinterestVideo10sViewsCount": "text",
"pinterestVideoMrcViewsCount": "text",
"pinterestVideoV50WatchTimeMsSum": "text",
"pinterestSaveRate": 1,
"twitterPerMediaVideoViewsCount": [
"text"
],
"twitterPerMediaVideoPlaybackStartCount": [
"text"
],
"twitterPerMediaVideoPlayback25Count": [
"text"
],
"twitterPerMediaVideoPlayback50Count": [
"text"
],
"twitterPerMediaVideoPlayback75Count": [
"text"
],
"twitterPerMediaVideoPlaybackCompleteCount": [
"text"
],
"facebookPostMediaViewsCount": "text",
"facebookPostMediaViewsUniqueCount": "text",
"facebookPostReactionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookBlueReelsPlaysCount": "text",
"facebookFbReelsReplaysCount": "text",
"facebookFbReelsTotalPlaysCount": "text",
"facebookPostVideoWatchTimeMsAvg": "text",
"facebookPostVideoFollowersCount": "text",
"facebookPostVideoLikesByReactionType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookPostVideoSocialActionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookPostVideoViewTimeMsSum": "text",
"facebookTotalVideoViewsCount": "text",
"facebookTotalVideoViewsUniqueCount": "text",
"facebookTotalVideoViewsAutoplayedCount": "text",
"facebookTotalVideoViewsClickedToPlayCount": "text",
"facebookTotalVideoViewsSoundOnCount": "text",
"facebookTotalVideoCompleteViewsCount": "text",
"facebookTotalVideoCompleteViewsUniqueCount": "text",
"facebookTotalVideoCompleteViewsAutoplayedCount": "text",
"facebookTotalVideoCompleteViewsClickedToPlayCount": "text",
"facebookTotalVideoCompleteViewsOrganicCount": "text",
"facebookTotalVideoCompleteViewsOrganicUniqueCount": "text",
"facebookTotalVideoCompleteViewsPaidCount": "text",
"facebookTotalVideoCompleteViewsPaidUniqueCount": "text",
"facebookTotalVideoViews10sCount": "text",
"facebookTotalVideoViews10sUniqueCount": "text",
"facebookTotalVideoViews10sAutoplayedCount": "text",
"facebookTotalVideoViews10sClickedToPlayCount": "text",
"facebookTotalVideoViews10sOrganicCount": "text",
"facebookTotalVideoViews10sPaidCount": "text",
"facebookTotalVideoViews10sSoundOnCount": "text",
"facebookTotalVideoViews15sCount": "text",
"facebookTotalVideoViews60sExcludesShorterCount": "text",
"facebookTotalVideoWatchTimeMsAvg": "text",
"facebookTotalVideoViewTimeMsSum": "text",
"facebookTotalVideoViewTimeOrganicMsSum": "text",
"facebookTotalVideoViewTimePaidMsSum": "text",
"facebookTotalVideoStoriesByActionType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoReactionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoViewTimeMsByAgeBucketAndGender": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoViewTimeMsByRegionId": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoViewsByDistributionType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"youtubeDislikesCount": "text",
"youtubeSubscribersLostCount": "text",
"youtubeVideosAddedToPlaylistsCount": "text",
"youtubeVideosRemovedFromPlaylistsCount": "text",
"youtubeRedViewsCount": "text",
"youtubeRedViewTimeMsSum": "text",
"youtubeEngagedViewsCount": "text",
"youtubeAverageViewPercentage": 1,
"youtubeCardClicksCount": "text",
"youtubeCardImpressionsCount": "text",
"youtubeCardClickRate": 1,
"youtubeCardTeaserClicksCount": "text",
"youtubeCardTeaserImpressionsCount": "text",
"youtubeCardTeaserClickRate": 1,
"youtubeAnnotationClicksCount": "text",
"youtubeAnnotationClickableImpressionsCount": "text",
"youtubeAnnotationClosesCount": "text",
"youtubeAnnotationClosableImpressionsCount": "text",
"youtubeAnnotationImpressionsCount": "text",
"youtubeAnnotationClickThroughRate": 1,
"youtubeAnnotationCloseRate": 1
}
},
"metricsHistory": [
{
"fetchedAt": "text",
"metrics": {
"clicksCount": "text",
"commentsCount": "text",
"followsCount": "text",
"impressionsCount": "text",
"interactionsSum": "text",
"likesCount": "text",
"navigationsCount": "text",
"playsCount": "text",
"profileActivityCount": "text",
"profileVisitsCount": "text",
"reachCount": "text",
"repliesCount": "text",
"savesCount": "text",
"sharesCount": "text",
"viewTimeMsSum": "text",
"viewsCount": "text",
"watchTimeMsAvg": "text",
"twitterRetweetsCount": "text",
"twitterQuotesCount": "text",
"blueskyRepostsCount": "text",
"blueskyQuotesCount": "text",
"threadsRepostsCount": "text",
"threadsQuotesCount": "text",
"linkedinFirstLevelCommentsCount": "text",
"linkedinReactionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"pinterestPinClicksCount": "text",
"pinterestReactionsCount": "text",
"pinterestVideoP95ViewsCount": "text",
"pinterestVideo10sViewsCount": "text",
"pinterestVideoMrcViewsCount": "text",
"pinterestVideoV50WatchTimeMsSum": "text",
"pinterestSaveRate": 1,
"twitterPerMediaVideoViewsCount": [
"text"
],
"twitterPerMediaVideoPlaybackStartCount": [
"text"
],
"twitterPerMediaVideoPlayback25Count": [
"text"
],
"twitterPerMediaVideoPlayback50Count": [
"text"
],
"twitterPerMediaVideoPlayback75Count": [
"text"
],
"twitterPerMediaVideoPlaybackCompleteCount": [
"text"
],
"facebookPostMediaViewsCount": "text",
"facebookPostMediaViewsUniqueCount": "text",
"facebookPostReactionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookBlueReelsPlaysCount": "text",
"facebookFbReelsReplaysCount": "text",
"facebookFbReelsTotalPlaysCount": "text",
"facebookPostVideoWatchTimeMsAvg": "text",
"facebookPostVideoFollowersCount": "text",
"facebookPostVideoLikesByReactionType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookPostVideoSocialActionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookPostVideoViewTimeMsSum": "text",
"facebookTotalVideoViewsCount": "text",
"facebookTotalVideoViewsUniqueCount": "text",
"facebookTotalVideoViewsAutoplayedCount": "text",
"facebookTotalVideoViewsClickedToPlayCount": "text",
"facebookTotalVideoViewsSoundOnCount": "text",
"facebookTotalVideoCompleteViewsCount": "text",
"facebookTotalVideoCompleteViewsUniqueCount": "text",
"facebookTotalVideoCompleteViewsAutoplayedCount": "text",
"facebookTotalVideoCompleteViewsClickedToPlayCount": "text",
"facebookTotalVideoCompleteViewsOrganicCount": "text",
"facebookTotalVideoCompleteViewsOrganicUniqueCount": "text",
"facebookTotalVideoCompleteViewsPaidCount": "text",
"facebookTotalVideoCompleteViewsPaidUniqueCount": "text",
"facebookTotalVideoViews10sCount": "text",
"facebookTotalVideoViews10sUniqueCount": "text",
"facebookTotalVideoViews10sAutoplayedCount": "text",
"facebookTotalVideoViews10sClickedToPlayCount": "text",
"facebookTotalVideoViews10sOrganicCount": "text",
"facebookTotalVideoViews10sPaidCount": "text",
"facebookTotalVideoViews10sSoundOnCount": "text",
"facebookTotalVideoViews15sCount": "text",
"facebookTotalVideoViews60sExcludesShorterCount": "text",
"facebookTotalVideoWatchTimeMsAvg": "text",
"facebookTotalVideoViewTimeMsSum": "text",
"facebookTotalVideoViewTimeOrganicMsSum": "text",
"facebookTotalVideoViewTimePaidMsSum": "text",
"facebookTotalVideoStoriesByActionType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoReactionsByType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoViewTimeMsByAgeBucketAndGender": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoViewTimeMsByRegionId": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"facebookTotalVideoViewsByDistributionType": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"youtubeDislikesCount": "text",
"youtubeSubscribersLostCount": "text",
"youtubeVideosAddedToPlaylistsCount": "text",
"youtubeVideosRemovedFromPlaylistsCount": "text",
"youtubeRedViewsCount": "text",
"youtubeRedViewTimeMsSum": "text",
"youtubeEngagedViewsCount": "text",
"youtubeAverageViewPercentage": 1,
"youtubeCardClicksCount": "text",
"youtubeCardImpressionsCount": "text",
"youtubeCardClickRate": 1,
"youtubeCardTeaserClicksCount": "text",
"youtubeCardTeaserImpressionsCount": "text",
"youtubeCardTeaserClickRate": 1,
"youtubeAnnotationClicksCount": "text",
"youtubeAnnotationClickableImpressionsCount": "text",
"youtubeAnnotationClosesCount": "text",
"youtubeAnnotationClosableImpressionsCount": "text",
"youtubeAnnotationImpressionsCount": "text",
"youtubeAnnotationClickThroughRate": 1,
"youtubeAnnotationCloseRate": 1
}
}
]
}
],
"count": 1
}Fetches a published post by its ID, including the original publish payload for posts published through Blotato.
Default Response
Forbidden
Not found
Server error
GET /v2/published-posts/{id} HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{
"publishedPost": {
"id": "text",
"platform": "twitter",
"content": "text",
"mediaUrls": [
"text"
],
"postUrl": "text",
"createdAt": "text",
"rawPost": {
"accountId": "1",
"content": {
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
],
"platform": "twitter",
"additionalPosts": [
{
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
]
}
]
},
"target": {
"targetType": "webhook",
"url": "https://example.com/webhook"
}
}
}
}Fetches the current user's scheduled posts, ordered by scheduled time (ascending). Supports cursor-based pagination. Only returns posts scheduled in the future.
Default Response
Forbidden
Default Response
GET /v2/schedules HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{
"items": [
{
"id": "text",
"account": {
"id": "text",
"name": "text",
"username": "text",
"profileImageUrl": "text",
"subaccountId": "text",
"subId": "text",
"subaccountName": "text"
},
"draft": {
"accountId": "1",
"content": {
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
],
"platform": "twitter",
"additionalPosts": [
{
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
]
}
]
},
"target": {
"targetType": "webhook",
"url": "https://example.com/webhook"
}
},
"scheduledAt": "text"
}
],
"count": "text",
"cursor": "text"
}Fetches a single scheduled post by its ID. Returns the schedule details including the draft content and account information.
Default Response
Forbidden
Not found
Server error
GET /v2/schedules/{id} HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{
"schedule": {
"id": "text",
"account": {
"id": "text",
"name": "text",
"username": "text",
"profileImageUrl": "text",
"subaccountId": "text",
"subId": "text",
"subaccountName": "text"
},
"draft": {
"accountId": "1",
"content": {
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
],
"platform": "twitter",
"additionalPosts": [
{
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
]
}
]
},
"target": {
"targetType": "webhook",
"url": "https://example.com/webhook"
}
},
"scheduledAt": "text"
}
}Deletes a scheduled post by its ID. The associated publishing job is also cancelled.
The ID of the schedule to delete.
Default Response
Forbidden
Not found
Default Response
DELETE /v2/schedules/{id} HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{}Updates a scheduled post. The post must be in scheduled state to be updated. You can update the scheduled time or change the post contents.
Updates a scheduled post by ID. You can update the draft content, the scheduled time, or both. The scheduled time must be a valid ISO 8601 date in the future. When the scheduled time is changed, the post is re-queued for publishing at the new time.
The ID of the schedule to update.
Default Response
Forbidden
Not found
Validation error
Default Response
PATCH /v2/schedules/{id} HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 347
{
"patch": {
"draft": {
"accountId": "1",
"content": {
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
],
"platform": "twitter",
"additionalPosts": [
{
"text": "My text",
"mediaUrls": [
"https://database.blotato.io/some-image-path.jpg"
]
}
]
},
"target": {
"targetType": "webhook",
"url": "https://example.com/webhook"
}
},
"scheduledTime": "text"
}
}{}Submits a source for asynchronous resolution. The response contains a source resolution ID that can be used to check the status of the resolution. A source can be any text content, URL, or other data that needs to be processed to generate a title and content. Source resolution has a user-level rate limit of 30 requests / minute.
Default Response
Forbidden
Validation error
Default Response
POST /v2/source-resolutions-v3 HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 74
{
"source": {
"sourceType": "text",
"text": "text"
},
"customInstructions": "text"
}{
"id": "text"
}Fetches the status of a source resolution by its ID. This endpoint allows users to check whether the source has been resolved or is still in the queue. Source resolution lookup has a user-level rate limit of 60 requests / minute.
Default Response
Forbidden
Not found
Default Response
GET /v2/source-resolutions-v3/{id} HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Accept: */*
{
"id": "text",
"status": "completed",
"title": "text",
"content": "text",
"referenceUrl": "text"
}Last updated